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

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


The following commit(s) were added to refs/heads/master by this push:
     new 5a1b4c0  [IOTDB-1514] Support null in insertTablet (#3995)
5a1b4c0 is described below

commit 5a1b4c0ad2964c92d630af6492f26aede00b0950
Author: Alan Choo <[email protected]>
AuthorDate: Wed Sep 29 11:09:11 2021 +0800

    [IOTDB-1514] Support null in insertTablet (#3995)
---
 .../main/java/org/apache/iotdb/SessionExample.java | 83 ++++++++++++++++++++
 .../iotdb/db/engine/memtable/AbstractMemTable.java |  4 +-
 .../apache/iotdb/db/engine/memtable/IMemTable.java |  8 +-
 .../db/engine/memtable/IWritableMemChunk.java      | 21 ++---
 .../iotdb/db/engine/memtable/WritableMemChunk.java | 44 +++++------
 .../engine/storagegroup/StorageGroupProcessor.java |  3 +-
 .../db/engine/storagegroup/TsFileProcessor.java    |  5 +-
 .../db/qp/physical/crud/InsertTabletPlan.java      | 30 ++++++--
 .../iotdb/db/utils/datastructure/BinaryTVList.java | 59 ++++++++++++--
 .../db/utils/datastructure/BooleanTVList.java      | 59 ++++++++++++--
 .../iotdb/db/utils/datastructure/DoubleTVList.java | 59 ++++++++++++--
 .../iotdb/db/utils/datastructure/FloatTVList.java  | 59 ++++++++++++--
 .../iotdb/db/utils/datastructure/IntTVList.java    | 59 ++++++++++++--
 .../iotdb/db/utils/datastructure/LongTVList.java   | 69 ++++++++++++++---
 .../iotdb/db/utils/datastructure/TVList.java       | 16 ++--
 .../iotdb/db/utils/datastructure/VectorTVList.java | 82 ++++++++++++--------
 .../iotdb/db/integration/IoTDBSelectIntoIT.java    |  2 +-
 .../iotdb/db/qp/physical/InsertTabletPlanTest.java | 89 +++++++++++++++++++---
 .../db/utils/datastructure/BinaryTVListTest.java   | 59 +++++++++++++-
 .../db/utils/datastructure/BooleanTVListTest.java  | 63 ++++++++++++++-
 .../db/utils/datastructure/DoubleTVListTest.java   | 63 ++++++++++++++-
 .../db/utils/datastructure/FloatTVListTest.java    | 63 ++++++++++++++-
 .../db/utils/datastructure/IntTVListTest.java      | 63 ++++++++++++++-
 .../db/utils/datastructure/LongTVListTest.java     | 62 ++++++++++++++-
 .../db/utils/datastructure/VectorTVListTest.java   | 40 +++++++++-
 .../apache/iotdb/session/IoTDBSessionSimpleIT.java | 53 +++++++++++++
 .../java/org/apache/iotdb/tsfile/utils/BitMap.java |  7 ++
 .../apache/iotdb/tsfile/write/record/Tablet.java   |  9 ++-
 28 files changed, 1093 insertions(+), 140 deletions(-)

diff --git a/example/session/src/main/java/org/apache/iotdb/SessionExample.java 
b/example/session/src/main/java/org/apache/iotdb/SessionExample.java
index a043962..32f3f74 100644
--- a/example/session/src/main/java/org/apache/iotdb/SessionExample.java
+++ b/example/session/src/main/java/org/apache/iotdb/SessionExample.java
@@ -28,6 +28,7 @@ import org.apache.iotdb.session.SessionDataSet.DataIterator;
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.utils.BitMap;
 import org.apache.iotdb.tsfile.write.record.Tablet;
 import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
 import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
@@ -74,6 +75,7 @@ public class SessionExample {
     createMultiTimeseries();
     insertRecord();
     insertTablet();
+    insertTabletWithNullValues();
     insertTablets();
     insertRecords();
     selectInto();
@@ -433,6 +435,87 @@ public class SessionExample {
     }
   }
 
+  private static void insertTabletWithNullValues()
+      throws IoTDBConnectionException, StatementExecutionException {
+    /*
+     * A Tablet example:
+     *      device1
+     * time s1,   s2,   s3
+     * 1,   null, 1,    1
+     * 2,   2,    null, 2
+     * 3,   3,    3,    null
+     */
+    // The schema of measurements of one device
+    // only measurementId and data type in MeasurementSchema take effects in 
Tablet
+    List<IMeasurementSchema> schemaList = new ArrayList<>();
+    schemaList.add(new MeasurementSchema("s1", TSDataType.INT64));
+    schemaList.add(new MeasurementSchema("s2", TSDataType.INT64));
+    schemaList.add(new MeasurementSchema("s3", TSDataType.INT64));
+
+    Tablet tablet = new Tablet(ROOT_SG1_D1, schemaList, 100);
+
+    // Method 1 to add tablet data
+    tablet.bitMaps = new BitMap[schemaList.size()];
+    for (int s = 0; s < 3; s++) {
+      tablet.bitMaps[s] = new BitMap(tablet.getMaxRowNumber());
+    }
+
+    long timestamp = System.currentTimeMillis();
+    for (long row = 0; row < 100; row++) {
+      int rowIndex = tablet.rowSize++;
+      tablet.addTimestamp(rowIndex, timestamp);
+      for (int s = 0; s < 3; s++) {
+        long value = new Random().nextLong();
+        // mark null value
+        if (row % 3 == s) {
+          tablet.bitMaps[s].mark((int) row);
+        }
+        tablet.addValue(schemaList.get(s).getMeasurementId(), rowIndex, value);
+      }
+      if (tablet.rowSize == tablet.getMaxRowNumber()) {
+        session.insertTablet(tablet, true);
+        tablet.reset();
+      }
+      timestamp++;
+    }
+
+    if (tablet.rowSize != 0) {
+      session.insertTablet(tablet);
+      tablet.reset();
+    }
+
+    // Method 2 to add tablet data
+    long[] timestamps = tablet.timestamps;
+    Object[] values = tablet.values;
+    BitMap[] bitMaps = new BitMap[schemaList.size()];
+    for (int s = 0; s < 3; s++) {
+      bitMaps[s] = new BitMap(tablet.getMaxRowNumber());
+    }
+    tablet.bitMaps = bitMaps;
+
+    for (long time = 0; time < 100; time++) {
+      int row = tablet.rowSize++;
+      timestamps[row] = time;
+      for (int i = 0; i < 3; i++) {
+        long[] sensor = (long[]) values[i];
+        // mark null value
+        if (row % 3 == i) {
+          bitMaps[i].mark(row);
+        }
+        sensor[row] = i;
+      }
+      if (tablet.rowSize == tablet.getMaxRowNumber()) {
+        session.insertTablet(tablet, true);
+        tablet.reset();
+      }
+    }
+
+    if (tablet.rowSize != 0) {
+      session.insertTablet(tablet);
+      tablet.reset();
+    }
+  }
+
   private static void insertTablets() throws IoTDBConnectionException, 
StatementExecutionException {
     // The schema of measurements of one device
     // only measurementId and data type in MeasurementSchema take effects in 
Tablet
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
index 3f05dc9..58501a9 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/AbstractMemTable.java
@@ -220,15 +220,15 @@ public abstract class AbstractMemTable implements 
IMemTable {
           columnIndex++;
         }
         memSeries.write(
-            insertTabletPlan.getTimes(), bitMaps, columns, TSDataType.VECTOR, 
start, end);
+            insertTabletPlan.getTimes(), columns, bitMaps, TSDataType.VECTOR, 
start, end);
         break;
       } else {
         memSeries.write(
             insertTabletPlan.getTimes(),
+            insertTabletPlan.getColumns()[columnIndex],
             insertTabletPlan.getBitMaps() != null
                 ? insertTabletPlan.getBitMaps()[columnIndex]
                 : null,
-            insertTabletPlan.getColumns()[columnIndex],
             insertTabletPlan.getDataTypes()[columnIndex],
             start,
             end);
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java
index 8cf61dc..e86fc96 100644
--- a/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java
+++ b/server/src/main/java/org/apache/iotdb/db/engine/memtable/IMemTable.java
@@ -46,6 +46,10 @@ public interface IMemTable {
 
   void write(String deviceId, IMeasurementSchema schema, long insertTime, 
Object objectValue);
 
+  /**
+   * write data in the range [start, end). Null value in each column values 
will be replaced by the
+   * subsequent non-null value, e.g., {1, null, 3, null, 5} will be {1, 3, 5, 
null, 5}
+   */
   void write(InsertTabletPlan insertTabletPlan, int start, int end);
 
   /** @return the number of points */
@@ -82,7 +86,9 @@ public interface IMemTable {
   void insert(InsertRowPlan insertRowPlan);
 
   /**
-   * insert tablet into this memtable
+   * insert tablet into this memtable. The rows to be inserted are in the 
range [start, end). Null
+   * value in each column values will be replaced by the subsequent non-null 
value, e.g., {1, null,
+   * 3, null, 5} will be {1, 3, 5, null, 5}
    *
    * @param insertTabletPlan insertTabletPlan
    * @param start included
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/IWritableMemChunk.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/IWritableMemChunk.java
index 6cb896f..b58f3b7 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/IWritableMemChunk.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/IWritableMemChunk.java
@@ -42,25 +42,28 @@ public interface IWritableMemChunk {
 
   void putVector(long t, Object[] v);
 
-  void putLongs(long[] t, BitMap bitMap, long[] v, int start, int end);
+  void putLongs(long[] t, long[] v, BitMap bitMap, int start, int end);
 
-  void putInts(long[] t, BitMap bitMap, int[] v, int start, int end);
+  void putInts(long[] t, int[] v, BitMap bitMap, int start, int end);
 
-  void putFloats(long[] t, BitMap bitMap, float[] v, int start, int end);
+  void putFloats(long[] t, float[] v, BitMap bitMap, int start, int end);
 
-  void putDoubles(long[] t, BitMap bitMap, double[] v, int start, int end);
+  void putDoubles(long[] t, double[] v, BitMap bitMap, int start, int end);
 
-  void putBinaries(long[] t, BitMap bitMap, Binary[] v, int start, int end);
+  void putBinaries(long[] t, Binary[] v, BitMap bitMap, int start, int end);
 
-  void putBooleans(long[] t, BitMap bitMap, boolean[] v, int start, int end);
+  void putBooleans(long[] t, boolean[] v, BitMap bitMap, int start, int end);
 
-  void putVectors(long[] t, BitMap[] bitMaps, Object[] v, int start, int end);
+  void putVectors(long[] t, Object[] v, BitMap[] bitMaps, int start, int end);
 
   void write(long insertTime, Object objectValue);
 
-  /** [start, end) */
+  /**
+   * write data in the range [start, end). Null value in the valueList will be 
replaced by the
+   * subsequent non-null value, e.g., {1, null, 3, null, 5} will be {1, 3, 5, 
null, 5}
+   */
   void write(
-      long[] times, Object bitMaps, Object valueList, TSDataType dataType, int 
start, int end);
+      long[] times, Object valueList, Object bitMaps, TSDataType dataType, int 
start, int end);
 
   long count();
 
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/WritableMemChunk.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/WritableMemChunk.java
index a841486..09b30e8 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/memtable/WritableMemChunk.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/memtable/WritableMemChunk.java
@@ -69,35 +69,35 @@ public class WritableMemChunk implements IWritableMemChunk {
 
   @Override
   public void write(
-      long[] times, Object bitMap, Object valueList, TSDataType dataType, int 
start, int end) {
+      long[] times, Object valueList, Object bitMap, TSDataType dataType, int 
start, int end) {
     switch (dataType) {
       case BOOLEAN:
         boolean[] boolValues = (boolean[]) valueList;
-        putBooleans(times, (BitMap) bitMap, boolValues, start, end);
+        putBooleans(times, boolValues, (BitMap) bitMap, start, end);
         break;
       case INT32:
         int[] intValues = (int[]) valueList;
-        putInts(times, (BitMap) bitMap, intValues, start, end);
+        putInts(times, intValues, (BitMap) bitMap, start, end);
         break;
       case INT64:
         long[] longValues = (long[]) valueList;
-        putLongs(times, (BitMap) bitMap, longValues, start, end);
+        putLongs(times, longValues, (BitMap) bitMap, start, end);
         break;
       case FLOAT:
         float[] floatValues = (float[]) valueList;
-        putFloats(times, (BitMap) bitMap, floatValues, start, end);
+        putFloats(times, floatValues, (BitMap) bitMap, start, end);
         break;
       case DOUBLE:
         double[] doubleValues = (double[]) valueList;
-        putDoubles(times, (BitMap) bitMap, doubleValues, start, end);
+        putDoubles(times, doubleValues, (BitMap) bitMap, start, end);
         break;
       case TEXT:
         Binary[] binaryValues = (Binary[]) valueList;
-        putBinaries(times, (BitMap) bitMap, binaryValues, start, end);
+        putBinaries(times, binaryValues, (BitMap) bitMap, start, end);
         break;
       case VECTOR:
         Object[] vectorValues = (Object[]) valueList;
-        putVectors(times, (BitMap[]) bitMap, vectorValues, start, end);
+        putVectors(times, vectorValues, (BitMap[]) bitMap, start, end);
         break;
       default:
         throw new UnSupportedDataTypeException(UNSUPPORTED_TYPE + dataType);
@@ -140,38 +140,38 @@ public class WritableMemChunk implements 
IWritableMemChunk {
   }
 
   @Override
-  public void putLongs(long[] t, BitMap bitMap, long[] v, int start, int end) {
-    list.putLongs(t, v, start, end);
+  public void putLongs(long[] t, long[] v, BitMap bitMap, int start, int end) {
+    list.putLongs(t, v, bitMap, start, end);
   }
 
   @Override
-  public void putInts(long[] t, BitMap bitMap, int[] v, int start, int end) {
-    list.putInts(t, v, start, end);
+  public void putInts(long[] t, int[] v, BitMap bitMap, int start, int end) {
+    list.putInts(t, v, bitMap, start, end);
   }
 
   @Override
-  public void putFloats(long[] t, BitMap bitMap, float[] v, int start, int 
end) {
-    list.putFloats(t, v, start, end);
+  public void putFloats(long[] t, float[] v, BitMap bitMap, int start, int 
end) {
+    list.putFloats(t, v, bitMap, start, end);
   }
 
   @Override
-  public void putDoubles(long[] t, BitMap bitMap, double[] v, int start, int 
end) {
-    list.putDoubles(t, v, start, end);
+  public void putDoubles(long[] t, double[] v, BitMap bitMap, int start, int 
end) {
+    list.putDoubles(t, v, bitMap, start, end);
   }
 
   @Override
-  public void putBinaries(long[] t, BitMap bitMap, Binary[] v, int start, int 
end) {
-    list.putBinaries(t, v, start, end);
+  public void putBinaries(long[] t, Binary[] v, BitMap bitMap, int start, int 
end) {
+    list.putBinaries(t, v, bitMap, start, end);
   }
 
   @Override
-  public void putBooleans(long[] t, BitMap bitMap, boolean[] v, int start, int 
end) {
-    list.putBooleans(t, v, start, end);
+  public void putBooleans(long[] t, boolean[] v, BitMap bitMap, int start, int 
end) {
+    list.putBooleans(t, v, bitMap, start, end);
   }
 
   @Override
-  public void putVectors(long[] t, BitMap[] bitMaps, Object[] v, int start, 
int end) {
-    list.putVectors(t, bitMaps, v, start, end);
+  public void putVectors(long[] t, Object[] v, BitMap[] bitMaps, int start, 
int end) {
+    list.putVectors(t, v, bitMaps, start, end);
   }
 
   @Override
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
index 717a971..8e92a26 100755
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/StorageGroupProcessor.java
@@ -1020,7 +1020,8 @@ public class StorageGroupProcessor {
 
   /**
    * insert batch to tsfile processor thread-safety that the caller need to 
guarantee The rows to be
-   * inserted are in the range [start, end)
+   * inserted are in the range [start, end) Null value in each column values 
will be replaced by the
+   * subsequent non-null value, e.g., {1, null, 3, null, 5} will be {1, 3, 5, 
null, 5}
    *
    * @param insertTabletPlan insert a tablet of a device
    * @param sequence whether is sequence
diff --git 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
index c00a245..ec71755 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/engine/storagegroup/TsFileProcessor.java
@@ -247,8 +247,9 @@ public class TsFileProcessor {
   }
 
   /**
-   * insert batch data of insertTabletPlan into the workingMemtable The rows 
to be inserted are in
-   * the range [start, end)
+   * insert batch data of insertTabletPlan into the workingMemtable. The rows 
to be inserted are in
+   * the range [start, end). Null value in each column values will be replaced 
by the subsequent
+   * non-null value, e.g., {1, null, 3, null, 5} will be {1, 3, 5, null, 5}
    *
    * @param insertTabletPlan insert a tablet of a device
    * @param start start index of rows to be inserted in insertTabletPlan
diff --git 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertTabletPlan.java
 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertTabletPlan.java
index 75e3aef..6a5b3dc 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertTabletPlan.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/qp/physical/crud/InsertTabletPlan.java
@@ -534,37 +534,53 @@ public class InsertTabletPlan extends InsertPlan {
     if (measurementIndex >= columns.length) {
       return null;
     }
+
+    // get non-null value
+    int lastIdx = rowCount - 1;
+    if (bitMaps != null && bitMaps[measurementIndex] != null) {
+      BitMap bitMap = bitMaps[measurementIndex];
+      while (lastIdx >= 0) {
+        if (!bitMap.isMarked(lastIdx)) {
+          break;
+        }
+        lastIdx--;
+      }
+    }
+    if (lastIdx < 0) {
+      return null;
+    }
+
     TsPrimitiveType value;
     switch (dataTypes[measurementIndex]) {
       case INT32:
         int[] intValues = (int[]) columns[measurementIndex];
-        value = new TsInt(intValues[rowCount - 1]);
+        value = new TsInt(intValues[lastIdx]);
         break;
       case INT64:
         long[] longValues = (long[]) columns[measurementIndex];
-        value = new TsLong(longValues[rowCount - 1]);
+        value = new TsLong(longValues[lastIdx]);
         break;
       case FLOAT:
         float[] floatValues = (float[]) columns[measurementIndex];
-        value = new TsFloat(floatValues[rowCount - 1]);
+        value = new TsFloat(floatValues[lastIdx]);
         break;
       case DOUBLE:
         double[] doubleValues = (double[]) columns[measurementIndex];
-        value = new TsDouble(doubleValues[rowCount - 1]);
+        value = new TsDouble(doubleValues[lastIdx]);
         break;
       case BOOLEAN:
         boolean[] boolValues = (boolean[]) columns[measurementIndex];
-        value = new TsBoolean(boolValues[rowCount - 1]);
+        value = new TsBoolean(boolValues[lastIdx]);
         break;
       case TEXT:
         Binary[] binaryValues = (Binary[]) columns[measurementIndex];
-        value = new TsBinary(binaryValues[rowCount - 1]);
+        value = new TsBinary(binaryValues[lastIdx]);
         break;
       default:
         throw new UnSupportedDataTypeException(
             String.format(DATATYPE_UNSUPPORTED, dataTypes[measurementIndex]));
     }
-    return new TimeValuePair(times[rowCount - 1], value);
+    return new TimeValuePair(times[lastIdx], value);
   }
 
   public long[] getTimes() {
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/BinaryTVList.java
 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/BinaryTVList.java
index bf62d63..136c283 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/BinaryTVList.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/BinaryTVList.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
 import org.apache.iotdb.tsfile.utils.Binary;
+import org.apache.iotdb.tsfile.utils.BitMap;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType;
 
 import java.util.ArrayList;
@@ -32,6 +33,8 @@ import static 
org.apache.iotdb.db.rescon.PrimitiveArrayManager.ARRAY_SIZE;
 
 public class BinaryTVList extends TVList {
 
+  // list of primitive array, add 1 when expanded -> Binary primitive array
+  // index relation: arrayIndex -> elementIndex
   private List<Binary[]> values;
 
   private Binary[][] sortedValues;
@@ -194,11 +197,25 @@ public class BinaryTVList extends TVList {
   }
 
   @Override
-  public void putBinaries(long[] time, Binary[] value, int start, int end) {
+  public void putBinaries(long[] time, Binary[] value, BitMap bitMap, int 
start, int end) {
     checkExpansion();
-    int idx = start;
 
-    updateMinTimeAndSorted(time, start, end);
+    int idx = start;
+    // constraint: time.length + timeIdxOffset == value.length
+    int timeIdxOffset = 0;
+    if (bitMap != null && !bitMap.isAllUnmarked()) {
+      // time array is a reference, should clone necessary time values
+      long[] clonedTime = new long[end - start];
+      System.arraycopy(time, start, clonedTime, 0, end - start);
+      time = clonedTime;
+      timeIdxOffset = start;
+      // drop null at the end of value array
+      int nullCnt =
+          dropNullValThenUpdateMinTimeAndSorted(time, value, bitMap, start, 
end, timeIdxOffset);
+      end -= nullCnt;
+    } else {
+      updateMinTimeAndSorted(time, start, end);
+    }
 
     while (idx < end) {
       int inputRemaining = end - idx;
@@ -207,14 +224,16 @@ public class BinaryTVList extends TVList {
       int internalRemaining = ARRAY_SIZE - elementIdx;
       if (internalRemaining >= inputRemaining) {
         // the remaining inputs can fit the last array, copy all remaining 
inputs into last array
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
inputRemaining);
         size += inputRemaining;
         break;
       } else {
         // the remaining inputs cannot fit the last array, fill the last array 
and create a new
         // one and enter the next loop
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
internalRemaining);
         idx += internalRemaining;
         size += internalRemaining;
@@ -223,6 +242,36 @@ public class BinaryTVList extends TVList {
     }
   }
 
+  // move null values to the end of time array and value array, then return 
number of null values
+  int dropNullValThenUpdateMinTimeAndSorted(
+      long[] time, Binary[] values, BitMap bitMap, int start, int end, int 
tIdxOffset) {
+    long inPutMinTime = Long.MAX_VALUE;
+    boolean inputSorted = true;
+
+    int nullCnt = 0;
+    for (int vIdx = start; vIdx < end; vIdx++) {
+      if (bitMap.isMarked(vIdx)) {
+        nullCnt++;
+        continue;
+      }
+      // move value ahead to replace null
+      int tIdx = vIdx - tIdxOffset;
+      if (nullCnt != 0) {
+        time[tIdx - nullCnt] = time[tIdx];
+        values[vIdx - nullCnt] = values[vIdx];
+      }
+      // update minTime and sorted
+      tIdx = tIdx - nullCnt;
+      inPutMinTime = Math.min(inPutMinTime, time[tIdx]);
+      if (inputSorted && tIdx > 0 && time[tIdx - 1] > time[tIdx]) {
+        inputSorted = false;
+      }
+    }
+    minTime = Math.min(inPutMinTime, minTime);
+    sorted = sorted && inputSorted && (size == 0 || inPutMinTime >= 
getTime(size - 1));
+    return nullCnt;
+  }
+
   @Override
   public TSDataType getDataType() {
     return TSDataType.TEXT;
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/BooleanTVList.java
 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/BooleanTVList.java
index e293544..f4c9b31 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/BooleanTVList.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/BooleanTVList.java
@@ -22,6 +22,7 @@ import org.apache.iotdb.db.rescon.PrimitiveArrayManager;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
+import org.apache.iotdb.tsfile.utils.BitMap;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType;
 
 import java.util.ArrayList;
@@ -31,6 +32,8 @@ import static 
org.apache.iotdb.db.rescon.PrimitiveArrayManager.ARRAY_SIZE;
 
 public class BooleanTVList extends TVList {
 
+  // list of primitive array, add 1 when expanded -> boolean primitive array
+  // index relation: arrayIndex -> elementIndex
   private List<boolean[]> values;
 
   private boolean[][] sortedValues;
@@ -194,11 +197,25 @@ public class BooleanTVList extends TVList {
   }
 
   @Override
-  public void putBooleans(long[] time, boolean[] value, int start, int end) {
+  public void putBooleans(long[] time, boolean[] value, BitMap bitMap, int 
start, int end) {
     checkExpansion();
-    int idx = start;
 
-    updateMinTimeAndSorted(time, start, end);
+    int idx = start;
+    // constraint: time.length + timeIdxOffset == value.length
+    int timeIdxOffset = 0;
+    if (bitMap != null && !bitMap.isAllUnmarked()) {
+      // time array is a reference, should clone necessary time values
+      long[] clonedTime = new long[end - start];
+      System.arraycopy(time, start, clonedTime, 0, end - start);
+      time = clonedTime;
+      timeIdxOffset = start;
+      // drop null at the end of value array
+      int nullCnt =
+          dropNullValThenUpdateMinTimeAndSorted(time, value, bitMap, start, 
end, timeIdxOffset);
+      end -= nullCnt;
+    } else {
+      updateMinTimeAndSorted(time, start, end);
+    }
 
     while (idx < end) {
       int inputRemaining = end - idx;
@@ -207,14 +224,16 @@ public class BooleanTVList extends TVList {
       int internalRemaining = ARRAY_SIZE - elementIdx;
       if (internalRemaining >= inputRemaining) {
         // the remaining inputs can fit the last array, copy all remaining 
inputs into last array
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
inputRemaining);
         size += inputRemaining;
         break;
       } else {
         // the remaining inputs cannot fit the last array, fill the last array 
and create a new
         // one and enter the next loop
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
internalRemaining);
         idx += internalRemaining;
         size += internalRemaining;
@@ -223,6 +242,36 @@ public class BooleanTVList extends TVList {
     }
   }
 
+  // move null values to the end of time array and value array, then return 
number of null values
+  int dropNullValThenUpdateMinTimeAndSorted(
+      long[] time, boolean[] values, BitMap bitMap, int start, int end, int 
tIdxOffset) {
+    long inPutMinTime = Long.MAX_VALUE;
+    boolean inputSorted = true;
+
+    int nullCnt = 0;
+    for (int vIdx = start; vIdx < end; vIdx++) {
+      if (bitMap.isMarked(vIdx)) {
+        nullCnt++;
+        continue;
+      }
+      // move value ahead to replace null
+      int tIdx = vIdx - tIdxOffset;
+      if (nullCnt != 0) {
+        time[tIdx - nullCnt] = time[tIdx];
+        values[vIdx - nullCnt] = values[vIdx];
+      }
+      // update minTime and sorted
+      tIdx = tIdx - nullCnt;
+      inPutMinTime = Math.min(inPutMinTime, time[tIdx]);
+      if (inputSorted && tIdx > 0 && time[tIdx - 1] > time[tIdx]) {
+        inputSorted = false;
+      }
+    }
+    minTime = Math.min(inPutMinTime, minTime);
+    sorted = sorted && inputSorted && (size == 0 || inPutMinTime >= 
getTime(size - 1));
+    return nullCnt;
+  }
+
   @Override
   public TSDataType getDataType() {
     return TSDataType.BOOLEAN;
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/DoubleTVList.java
 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/DoubleTVList.java
index d7e8178..6b3fcb8 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/DoubleTVList.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/DoubleTVList.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.utils.MathUtils;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
+import org.apache.iotdb.tsfile.utils.BitMap;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType;
 
 import java.util.ArrayList;
@@ -32,6 +33,8 @@ import static 
org.apache.iotdb.db.rescon.PrimitiveArrayManager.ARRAY_SIZE;
 
 public class DoubleTVList extends TVList {
 
+  // list of primitive array, add 1 when expanded -> double primitive array
+  // index relation: arrayIndex -> elementIndex
   private List<double[]> values;
 
   private double[][] sortedValues;
@@ -198,11 +201,25 @@ public class DoubleTVList extends TVList {
   }
 
   @Override
-  public void putDoubles(long[] time, double[] value, int start, int end) {
+  public void putDoubles(long[] time, double[] value, BitMap bitMap, int 
start, int end) {
     checkExpansion();
-    int idx = start;
 
-    updateMinTimeAndSorted(time, start, end);
+    int idx = start;
+    // constraint: time.length + timeIdxOffset == value.length
+    int timeIdxOffset = 0;
+    if (bitMap != null && !bitMap.isAllUnmarked()) {
+      // time array is a reference, should clone necessary time values
+      long[] clonedTime = new long[end - start];
+      System.arraycopy(time, start, clonedTime, 0, end - start);
+      time = clonedTime;
+      timeIdxOffset = start;
+      // drop null at the end of value array
+      int nullCnt =
+          dropNullValThenUpdateMinTimeAndSorted(time, value, bitMap, start, 
end, timeIdxOffset);
+      end -= nullCnt;
+    } else {
+      updateMinTimeAndSorted(time, start, end);
+    }
 
     while (idx < end) {
       int inputRemaining = end - idx;
@@ -211,14 +228,16 @@ public class DoubleTVList extends TVList {
       int internalRemaining = ARRAY_SIZE - elementIdx;
       if (internalRemaining >= inputRemaining) {
         // the remaining inputs can fit the last array, copy all remaining 
inputs into last array
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
inputRemaining);
         size += inputRemaining;
         break;
       } else {
         // the remaining inputs cannot fit the last array, fill the last array 
and create a new
         // one and enter the next loop
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
internalRemaining);
         idx += internalRemaining;
         size += internalRemaining;
@@ -227,6 +246,36 @@ public class DoubleTVList extends TVList {
     }
   }
 
+  // move null values to the end of time array and value array, then return 
number of null values
+  int dropNullValThenUpdateMinTimeAndSorted(
+      long[] time, double[] values, BitMap bitMap, int start, int end, int 
tIdxOffset) {
+    long inPutMinTime = Long.MAX_VALUE;
+    boolean inputSorted = true;
+
+    int nullCnt = 0;
+    for (int vIdx = start; vIdx < end; vIdx++) {
+      if (bitMap.isMarked(vIdx)) {
+        nullCnt++;
+        continue;
+      }
+      // move value ahead to replace null
+      int tIdx = vIdx - tIdxOffset;
+      if (nullCnt != 0) {
+        time[tIdx - nullCnt] = time[tIdx];
+        values[vIdx - nullCnt] = values[vIdx];
+      }
+      // update minTime and sorted
+      tIdx = tIdx - nullCnt;
+      inPutMinTime = Math.min(inPutMinTime, time[tIdx]);
+      if (inputSorted && tIdx > 0 && time[tIdx - 1] > time[tIdx]) {
+        inputSorted = false;
+      }
+    }
+    minTime = Math.min(inPutMinTime, minTime);
+    sorted = sorted && inputSorted && (size == 0 || inPutMinTime >= 
getTime(size - 1));
+    return nullCnt;
+  }
+
   @Override
   public TSDataType getDataType() {
     return TSDataType.DOUBLE;
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/FloatTVList.java 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/FloatTVList.java
index d2ead4b..3e4078a 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/FloatTVList.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/FloatTVList.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.db.utils.MathUtils;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
+import org.apache.iotdb.tsfile.utils.BitMap;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType;
 
 import java.util.ArrayList;
@@ -32,6 +33,8 @@ import static 
org.apache.iotdb.db.rescon.PrimitiveArrayManager.ARRAY_SIZE;
 
 public class FloatTVList extends TVList {
 
+  // list of primitive array, add 1 when expanded -> float primitive array
+  // index relation: arrayIndex -> elementIndex
   private List<float[]> values;
 
   private float[][] sortedValues;
@@ -198,11 +201,25 @@ public class FloatTVList extends TVList {
   }
 
   @Override
-  public void putFloats(long[] time, float[] value, int start, int end) {
+  public void putFloats(long[] time, float[] value, BitMap bitMap, int start, 
int end) {
     checkExpansion();
-    int idx = start;
 
-    updateMinTimeAndSorted(time, start, end);
+    int idx = start;
+    // constraint: time.length + timeIdxOffset == value.length
+    int timeIdxOffset = 0;
+    if (bitMap != null && !bitMap.isAllUnmarked()) {
+      // time array is a reference, should clone necessary time values
+      long[] clonedTime = new long[end - start];
+      System.arraycopy(time, start, clonedTime, 0, end - start);
+      time = clonedTime;
+      timeIdxOffset = start;
+      // drop null at the end of value array
+      int nullCnt =
+          dropNullValThenUpdateMinTimeAndSorted(time, value, bitMap, start, 
end, timeIdxOffset);
+      end -= nullCnt;
+    } else {
+      updateMinTimeAndSorted(time, start, end);
+    }
 
     while (idx < end) {
       int inputRemaining = end - idx;
@@ -211,14 +228,16 @@ public class FloatTVList extends TVList {
       int internalRemaining = ARRAY_SIZE - elementIdx;
       if (internalRemaining >= inputRemaining) {
         // the remaining inputs can fit the last array, copy all remaining 
inputs into last array
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
inputRemaining);
         size += inputRemaining;
         break;
       } else {
         // the remaining inputs cannot fit the last array, fill the last array 
and create a new
         // one and enter the next loop
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
internalRemaining);
         idx += internalRemaining;
         size += internalRemaining;
@@ -227,6 +246,36 @@ public class FloatTVList extends TVList {
     }
   }
 
+  // move null values to the end of time array and value array, then return 
number of null values
+  int dropNullValThenUpdateMinTimeAndSorted(
+      long[] time, float[] values, BitMap bitMap, int start, int end, int 
tIdxOffset) {
+    long inPutMinTime = Long.MAX_VALUE;
+    boolean inputSorted = true;
+
+    int nullCnt = 0;
+    for (int vIdx = start; vIdx < end; vIdx++) {
+      if (bitMap.isMarked(vIdx)) {
+        nullCnt++;
+        continue;
+      }
+      // move value ahead to replace null
+      int tIdx = vIdx - tIdxOffset;
+      if (nullCnt != 0) {
+        time[tIdx - nullCnt] = time[tIdx];
+        values[vIdx - nullCnt] = values[vIdx];
+      }
+      // update minTime and sorted
+      tIdx = tIdx - nullCnt;
+      inPutMinTime = Math.min(inPutMinTime, time[tIdx]);
+      if (inputSorted && tIdx > 0 && time[tIdx - 1] > time[tIdx]) {
+        inputSorted = false;
+      }
+    }
+    minTime = Math.min(inPutMinTime, minTime);
+    sorted = sorted && inputSorted && (size == 0 || inPutMinTime >= 
getTime(size - 1));
+    return nullCnt;
+  }
+
   @Override
   public TSDataType getDataType() {
     return TSDataType.FLOAT;
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/IntTVList.java 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/IntTVList.java
index caab7d9..7a7f35a 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/IntTVList.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/IntTVList.java
@@ -22,6 +22,7 @@ import org.apache.iotdb.db.rescon.PrimitiveArrayManager;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
+import org.apache.iotdb.tsfile.utils.BitMap;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType;
 
 import java.util.ArrayList;
@@ -31,6 +32,8 @@ import static 
org.apache.iotdb.db.rescon.PrimitiveArrayManager.ARRAY_SIZE;
 
 public class IntTVList extends TVList {
 
+  // list of primitive array, add 1 when expanded -> int primitive array
+  // index relation: arrayIndex -> elementIndex
   private List<int[]> values;
 
   private int[][] sortedValues;
@@ -192,11 +195,25 @@ public class IntTVList extends TVList {
   }
 
   @Override
-  public void putInts(long[] time, int[] value, int start, int end) {
+  public void putInts(long[] time, int[] value, BitMap bitMap, int start, int 
end) {
     checkExpansion();
-    int idx = start;
 
-    updateMinTimeAndSorted(time, start, end);
+    int idx = start;
+    // constraint: time.length + timeIdxOffset == value.length
+    int timeIdxOffset = 0;
+    if (bitMap != null && !bitMap.isAllUnmarked()) {
+      // time array is a reference, should clone necessary time values
+      long[] clonedTime = new long[end - start];
+      System.arraycopy(time, start, clonedTime, 0, end - start);
+      time = clonedTime;
+      timeIdxOffset = start;
+      // drop null at the end of value array
+      int nullCnt =
+          dropNullValThenUpdateMinTimeAndSorted(time, value, bitMap, start, 
end, timeIdxOffset);
+      end -= nullCnt;
+    } else {
+      updateMinTimeAndSorted(time, start, end);
+    }
 
     while (idx < end) {
       int inputRemaining = end - idx;
@@ -205,14 +222,16 @@ public class IntTVList extends TVList {
       int internalRemaining = ARRAY_SIZE - elementIdx;
       if (internalRemaining >= inputRemaining) {
         // the remaining inputs can fit the last array, copy all remaining 
inputs into last array
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
inputRemaining);
         size += inputRemaining;
         break;
       } else {
         // the remaining inputs cannot fit the last array, fill the last array 
and create a new
         // one and enter the next loop
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
internalRemaining);
         idx += internalRemaining;
         size += internalRemaining;
@@ -221,6 +240,36 @@ public class IntTVList extends TVList {
     }
   }
 
+  // move null values to the end of time array and value array, then return 
number of null values
+  int dropNullValThenUpdateMinTimeAndSorted(
+      long[] time, int[] values, BitMap bitMap, int start, int end, int 
tIdxOffset) {
+    long inPutMinTime = Long.MAX_VALUE;
+    boolean inputSorted = true;
+
+    int nullCnt = 0;
+    for (int vIdx = start; vIdx < end; vIdx++) {
+      if (bitMap.isMarked(vIdx)) {
+        nullCnt++;
+        continue;
+      }
+      // move value ahead to replace null
+      int tIdx = vIdx - tIdxOffset;
+      if (nullCnt != 0) {
+        time[tIdx - nullCnt] = time[tIdx];
+        values[vIdx - nullCnt] = values[vIdx];
+      }
+      // update minTime and sorted
+      tIdx = tIdx - nullCnt;
+      inPutMinTime = Math.min(inPutMinTime, time[tIdx]);
+      if (inputSorted && tIdx > 0 && time[tIdx - 1] > time[tIdx]) {
+        inputSorted = false;
+      }
+    }
+    minTime = Math.min(inPutMinTime, minTime);
+    sorted = sorted && inputSorted && (size == 0 || inPutMinTime >= 
getTime(size - 1));
+    return nullCnt;
+  }
+
   @Override
   public TSDataType getDataType() {
     return TSDataType.INT32;
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/LongTVList.java 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/LongTVList.java
index 1459e39..c8c8ddd 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/LongTVList.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/LongTVList.java
@@ -22,6 +22,7 @@ import org.apache.iotdb.db.rescon.PrimitiveArrayManager;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.read.TimeValuePair;
+import org.apache.iotdb.tsfile.utils.BitMap;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType;
 
 import java.util.ArrayList;
@@ -31,6 +32,8 @@ import static 
org.apache.iotdb.db.rescon.PrimitiveArrayManager.ARRAY_SIZE;
 
 public class LongTVList extends TVList {
 
+  // list of primitive array, add 1 when expanded -> long primitive array
+  // index relation: arrayIndex -> elementIndex
   private List<long[]> values;
 
   private long[][] sortedValues;
@@ -187,21 +190,30 @@ public class LongTVList extends TVList {
   }
 
   @Override
-  public TSDataType getDataType() {
-    return TSDataType.INT64;
-  }
-
-  @Override
   protected void releaseLastValueArray() {
     PrimitiveArrayManager.release(values.remove(values.size() - 1));
   }
 
   @Override
-  public void putLongs(long[] time, long[] value, int start, int end) {
+  public void putLongs(long[] time, long[] value, BitMap bitMap, int start, 
int end) {
     checkExpansion();
-    int idx = start;
 
-    updateMinTimeAndSorted(time, start, end);
+    int idx = start;
+    // constraint: time.length + timeIdxOffset == value.length
+    int timeIdxOffset = 0;
+    if (bitMap != null && !bitMap.isAllUnmarked()) {
+      // time array is a reference, should clone necessary time values
+      long[] clonedTime = new long[end - start];
+      System.arraycopy(time, start, clonedTime, 0, end - start);
+      time = clonedTime;
+      timeIdxOffset = start;
+      // drop null at the end of value array
+      int nullCnt =
+          dropNullValThenUpdateMinTimeAndSorted(time, value, bitMap, start, 
end, timeIdxOffset);
+      end -= nullCnt;
+    } else {
+      updateMinTimeAndSorted(time, start, end);
+    }
 
     while (idx < end) {
       int inputRemaining = end - idx;
@@ -210,14 +222,16 @@ public class LongTVList extends TVList {
       int internalRemaining = ARRAY_SIZE - elementIdx;
       if (internalRemaining >= inputRemaining) {
         // the remaining inputs can fit the last array, copy all remaining 
inputs into last array
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
inputRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
inputRemaining);
         size += inputRemaining;
         break;
       } else {
         // the remaining inputs cannot fit the last array, fill the last array 
and create a new
         // one and enter the next loop
-        System.arraycopy(time, idx, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
+        System.arraycopy(
+            time, idx - timeIdxOffset, timestamps.get(arrayIdx), elementIdx, 
internalRemaining);
         System.arraycopy(value, idx, values.get(arrayIdx), elementIdx, 
internalRemaining);
         idx += internalRemaining;
         size += internalRemaining;
@@ -225,4 +239,39 @@ public class LongTVList extends TVList {
       }
     }
   }
+
+  // move null values to the end of time array and value array, then return 
number of null values
+  int dropNullValThenUpdateMinTimeAndSorted(
+      long[] time, long[] values, BitMap bitMap, int start, int end, int 
tIdxOffset) {
+    long inPutMinTime = Long.MAX_VALUE;
+    boolean inputSorted = true;
+
+    int nullCnt = 0;
+    for (int vIdx = start; vIdx < end; vIdx++) {
+      if (bitMap.isMarked(vIdx)) {
+        nullCnt++;
+        continue;
+      }
+      // move value ahead to replace null
+      int tIdx = vIdx - tIdxOffset;
+      if (nullCnt != 0) {
+        time[tIdx - nullCnt] = time[tIdx];
+        values[vIdx - nullCnt] = values[vIdx];
+      }
+      // update minTime and sorted
+      tIdx = tIdx - nullCnt;
+      inPutMinTime = Math.min(inPutMinTime, time[tIdx]);
+      if (inputSorted && tIdx > 0 && time[tIdx - 1] > time[tIdx]) {
+        inputSorted = false;
+      }
+    }
+    minTime = Math.min(inPutMinTime, minTime);
+    sorted = sorted && inputSorted && (size == 0 || inPutMinTime >= 
getTime(size - 1));
+    return nullCnt;
+  }
+
+  @Override
+  public TSDataType getDataType() {
+    return TSDataType.INT64;
+  }
 }
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/TVList.java 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/TVList.java
index 5b960d0..3e78339 100644
--- a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/TVList.java
+++ b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/TVList.java
@@ -40,6 +40,8 @@ public abstract class TVList {
 
   protected static final int SMALL_ARRAY_LENGTH = 32;
   protected static final String ERR_DATATYPE_NOT_CONSISTENT = "DataType not 
consistent";
+  // list of timestamp array, add 1 when expanded -> data point timestamp array
+  // index relation: arrayIndex -> elementIndex
   protected List<long[]> timestamps;
   protected int size;
 
@@ -165,31 +167,31 @@ public abstract class TVList {
     throw new UnsupportedOperationException(ERR_DATATYPE_NOT_CONSISTENT);
   }
 
-  public void putLongs(long[] time, long[] value, int start, int end) {
+  public void putLongs(long[] time, long[] value, BitMap bitMap, int start, 
int end) {
     throw new UnsupportedOperationException(ERR_DATATYPE_NOT_CONSISTENT);
   }
 
-  public void putInts(long[] time, int[] value, int start, int end) {
+  public void putInts(long[] time, int[] value, BitMap bitMap, int start, int 
end) {
     throw new UnsupportedOperationException(ERR_DATATYPE_NOT_CONSISTENT);
   }
 
-  public void putFloats(long[] time, float[] value, int start, int end) {
+  public void putFloats(long[] time, float[] value, BitMap bitMap, int start, 
int end) {
     throw new UnsupportedOperationException(ERR_DATATYPE_NOT_CONSISTENT);
   }
 
-  public void putDoubles(long[] time, double[] value, int start, int end) {
+  public void putDoubles(long[] time, double[] value, BitMap bitMap, int 
start, int end) {
     throw new UnsupportedOperationException(ERR_DATATYPE_NOT_CONSISTENT);
   }
 
-  public void putBinaries(long[] time, Binary[] value, int start, int end) {
+  public void putBinaries(long[] time, Binary[] value, BitMap bitMap, int 
start, int end) {
     throw new UnsupportedOperationException(ERR_DATATYPE_NOT_CONSISTENT);
   }
 
-  public void putBooleans(long[] time, boolean[] value, int start, int end) {
+  public void putBooleans(long[] time, boolean[] value, BitMap bitMap, int 
start, int end) {
     throw new UnsupportedOperationException(ERR_DATATYPE_NOT_CONSISTENT);
   }
 
-  public void putVectors(long[] time, BitMap[] bitMaps, Object[] value, int 
start, int end) {
+  public void putVectors(long[] time, Object[] value, BitMap[] bitMaps, int 
start, int end) {
     throw new UnsupportedOperationException(ERR_DATATYPE_NOT_CONSISTENT);
   }
 
diff --git 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/VectorTVList.java
 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/VectorTVList.java
index 1bb4cfe..05b30cd 100644
--- 
a/server/src/main/java/org/apache/iotdb/db/utils/datastructure/VectorTVList.java
+++ 
b/server/src/main/java/org/apache/iotdb/db/utils/datastructure/VectorTVList.java
@@ -34,12 +34,21 @@ import static 
org.apache.iotdb.db.rescon.PrimitiveArrayManager.ARRAY_SIZE;
 
 public class VectorTVList extends TVList {
 
+  // data types of this vector
   private List<TSDataType> dataTypes;
 
+  // data type list -> list of TVList, add 1 when expanded -> primitive array 
of basic type
+  // index relation: columnIndex(dataTypeIndex) -> arrayIndex -> elementIndex
   private List<List<Object>> values;
 
+  // list of index array, add 1 when expanded -> data point index array
+  // index relation: arrayIndex -> elementIndex
+  // used in sort method, sort only changes indices
   private List<int[]> indices;
 
+  // data type list -> list of BitMap, add 1 when expanded -> BitMap(maybe 
null), marked means the
+  // value is null
+  // index relation: columnIndex(dataTypeIndex) -> arrayIndex -> elementIndex
   private List<List<BitMap>> bitMaps;
 
   private int[][] sortedIndices;
@@ -135,47 +144,52 @@ public class VectorTVList extends TVList {
     int arrayIndex = valueIndex / ARRAY_SIZE;
     int elementIndex = valueIndex % ARRAY_SIZE;
     TsPrimitiveType[] vector = new TsPrimitiveType[values.size()];
-    for (int i = 0; i < values.size(); i++) {
-      List<Object> columnValues = values.get(i);
+    for (int columnIndex = 0; columnIndex < values.size(); columnIndex++) {
+      List<Object> columnValues = values.get(columnIndex);
       if (validIndexesForTimeDuplicatedRows != null) {
-        arrayIndex = validIndexesForTimeDuplicatedRows[i] / ARRAY_SIZE;
-        elementIndex = validIndexesForTimeDuplicatedRows[i] % ARRAY_SIZE;
+        arrayIndex = validIndexesForTimeDuplicatedRows[columnIndex] / 
ARRAY_SIZE;
+        elementIndex = validIndexesForTimeDuplicatedRows[columnIndex] % 
ARRAY_SIZE;
       }
       if (bitMaps != null
-          && bitMaps.get(i) != null
-          && bitMaps.get(i).get(arrayIndex).isMarked(elementIndex)) {
+          && bitMaps.get(columnIndex) != null
+          && isValueMarked(valueIndex, columnIndex)) {
         continue;
       }
-      switch (dataTypes.get(i)) {
+      switch (dataTypes.get(columnIndex)) {
         case TEXT:
-          vector[i] =
+          vector[columnIndex] =
               TsPrimitiveType.getByType(
-                  dataTypes.get(i), ((Binary[]) 
columnValues.get(arrayIndex))[elementIndex]);
+                  dataTypes.get(columnIndex),
+                  ((Binary[]) columnValues.get(arrayIndex))[elementIndex]);
           break;
         case FLOAT:
-          vector[i] =
+          vector[columnIndex] =
               TsPrimitiveType.getByType(
-                  dataTypes.get(i), ((float[]) 
columnValues.get(arrayIndex))[elementIndex]);
+                  dataTypes.get(columnIndex),
+                  ((float[]) columnValues.get(arrayIndex))[elementIndex]);
           break;
         case INT32:
-          vector[i] =
+          vector[columnIndex] =
               TsPrimitiveType.getByType(
-                  dataTypes.get(i), ((int[]) 
columnValues.get(arrayIndex))[elementIndex]);
+                  dataTypes.get(columnIndex), ((int[]) 
columnValues.get(arrayIndex))[elementIndex]);
           break;
         case INT64:
-          vector[i] =
+          vector[columnIndex] =
               TsPrimitiveType.getByType(
-                  dataTypes.get(i), ((long[]) 
columnValues.get(arrayIndex))[elementIndex]);
+                  dataTypes.get(columnIndex),
+                  ((long[]) columnValues.get(arrayIndex))[elementIndex]);
           break;
         case DOUBLE:
-          vector[i] =
+          vector[columnIndex] =
               TsPrimitiveType.getByType(
-                  dataTypes.get(i), ((double[]) 
columnValues.get(arrayIndex))[elementIndex]);
+                  dataTypes.get(columnIndex),
+                  ((double[]) columnValues.get(arrayIndex))[elementIndex]);
           break;
         case BOOLEAN:
-          vector[i] =
+          vector[columnIndex] =
               TsPrimitiveType.getByType(
-                  dataTypes.get(i), ((boolean[]) 
columnValues.get(arrayIndex))[elementIndex]);
+                  dataTypes.get(columnIndex),
+                  ((boolean[]) columnValues.get(arrayIndex))[elementIndex]);
           break;
         default:
           throw new UnsupportedOperationException(ERR_DATATYPE_NOT_CONSISTENT);
@@ -306,7 +320,9 @@ public class VectorTVList extends TVList {
     if (rowIndex >= size) {
       return false;
     }
-    if (bitMaps == null || bitMaps.get(columnIndex) == null) {
+    if (bitMaps == null
+        || bitMaps.get(columnIndex) == null
+        || bitMaps.get(columnIndex).get(rowIndex / ARRAY_SIZE) == null) {
       return false;
     }
     int arrayIndex = rowIndex / ARRAY_SIZE;
@@ -343,6 +359,7 @@ public class VectorTVList extends TVList {
       for (Object valueArray : columnValues) {
         cloneList.values.get(i).add(cloneValue(dataTypes.get(i), valueArray));
       }
+      // clone bitmap in columnIndex
       if (bitMaps != null && bitMaps.get(i) != null) {
         List<BitMap> columnBitMaps = bitMaps.get(i);
         if (cloneList.bitMaps == null) {
@@ -353,11 +370,11 @@ public class VectorTVList extends TVList {
         }
         if (cloneList.bitMaps.get(i) == null) {
           List<BitMap> cloneColumnBitMaps = new ArrayList<>();
+          for (BitMap bitMap : columnBitMaps) {
+            cloneColumnBitMaps.add(bitMap == null ? null : bitMap.clone());
+          }
           cloneList.bitMaps.set(i, cloneColumnBitMaps);
         }
-        for (BitMap bitMap : columnBitMaps) {
-          cloneList.bitMaps.get(i).add(cloneBitMap(bitMap));
-        }
       }
     }
     return cloneList;
@@ -369,12 +386,6 @@ public class VectorTVList extends TVList {
     return cloneArray;
   }
 
-  private BitMap cloneBitMap(BitMap bitMap) {
-    byte[] cloneBytes = new byte[bitMap.getByteArray().length];
-    System.arraycopy(bitMap.getByteArray(), 0, cloneBytes, 0, 
bitMap.getByteArray().length);
-    return new BitMap(bitMap.getSize(), cloneBytes);
-  }
-
   private Object cloneValue(TSDataType type, Object value) {
     switch (type) {
       case TEXT:
@@ -497,10 +508,10 @@ public class VectorTVList extends TVList {
   protected void expandValues() {
     indices.add((int[]) getPrimitiveArraysByType(TSDataType.INT32));
     for (int i = 0; i < dataTypes.size(); i++) {
+      values.get(i).add(getPrimitiveArraysByType(dataTypes.get(i)));
       if (bitMaps != null && bitMaps.get(i) != null) {
-        bitMaps.get(i).add(new BitMap(ARRAY_SIZE));
+        bitMaps.get(i).add(null);
       }
-      values.get(i).add(getPrimitiveArraysByType(dataTypes.get(i)));
     }
   }
 
@@ -590,7 +601,7 @@ public class VectorTVList extends TVList {
 
   @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity 
warning
   @Override
-  public void putVectors(long[] time, BitMap[] bitMaps, Object[] value, int 
start, int end) {
+  public void putVectors(long[] time, Object[] value, BitMap[] bitMaps, int 
start, int end) {
     checkExpansion();
     int idx = start;
 
@@ -686,11 +697,16 @@ public class VectorTVList extends TVList {
     if (bitMaps.get(columnIndex) == null) {
       List<BitMap> columnBitMaps = new ArrayList<>();
       for (int i = 0; i < values.get(columnIndex).size(); i++) {
-        columnBitMaps.add(new BitMap(ARRAY_SIZE));
+        columnBitMaps.add(null);
       }
       bitMaps.set(columnIndex, columnBitMaps);
     }
 
+    // if the bitmap in arrayIndex is null, init the bitmap
+    if (bitMaps.get(columnIndex).get(arrayIndex) == null) {
+      bitMaps.get(columnIndex).set(arrayIndex, new BitMap(ARRAY_SIZE));
+    }
+
     // mark the null value in the current bitmap
     bitMaps.get(columnIndex).get(arrayIndex).mark(elementIndex);
   }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSelectIntoIT.java 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSelectIntoIT.java
index 1b30344..f80b588 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSelectIntoIT.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/integration/IoTDBSelectIntoIT.java
@@ -397,7 +397,7 @@ public class IoTDBSelectIntoIT {
       try (ResultSet resultSet = statement.executeQuery("select gbf_s1 from 
root.sg.d1")) {
         assertEquals(1 + 1, resultSet.getMetaData().getColumnCount());
 
-        for (int i = 1; i < 10; ++i) {
+        for (int i = 1; i < 5; ++i) {
           assertTrue(resultSet.next());
           for (int j = 0; j < 1 + 1; ++j) {
             assertEquals(String.valueOf(i), resultSet.getString(1));
diff --git 
a/server/src/test/java/org/apache/iotdb/db/qp/physical/InsertTabletPlanTest.java
 
b/server/src/test/java/org/apache/iotdb/db/qp/physical/InsertTabletPlanTest.java
index a3f7e3b..1fae60e 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/qp/physical/InsertTabletPlanTest.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/qp/physical/InsertTabletPlanTest.java
@@ -37,6 +37,7 @@ import 
org.apache.iotdb.tsfile.exception.filter.QueryFilterOptimizationException
 import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
 import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.read.common.Field;
 import org.apache.iotdb.tsfile.read.common.RowRecord;
 import org.apache.iotdb.tsfile.read.query.dataset.QueryDataSet;
 import org.apache.iotdb.tsfile.utils.Binary;
@@ -121,10 +122,80 @@ public class InsertTabletPlanTest {
   }
 
   @Test
+  public void testInsertNullableTabletPlan()
+      throws QueryProcessException, MetadataException, InterruptedException,
+          QueryFilterOptimizationException, StorageEngineException, 
IOException {
+    long[] times = new long[] {110L, 111L, 112L, 113L};
+    List<Integer> dataTypes = new ArrayList<>();
+    dataTypes.add(TSDataType.DOUBLE.ordinal());
+    dataTypes.add(TSDataType.FLOAT.ordinal());
+    dataTypes.add(TSDataType.INT64.ordinal());
+    dataTypes.add(TSDataType.INT32.ordinal());
+    dataTypes.add(TSDataType.BOOLEAN.ordinal());
+    dataTypes.add(TSDataType.TEXT.ordinal());
+
+    Object[] columns = new Object[6];
+    columns[0] = new double[4];
+    columns[1] = new float[4];
+    columns[2] = new long[4];
+    columns[3] = new int[4];
+    columns[4] = new boolean[4];
+    columns[5] = new Binary[4];
+
+    for (int r = 0; r < 4; r++) {
+      ((double[]) columns[0])[r] = 1.0 + r;
+      ((float[]) columns[1])[r] = 2 + r;
+      ((long[]) columns[2])[r] = 10000 + r;
+      ((int[]) columns[3])[r] = 100 + r;
+      ((boolean[]) columns[4])[r] = (r % 2 == 0);
+      ((Binary[]) columns[5])[r] = new Binary("hh" + r);
+    }
+
+    BitMap[] bitMaps = new BitMap[dataTypes.size()];
+    for (int i = 0; i < dataTypes.size(); i++) {
+      if (bitMaps[i] == null) {
+        bitMaps[i] = new BitMap(times.length);
+      }
+      bitMaps[i].mark(i % times.length);
+    }
+
+    InsertTabletPlan tabletPlan =
+        new InsertTabletPlan(
+            new PartialPath("root.isp.d1"),
+            new String[] {"s1", "s2", "s3", "s4", "s5", "s6"},
+            dataTypes);
+    tabletPlan.setTimes(times);
+    tabletPlan.setColumns(columns);
+    tabletPlan.setRowCount(times.length);
+    tabletPlan.setBitMaps(bitMaps);
+
+    PlanExecutor executor = new PlanExecutor();
+    executor.insertTablet(tabletPlan);
+
+    QueryPlan queryPlan = (QueryPlan) processor.parseSQLToPhysicalPlan("select 
* from root.isp.d1");
+    QueryDataSet dataSet = executor.processQuery(queryPlan, 
EnvironmentUtils.TEST_QUERY_CONTEXT);
+    Assert.assertEquals(6, dataSet.getPaths().size());
+    int rowNum = 0;
+    while (dataSet.hasNext()) {
+      RowRecord record = dataSet.next();
+      Assert.assertEquals(6, record.getFields().size());
+      List<Field> fields = record.getFields();
+      for (int i = 0; i < 6; ++i) {
+        if (i % times.length == rowNum) {
+          Assert.assertNull(fields.get(i));
+        } else {
+          Assert.assertNotNull(fields.get(i));
+        }
+      }
+      rowNum++;
+    }
+  }
+
+  @Test
   public void testInsertTabletPlanWithAlignedTimeseries()
       throws QueryProcessException, MetadataException, InterruptedException,
           QueryFilterOptimizationException, StorageEngineException, 
IOException {
-    InsertTabletPlan tabletPlan = getInsertTabletPlan();
+    InsertTabletPlan tabletPlan = getVectorInsertTabletPlan();
 
     PlanExecutor executor = new PlanExecutor();
     executor.insertTablet(tabletPlan);
@@ -146,10 +217,10 @@ public class InsertTabletPlanTest {
   public void testInsertNullableTabletPlanWithAlignedTimeseries()
       throws QueryProcessException, MetadataException, InterruptedException,
           QueryFilterOptimizationException, StorageEngineException, 
IOException {
-    InsertTabletPlan tabletPlan = getInsertTabletPlan();
-    tabletPlan.setBitMaps(new BitMap[6]);
+    InsertTabletPlan tabletPlan = getVectorInsertTabletPlan();
+    tabletPlan.setBitMaps(new BitMap[3]);
     BitMap[] bitMaps = tabletPlan.getBitMaps();
-    for (int i = 0; i < 4; i++) {
+    for (int i = 0; i < 3; i++) {
       if (bitMaps[i] == null) {
         bitMaps[i] = new BitMap(4);
       }
@@ -180,7 +251,7 @@ public class InsertTabletPlanTest {
     IoTDB.metaManager.createSchemaTemplate(plan);
     IoTDB.metaManager.setSchemaTemplate(new SetSchemaTemplatePlan("template1", 
"root.isp"));
 
-    InsertTabletPlan tabletPlan = getInsertTabletPlan();
+    InsertTabletPlan tabletPlan = getVectorInsertTabletPlan();
 
     PlanExecutor executor = new PlanExecutor();
 
@@ -259,7 +330,7 @@ public class InsertTabletPlanTest {
 
     IoTDB.metaManager.createSchemaTemplate(plan);
     IoTDB.metaManager.setSchemaTemplate(new SetSchemaTemplatePlan("template1", 
"root.isp"));
-    InsertTabletPlan tabletPlan = getInsertTabletPlan();
+    InsertTabletPlan tabletPlan = getVectorInsertTabletPlan();
 
     PlanExecutor executor = new PlanExecutor();
     executor.insertTablet(tabletPlan);
@@ -296,7 +367,7 @@ public class InsertTabletPlanTest {
 
   @Test
   public void testInsertTabletSerialization() throws IllegalPathException, 
QueryProcessException {
-    InsertTabletPlan plan1 = getInsertTabletPlan();
+    InsertTabletPlan plan1 = getVectorInsertTabletPlan();
 
     PlanExecutor executor = new PlanExecutor();
     executor.insertTablet(plan1);
@@ -317,7 +388,7 @@ public class InsertTabletPlanTest {
   @Test
   public void testInsertTabletWithBitMapsSerialization()
       throws IllegalPathException, QueryProcessException {
-    InsertTabletPlan plan1 = getInsertTabletPlan();
+    InsertTabletPlan plan1 = getVectorInsertTabletPlan();
     plan1.setBitMaps(new BitMap[3]);
     BitMap[] bitMaps = plan1.getBitMaps();
     for (int i = 0; i < 3; i++) {
@@ -342,7 +413,7 @@ public class InsertTabletPlanTest {
     Assert.assertEquals(plan1, plan2);
   }
 
-  private InsertTabletPlan getInsertTabletPlan() throws IllegalPathException {
+  private InsertTabletPlan getVectorInsertTabletPlan() throws 
IllegalPathException {
     long[] times = new long[] {110L, 111L, 112L, 113L};
     List<Integer> dataTypes = new ArrayList<>();
     dataTypes.add(TSDataType.DOUBLE.ordinal());
diff --git 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/BinaryTVListTest.java
 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/BinaryTVListTest.java
index b46a2b9..8e09c7d 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/BinaryTVListTest.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/BinaryTVListTest.java
@@ -19,6 +19,7 @@
 package org.apache.iotdb.db.utils.datastructure;
 
 import org.apache.iotdb.tsfile.utils.Binary;
+import org.apache.iotdb.tsfile.utils.BitMap;
 
 import org.apache.commons.lang3.ArrayUtils;
 import org.junit.Assert;
@@ -42,17 +43,69 @@ public class BinaryTVListTest {
   }
 
   @Test
-  public void testBinaryTVLists() {
+  public void testPutBinariesWithoutBitMap() {
     BinaryTVList tvList = new BinaryTVList();
     Binary[] binaryList = new Binary[1001];
     List<Long> timeList = new ArrayList<>();
     for (int i = 1000; i >= 0; i--) {
       timeList.add((long) i);
-      binaryList[i] = Binary.valueOf(String.valueOf(i));
+      binaryList[1000 - i] = Binary.valueOf(String.valueOf(i));
     }
-    tvList.putBinaries(ArrayUtils.toPrimitive(timeList.toArray(new Long[0])), 
binaryList, 0, 1000);
+    tvList.putBinaries(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])), binaryList, 
null, 0, 1000);
     for (long i = 0; i < tvList.size; i++) {
       Assert.assertEquals(tvList.size - i, tvList.getTime((int) i));
     }
   }
+
+  @Test
+  public void testPutBinariesWithBitMap() {
+    BinaryTVList tvList = new BinaryTVList();
+    Binary[] binaryList = new Binary[1001];
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (int i = 1000; i >= 0; i--) {
+      timeList.add((long) i);
+      binaryList[1000 - i] = Binary.valueOf(String.valueOf(i));
+      if (i % 100 == 0) {
+        bitMap.mark(i);
+      }
+    }
+    tvList.putBinaries(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])), binaryList, 
bitMap, 0, 1000);
+    tvList.sort();
+    int nullCnt = 0;
+    for (long i = 1; i < binaryList.length; i++) {
+      if (i % 100 == 0) {
+        nullCnt++;
+        continue;
+      }
+      Assert.assertEquals(
+          Binary.valueOf(String.valueOf(i)), tvList.getBinary((int) i - 
nullCnt - 1));
+      Assert.assertEquals(i, tvList.getTime((int) i - nullCnt - 1));
+    }
+  }
+
+  @Test
+  public void testClone() {
+    BinaryTVList tvList = new BinaryTVList();
+    Binary[] binaryList = new Binary[1001];
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (int i = 1000; i >= 0; i--) {
+      timeList.add((long) i);
+      binaryList[i] = Binary.valueOf(String.valueOf(i));
+      if (i % 100 == 0) {
+        bitMap.mark(i);
+      }
+    }
+    tvList.putBinaries(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])), binaryList, 
bitMap, 0, 1000);
+    tvList.sort();
+    BinaryTVList clonedTvList = tvList.clone();
+    for (long i = 0; i < tvList.size; i++) {
+      Assert.assertEquals(tvList.getBinary((int) i), 
clonedTvList.getBinary((int) i));
+      Assert.assertEquals(tvList.getTime((int) i), clonedTvList.getTime((int) 
i));
+    }
+  }
 }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/BooleanTVListTest.java
 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/BooleanTVListTest.java
index 20c2796..09eb4ab 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/BooleanTVListTest.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/BooleanTVListTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.iotdb.db.utils.datastructure;
 
+import org.apache.iotdb.tsfile.utils.BitMap;
+
 import org.apache.commons.lang3.ArrayUtils;
 import org.junit.Assert;
 import org.junit.Test;
@@ -46,7 +48,7 @@ public class BooleanTVListTest {
   }
 
   @Test
-  public void testBooleanTVLists() {
+  public void testPutBooleansWithoutBitMap() {
     BooleanTVList tvList = new BooleanTVList();
     List<Boolean> booleanList = new ArrayList<>();
     List<Long> timeList = new ArrayList<>();
@@ -57,10 +59,69 @@ public class BooleanTVListTest {
     tvList.putBooleans(
         ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
         ArrayUtils.toPrimitive(booleanList.toArray(new Boolean[0])),
+        null,
         0,
         1000);
     for (long i = 0; i < tvList.size; i++) {
       Assert.assertEquals(tvList.size - i, tvList.getTime((int) i));
     }
   }
+
+  @Test
+  public void testPutBooleansWithBitMap() {
+    BooleanTVList tvList = new BooleanTVList();
+    List<Boolean> booleanList = new ArrayList<>();
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (long i = 1000; i >= 0; i--) {
+      timeList.add((i));
+      booleanList.add(i % 2 == 0);
+      if (i % 100 == 0) {
+        bitMap.mark((int) i);
+      }
+    }
+    tvList.putBooleans(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
+        ArrayUtils.toPrimitive(booleanList.toArray(new Boolean[0])),
+        bitMap,
+        0,
+        1000);
+    tvList.sort();
+    int nullCnt = 0;
+    for (long i = 1; i < booleanList.size(); i++) {
+      if (i % 100 == 0) {
+        nullCnt++;
+        continue;
+      }
+      Assert.assertEquals(i % 2 == 0, tvList.getBoolean((int) i - nullCnt - 
1));
+      Assert.assertEquals(i, tvList.getTime((int) i - nullCnt - 1));
+    }
+  }
+
+  @Test
+  public void testClone() {
+    BooleanTVList tvList = new BooleanTVList();
+    List<Boolean> booleanList = new ArrayList<>();
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (long i = 1000; i >= 0; i--) {
+      timeList.add((i));
+      booleanList.add(i % 2 == 0);
+      if (i % 100 == 0) {
+        bitMap.mark((int) i);
+      }
+    }
+    tvList.putBooleans(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
+        ArrayUtils.toPrimitive(booleanList.toArray(new Boolean[0])),
+        bitMap,
+        0,
+        1000);
+    tvList.sort();
+    BooleanTVList clonedTvList = tvList.clone();
+    for (long i = 0; i < tvList.size; i++) {
+      Assert.assertEquals(tvList.getBoolean((int) i), 
clonedTvList.getBoolean((int) i));
+      Assert.assertEquals(tvList.getTime((int) i), clonedTvList.getTime((int) 
i));
+    }
+  }
 }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/DoubleTVListTest.java
 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/DoubleTVListTest.java
index 47d5a9d..315c0a3 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/DoubleTVListTest.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/DoubleTVListTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.iotdb.db.utils.datastructure;
 
+import org.apache.iotdb.tsfile.utils.BitMap;
+
 import org.apache.commons.lang3.ArrayUtils;
 import org.junit.Assert;
 import org.junit.Test;
@@ -55,7 +57,7 @@ public class DoubleTVListTest {
   }
 
   @Test
-  public void testDoubleTVLists() {
+  public void testPutDoublesWithoutBitMap() {
     DoubleTVList tvList = new DoubleTVList();
     List<Double> doubleList = new ArrayList<>();
     List<Long> timeList = new ArrayList<>();
@@ -66,6 +68,7 @@ public class DoubleTVListTest {
     tvList.putDoubles(
         ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
         ArrayUtils.toPrimitive(doubleList.toArray(new Double[0]), 0.0d),
+        null,
         0,
         1000);
     for (long i = 0; i < tvList.size; i++) {
@@ -73,4 +76,62 @@ public class DoubleTVListTest {
       Assert.assertEquals(tvList.size - i, tvList.getTime((int) i));
     }
   }
+
+  @Test
+  public void testPutDoublesWithBitMap() {
+    DoubleTVList tvList = new DoubleTVList();
+    List<Double> doubleList = new ArrayList<>();
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (long i = 1000; i >= 0; i--) {
+      timeList.add((i));
+      doubleList.add((double) i);
+      if (i % 100 == 0) {
+        bitMap.mark((int) i);
+      }
+    }
+    tvList.putDoubles(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
+        ArrayUtils.toPrimitive(doubleList.toArray(new Double[0]), 0.0d),
+        bitMap,
+        0,
+        1000);
+    tvList.sort();
+    int nullCnt = 0;
+    for (long i = 1; i < doubleList.size(); i++) {
+      if (i % 100 == 0) {
+        nullCnt++;
+        continue;
+      }
+      Assert.assertEquals(i, tvList.getDouble((int) i - nullCnt - 1), delta);
+      Assert.assertEquals(i, tvList.getTime((int) i - nullCnt - 1));
+    }
+  }
+
+  @Test
+  public void testClone() {
+    DoubleTVList tvList = new DoubleTVList();
+    List<Double> doubleList = new ArrayList<>();
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (long i = 1000; i >= 0; i--) {
+      timeList.add((i));
+      doubleList.add((double) i);
+      if (i % 100 == 0) {
+        bitMap.mark((int) i);
+      }
+    }
+    tvList.putDoubles(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
+        ArrayUtils.toPrimitive(doubleList.toArray(new Double[0]), 0.0d),
+        bitMap,
+        0,
+        1000);
+    tvList.sort();
+    DoubleTVList clonedTvList = tvList.clone();
+    for (long i = 0; i < tvList.size; i++) {
+      Assert.assertEquals(tvList.getDouble((int) i), 
clonedTvList.getDouble((int) i), delta);
+      Assert.assertEquals(tvList.getTime((int) i), clonedTvList.getTime((int) 
i));
+    }
+  }
 }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/FloatTVListTest.java
 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/FloatTVListTest.java
index a132f7a..90c1c12 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/FloatTVListTest.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/FloatTVListTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.iotdb.db.utils.datastructure;
 
+import org.apache.iotdb.tsfile.utils.BitMap;
+
 import org.apache.commons.lang3.ArrayUtils;
 import org.junit.Assert;
 import org.junit.Test;
@@ -55,7 +57,7 @@ public class FloatTVListTest {
   }
 
   @Test
-  public void testFloatTVLists() {
+  public void testPutFloatsWithoutBitMap() {
     FloatTVList tvList = new FloatTVList();
     List<Float> floatList = new ArrayList<>();
     List<Long> timeList = new ArrayList<>();
@@ -66,6 +68,7 @@ public class FloatTVListTest {
     tvList.putFloats(
         ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
         ArrayUtils.toPrimitive(floatList.toArray(new Float[0]), 0.0F),
+        null,
         0,
         1000);
     for (long i = 0; i < tvList.size; i++) {
@@ -73,4 +76,62 @@ public class FloatTVListTest {
       Assert.assertEquals(tvList.size - i, tvList.getTime((int) i));
     }
   }
+
+  @Test
+  public void testPutFloatsWithBitMap() {
+    FloatTVList tvList = new FloatTVList();
+    List<Float> floatList = new ArrayList<>();
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (long i = 1000; i >= 0; i--) {
+      timeList.add(i);
+      floatList.add((float) i);
+      if (i % 100 == 0) {
+        bitMap.mark((int) i);
+      }
+    }
+    tvList.putFloats(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
+        ArrayUtils.toPrimitive(floatList.toArray(new Float[0]), 0.0F),
+        bitMap,
+        0,
+        1000);
+    tvList.sort();
+    int nullCnt = 0;
+    for (long i = 1; i < floatList.size(); i++) {
+      if (i % 100 == 0) {
+        nullCnt++;
+        continue;
+      }
+      Assert.assertEquals(i, tvList.getFloat((int) i - nullCnt - 1), delta);
+      Assert.assertEquals(i, tvList.getTime((int) i - nullCnt - 1));
+    }
+  }
+
+  @Test
+  public void testClone() {
+    FloatTVList tvList = new FloatTVList();
+    List<Float> floatList = new ArrayList<>();
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (long i = 1000; i >= 0; i--) {
+      timeList.add(i);
+      floatList.add((float) i);
+      if (i % 100 == 0) {
+        bitMap.mark((int) i);
+      }
+    }
+    tvList.putFloats(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
+        ArrayUtils.toPrimitive(floatList.toArray(new Float[0]), 0.0F),
+        bitMap,
+        0,
+        1000);
+    tvList.sort();
+    FloatTVList clonedTvList = tvList.clone();
+    for (long i = 0; i < tvList.size; i++) {
+      Assert.assertEquals(tvList.getFloat((int) i), 
clonedTvList.getFloat((int) i), delta);
+      Assert.assertEquals(tvList.getTime((int) i), clonedTvList.getTime((int) 
i));
+    }
+  }
 }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/IntTVListTest.java
 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/IntTVListTest.java
index 250ad5c..8384b80 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/IntTVListTest.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/IntTVListTest.java
@@ -18,6 +18,8 @@
  */
 package org.apache.iotdb.db.utils.datastructure;
 
+import org.apache.iotdb.tsfile.utils.BitMap;
+
 import org.apache.commons.lang3.ArrayUtils;
 import org.junit.Assert;
 import org.junit.Test;
@@ -54,7 +56,7 @@ public class IntTVListTest {
   }
 
   @Test
-  public void testIntTVLists() {
+  public void testPutIntsWithoutBitMap() {
     IntTVList tvList = new IntTVList();
     List<Integer> intList = new ArrayList<>();
     List<Long> timeList = new ArrayList<>();
@@ -65,6 +67,7 @@ public class IntTVListTest {
     tvList.putInts(
         ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
         ArrayUtils.toPrimitive(intList.toArray(new Integer[0])),
+        null,
         0,
         1000);
     for (long i = 0; i < tvList.size; i++) {
@@ -72,4 +75,62 @@ public class IntTVListTest {
       Assert.assertEquals(tvList.size - i, tvList.getTime((int) i));
     }
   }
+
+  @Test
+  public void testPutIntsWithBitMap() {
+    IntTVList tvList = new IntTVList();
+    List<Integer> intList = new ArrayList<>();
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (int i = 1000; i >= 0; i--) {
+      timeList.add((long) i);
+      intList.add(i);
+      if (i % 100 == 0) {
+        bitMap.mark(i);
+      }
+    }
+    tvList.putInts(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
+        ArrayUtils.toPrimitive(intList.toArray(new Integer[0])),
+        bitMap,
+        0,
+        1000);
+    tvList.sort();
+    int nullCnt = 0;
+    for (long i = 1; i < intList.size(); i++) {
+      if (i % 100 == 0) {
+        nullCnt++;
+        continue;
+      }
+      Assert.assertEquals(i, tvList.getInt((int) i - nullCnt - 1));
+      Assert.assertEquals(i, tvList.getTime((int) i - nullCnt - 1));
+    }
+  }
+
+  @Test
+  public void testClone() {
+    IntTVList tvList = new IntTVList();
+    List<Integer> intList = new ArrayList<>();
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (int i = 1000; i >= 0; i--) {
+      timeList.add((long) i);
+      intList.add(i);
+      if (i % 100 == 0) {
+        bitMap.mark(i);
+      }
+    }
+    tvList.putInts(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
+        ArrayUtils.toPrimitive(intList.toArray(new Integer[0])),
+        bitMap,
+        0,
+        1000);
+    tvList.sort();
+    IntTVList clonedTvList = tvList.clone();
+    for (long i = 0; i < tvList.size; i++) {
+      Assert.assertEquals(tvList.getInt((int) i), clonedTvList.getInt((int) 
i));
+      Assert.assertEquals(tvList.getTime((int) i), clonedTvList.getTime((int) 
i));
+    }
+  }
 }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/LongTVListTest.java
 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/LongTVListTest.java
index fc63ec3..4af8cb7 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/LongTVListTest.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/LongTVListTest.java
@@ -19,6 +19,7 @@
 package org.apache.iotdb.db.utils.datastructure;
 
 import org.apache.iotdb.tsfile.read.TimeValuePair;
+import org.apache.iotdb.tsfile.utils.BitMap;
 import org.apache.iotdb.tsfile.utils.TsPrimitiveType.TsLong;
 
 import org.apache.commons.lang3.ArrayUtils;
@@ -77,7 +78,7 @@ public class LongTVListTest {
   }
 
   @Test
-  public void testLongTVLists() {
+  public void testPutLongsWithoutBitMap() {
     LongTVList tvList = new LongTVList();
     List<Long> longList = new ArrayList<>();
     List<Long> timeList = new ArrayList<>();
@@ -88,6 +89,7 @@ public class LongTVListTest {
     tvList.putLongs(
         ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
         ArrayUtils.toPrimitive(longList.toArray(new Long[0])),
+        null,
         0,
         1000);
     for (long i = 0; i < tvList.size; i++) {
@@ -95,4 +97,62 @@ public class LongTVListTest {
       Assert.assertEquals(tvList.size - i, tvList.getTime((int) i));
     }
   }
+
+  @Test
+  public void testPutIntsWithBitMap() {
+    LongTVList tvList = new LongTVList();
+    List<Long> longList = new ArrayList<>();
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (long i = 1000; i >= 0; i--) {
+      timeList.add(i);
+      longList.add(i);
+      if (i % 100 == 0) {
+        bitMap.mark((int) i);
+      }
+    }
+    tvList.putLongs(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
+        ArrayUtils.toPrimitive(longList.toArray(new Long[0])),
+        bitMap,
+        0,
+        1000);
+    tvList.sort();
+    int nullCnt = 0;
+    for (long i = 1; i < longList.size(); i++) {
+      if (i % 100 == 0) {
+        nullCnt++;
+        continue;
+      }
+      Assert.assertEquals(i, tvList.getLong((int) i - nullCnt - 1));
+      Assert.assertEquals(i, tvList.getTime((int) i - nullCnt - 1));
+    }
+  }
+
+  @Test
+  public void testClone() {
+    LongTVList tvList = new LongTVList();
+    List<Long> longList = new ArrayList<>();
+    List<Long> timeList = new ArrayList<>();
+    BitMap bitMap = new BitMap(1001);
+    for (long i = 1000; i >= 0; i--) {
+      timeList.add(i);
+      longList.add(i);
+      if (i % 100 == 0) {
+        bitMap.mark((int) i);
+      }
+    }
+    tvList.putLongs(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])),
+        ArrayUtils.toPrimitive(longList.toArray(new Long[0])),
+        bitMap,
+        0,
+        1000);
+    tvList.sort();
+    LongTVList clonedTvList = tvList.clone();
+    for (long i = 0; i < tvList.size; i++) {
+      Assert.assertEquals(tvList.getLong((int) i), clonedTvList.getLong((int) 
i));
+      Assert.assertEquals(tvList.getTime((int) i), clonedTvList.getTime((int) 
i));
+    }
+  }
 }
diff --git 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/VectorTVListTest.java
 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/VectorTVListTest.java
index c85021f..e1c11e3 100644
--- 
a/server/src/test/java/org/apache/iotdb/db/utils/datastructure/VectorTVListTest.java
+++ 
b/server/src/test/java/org/apache/iotdb/db/utils/datastructure/VectorTVListTest.java
@@ -104,7 +104,7 @@ public class VectorTVListTest {
     }
 
     tvList.putVectors(
-        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])), null, 
vectorArray, 0, 1000);
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])), vectorArray, 
null, 0, 1000);
     for (long i = 0; i < tvList.size; i++) {
       Assert.assertEquals(tvList.size - i, tvList.getTime((int) i));
     }
@@ -132,7 +132,7 @@ public class VectorTVListTest {
     }
 
     tvList.putVectors(
-        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])), bitMaps, 
vectorArray, 0, 1000);
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])), vectorArray, 
bitMaps, 0, 1000);
     for (long i = 0; i < tvList.size; i++) {
       Assert.assertEquals(tvList.size - i, tvList.getTime((int) i));
       if (i % 100 == 0) {
@@ -140,4 +140,40 @@ public class VectorTVListTest {
       }
     }
   }
+
+  @Test
+  public void testClone() {
+    List<TSDataType> dataTypes = new ArrayList<>();
+    BitMap[] bitMaps = new BitMap[5];
+    for (int i = 0; i < 5; i++) {
+      dataTypes.add(TSDataType.INT64);
+      bitMaps[i] = new BitMap(1001);
+    }
+    VectorTVList tvList = new VectorTVList(dataTypes);
+    long[][] vectorArray = new long[5][1001];
+    List<Long> timeList = new ArrayList<>();
+    for (int i = 1000; i >= 0; i--) {
+      timeList.add((long) i);
+      for (int j = 0; j < 5; j++) {
+        vectorArray[j][i] = (long) i;
+        if (i % 100 == 0) {
+          bitMaps[j].mark(i);
+        }
+      }
+    }
+
+    tvList.putVectors(
+        ArrayUtils.toPrimitive(timeList.toArray(new Long[0])), vectorArray, 
bitMaps, 0, 1000);
+
+    VectorTVList clonedTvList = tvList.clone();
+    for (long i = 0; i < tvList.size; i++) {
+      Assert.assertEquals(tvList.getTime((int) i), clonedTvList.getTime((int) 
i));
+      Assert.assertEquals(
+          tvList.getVector((int) i).toString(), clonedTvList.getVector((int) 
i).toString());
+      for (int column = 0; i < 5; i++) {
+        Assert.assertEquals(
+            tvList.isValueMarked((int) i, column), 
clonedTvList.isValueMarked((int) i, column));
+      }
+    }
+  }
 }
diff --git 
a/session/src/test/java/org/apache/iotdb/session/IoTDBSessionSimpleIT.java 
b/session/src/test/java/org/apache/iotdb/session/IoTDBSessionSimpleIT.java
index aad0f2b..171f980 100644
--- a/session/src/test/java/org/apache/iotdb/session/IoTDBSessionSimpleIT.java
+++ b/session/src/test/java/org/apache/iotdb/session/IoTDBSessionSimpleIT.java
@@ -37,6 +37,7 @@ import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
 import org.apache.iotdb.tsfile.read.common.Field;
 import org.apache.iotdb.tsfile.read.common.RowRecord;
 import org.apache.iotdb.tsfile.utils.Binary;
+import org.apache.iotdb.tsfile.utils.BitMap;
 import org.apache.iotdb.tsfile.write.record.Tablet;
 import org.apache.iotdb.tsfile.write.schema.IMeasurementSchema;
 import org.apache.iotdb.tsfile.write.schema.MeasurementSchema;
@@ -424,6 +425,58 @@ public class IoTDBSessionSimpleIT {
   }
 
   @Test
+  public void testInsertTabletWithNullValues()
+      throws IoTDBConnectionException, StatementExecutionException {
+    session = new Session("127.0.0.1", 6667, "root", "root");
+    session.open();
+    List<IMeasurementSchema> schemaList = new ArrayList<>();
+    schemaList.add(new MeasurementSchema("s0", TSDataType.DOUBLE, 
TSEncoding.RLE));
+    schemaList.add(new MeasurementSchema("s1", TSDataType.FLOAT, 
TSEncoding.RLE));
+    schemaList.add(new MeasurementSchema("s2", TSDataType.INT64, 
TSEncoding.RLE));
+    schemaList.add(new MeasurementSchema("s3", TSDataType.INT32, 
TSEncoding.RLE));
+    schemaList.add(new MeasurementSchema("s4", TSDataType.BOOLEAN, 
TSEncoding.RLE));
+    schemaList.add(new MeasurementSchema("s5", TSDataType.TEXT, 
TSEncoding.RLE));
+
+    Tablet tablet = new Tablet("root.sg1.d1", schemaList);
+    for (long time = 0; time < 10; time++) {
+      int rowIndex = tablet.rowSize++;
+      tablet.addTimestamp(rowIndex, time);
+
+      tablet.addValue(schemaList.get(0).getMeasurementId(), rowIndex, (double) 
time);
+      tablet.addValue(schemaList.get(1).getMeasurementId(), rowIndex, (float) 
time);
+      tablet.addValue(schemaList.get(2).getMeasurementId(), rowIndex, time);
+      tablet.addValue(schemaList.get(3).getMeasurementId(), rowIndex, (int) 
time);
+      tablet.addValue(schemaList.get(4).getMeasurementId(), rowIndex, time % 2 
== 0);
+      tablet.addValue(
+          schemaList.get(5).getMeasurementId(), rowIndex, new 
Binary(String.valueOf(time)));
+    }
+
+    BitMap[] bitMaps = new BitMap[schemaList.size()];
+    for (int i = 0; i < schemaList.size(); i++) {
+      if (bitMaps[i] == null) {
+        bitMaps[i] = new BitMap(10);
+      }
+      bitMaps[i].mark(i);
+    }
+    tablet.bitMaps = bitMaps;
+
+    if (tablet.rowSize != 0) {
+      session.insertTablet(tablet);
+      tablet.reset();
+    }
+
+    SessionDataSet dataSet = session.executeQueryStatement("select count(*) 
from root");
+    while (dataSet.hasNext()) {
+      RowRecord rowRecord = dataSet.next();
+      Assert.assertEquals(6L, rowRecord.getFields().size());
+      for (Field field : rowRecord.getFields()) {
+        Assert.assertEquals(9L, field.getLongV());
+      }
+    }
+    session.close();
+  }
+
+  @Test
   public void createTimeSeriesWithDoubleTicks()
       throws IoTDBConnectionException, StatementExecutionException {
     session = new Session("127.0.0.1", 6667, "root", "root");
diff --git a/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/BitMap.java 
b/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/BitMap.java
index 11e5ac1..a933f42 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/BitMap.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/utils/BitMap.java
@@ -124,6 +124,13 @@ public class BitMap {
     return res.toString();
   }
 
+  @Override
+  public BitMap clone() {
+    byte[] cloneBytes = new byte[this.bits.length];
+    System.arraycopy(this.bits, 0, cloneBytes, 0, this.bits.length);
+    return new BitMap(this.size, cloneBytes);
+  }
+
   /** Copies the specified range of the BitMap into a new BitMap. */
   public BitMap copyOfRange(int from, int to) {
     int newLength = to - from;
diff --git 
a/tsfile/src/main/java/org/apache/iotdb/tsfile/write/record/Tablet.java 
b/tsfile/src/main/java/org/apache/iotdb/tsfile/write/record/Tablet.java
index bbe91fb..f136b68 100644
--- a/tsfile/src/main/java/org/apache/iotdb/tsfile/write/record/Tablet.java
+++ b/tsfile/src/main/java/org/apache/iotdb/tsfile/write/record/Tablet.java
@@ -197,9 +197,16 @@ public class Tablet {
     return maxRowNumber;
   }
 
-  /** Reset Tablet to the default state - set the rowSize to 0 */
+  /** Reset Tablet to the default state - set the rowSize to 0 and reset 
bitMaps */
   public void reset() {
     rowSize = 0;
+    if (bitMaps != null) {
+      for (BitMap bitMap : bitMaps) {
+        if (bitMap != null) {
+          bitMap.reset();
+        }
+      }
+    }
   }
 
   private void createColumns() {

Reply via email to