You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by ha...@apache.org on 2024/09/12 10:27:47 UTC

(iotdb) 01/01: [Py-Client] support new data types

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

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

commit a8f519c0b38ff8343e433aaeb501d63065349fac
Author: HTHou <hh...@outlook.com>
AuthorDate: Thu Sep 12 18:27:18 2024 +0800

    [Py-Client] support new data types
---
 iotdb-client/client-py/iotdb/Session.py            | 14 +++-
 .../client-py/iotdb/tsfile/utils/DateUtils.py      | 41 +++++++++++
 iotdb-client/client-py/iotdb/utils/Field.py        | 28 ++++++-
 .../client-py/iotdb/utils/IoTDBConstants.py        |  7 +-
 .../client-py/iotdb/utils/IoTDBRpcDataSet.py       | 85 ++++++++++++++++++----
 iotdb-client/client-py/iotdb/utils/NumpyTablet.py  | 30 ++++++--
 .../client-py/iotdb/utils/SessionDataSet.py        | 24 +++---
 iotdb-client/client-py/iotdb/utils/Tablet.py       | 45 ++++++++----
 8 files changed, 221 insertions(+), 53 deletions(-)

diff --git a/iotdb-client/client-py/iotdb/Session.py b/iotdb-client/client-py/iotdb/Session.py
index 098faf0d520..2904b29dab2 100644
--- a/iotdb-client/client-py/iotdb/Session.py
+++ b/iotdb-client/client-py/iotdb/Session.py
@@ -58,6 +58,7 @@ from .thrift.rpc.ttypes import (
     TSLastDataQueryReq,
     TSInsertStringRecordsOfOneDeviceReq,
 )
+from .tsfile.utils.DateUtils import parse_date_to_int
 from .utils.IoTDBConnectionException import IoTDBConnectionException
 
 logger = logging.getLogger("IoTDB")
@@ -1493,8 +1494,8 @@ class Session(object):
                 format_str_list.append("ci")
                 values_tobe_packed.append(b"\x01")
                 values_tobe_packed.append(value)
-            # INT64
-            elif data_type == 2:
+            # INT64 or TIMESTAMP
+            elif data_type == 2 or data_type == 8:
                 format_str_list.append("cq")
                 values_tobe_packed.append(b"\x02")
                 values_tobe_packed.append(value)
@@ -1508,8 +1509,8 @@ class Session(object):
                 format_str_list.append("cd")
                 values_tobe_packed.append(b"\x04")
                 values_tobe_packed.append(value)
-            # TEXT
-            elif data_type == 5:
+            # TEXT or STRING or BLOB
+            elif data_type == 5 or data_type == 10 or data_type == 11:
                 if isinstance(value, str):
                     value_bytes = bytes(value, "utf-8")
                 else:
@@ -1520,6 +1521,11 @@ class Session(object):
                 values_tobe_packed.append(b"\x05")
                 values_tobe_packed.append(len(value_bytes))
                 values_tobe_packed.append(value_bytes)
+            # DATE
+            elif data_type == 9:
+                format_str_list.append("ci")
+                values_tobe_packed.append(b"\x01")
+                values_tobe_packed.append(parse_date_to_int(value))
             else:
                 raise RuntimeError("Unsupported data type:" + str(data_type))
         format_str = "".join(format_str_list)
diff --git a/iotdb-client/client-py/iotdb/tsfile/utils/DateUtils.py b/iotdb-client/client-py/iotdb/tsfile/utils/DateUtils.py
new file mode 100644
index 00000000000..4cafedea618
--- /dev/null
+++ b/iotdb-client/client-py/iotdb/tsfile/utils/DateUtils.py
@@ -0,0 +1,41 @@
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+from datetime import date
+
+
+class DateTimeParseException(Exception):
+    pass
+
+
+def parse_int_to_date(date_int: int) -> date:
+    try:
+        year = date_int // 10000
+        month = (date_int // 100) % 100
+        day = date_int % 100
+        return date(year, month, day)
+    except ValueError as e:
+        raise DateTimeParseException("Invalid date format.") from e
+
+
+def parse_date_to_int(local_date: date) -> int:
+    if local_date is None:
+        raise DateTimeParseException("Date expression is none or empty.")
+    if local_date.year < 1000:
+        raise DateTimeParseException("Year must be between 1000 and 9999.")
+    return local_date.year * 10000 + local_date.month * 100 + local_date.day
diff --git a/iotdb-client/client-py/iotdb/utils/Field.py b/iotdb-client/client-py/iotdb/utils/Field.py
index 7b4b05eab72..da0cc42229a 100644
--- a/iotdb-client/client-py/iotdb/utils/Field.py
+++ b/iotdb-client/client-py/iotdb/utils/Field.py
@@ -18,6 +18,7 @@
 
 # for package
 from .IoTDBConstants import TSDataType
+from iotdb.tsfile.utils import DateUtils
 import numpy as np
 import pandas as pd
 
@@ -36,7 +37,10 @@ class Field(object):
         if output.get_data_type() is not None:
             if output.get_data_type() == TSDataType.BOOLEAN:
                 output.set_bool_value(field.get_bool_value())
-            elif output.get_data_type() == TSDataType.INT32:
+            elif (
+                output.get_data_type() == TSDataType.INT32
+                or output.get_data_type() == TSDataType.DATE
+            ):
                 output.set_int_value(field.get_int_value())
             elif (
                 output.get_data_type() == TSDataType.INT64
@@ -50,6 +54,7 @@ class Field(object):
             elif (
                 output.get_data_type() == TSDataType.TEXT
                 or output.get_data_type() == TSDataType.STRING
+                or output.get_data_type() == TSDataType.BLOB
             ):
                 output.set_binary_value(field.get_binary_value())
             else:
@@ -86,6 +91,7 @@ class Field(object):
             raise Exception("Null Field Exception!")
         if (
             self.__data_type != TSDataType.INT32
+            and self.__data_type != TSDataType.DATE
             or self.value is None
             or self.value is pd.NA
         ):
@@ -151,11 +157,26 @@ class Field(object):
             return None
         return self.value
 
+    def get_date_value(self):
+        if self.__data_type is None:
+            raise Exception("Null Field Exception!")
+        if (
+            self.__data_type != TSDataType.DATE
+            or self.value is None
+            or self.value is pd.NA
+        ):
+            return None
+        return DateUtils.parse_int_to_date(self.value)
+
     def get_string_value(self):
         if self.__data_type is None or self.value is None or self.value is pd.NA:
             return "None"
+        # TEXT, STRING
         elif self.__data_type == 5 or self.__data_type == 11:
             return self.value.decode("utf-8")
+        # BLOB
+        elif self.__data_type == 10:
+            return str(hex(int.from_bytes(self.value, byteorder="big")))
         else:
             return str(self.get_object_value(self.__data_type))
 
@@ -172,12 +193,15 @@ class Field(object):
             return bool(self.value)
         elif data_type == 1:
             return np.int32(self.value)
-        elif data_type == 2:
+        elif data_type == 2 or data_type == 8:
             return np.int64(self.value)
         elif data_type == 3:
             return np.float32(self.value)
         elif data_type == 4:
             return np.float64(self.value)
+        elif data_type == 9:
+            return DateUtils.parse_int_to_date(self.value)
+        # TEXT, BLOB, STRING
         return self.value
 
     @staticmethod
diff --git a/iotdb-client/client-py/iotdb/utils/IoTDBConstants.py b/iotdb-client/client-py/iotdb/utils/IoTDBConstants.py
index daae37d23ba..106df91c498 100644
--- a/iotdb-client/client-py/iotdb/utils/IoTDBConstants.py
+++ b/iotdb-client/client-py/iotdb/utils/IoTDBConstants.py
@@ -15,6 +15,7 @@
 # specific language governing permissions and limitations
 # under the License.
 #
+import datetime
 from enum import unique, IntEnum
 import numpy as np
 
@@ -39,9 +40,11 @@ class TSDataType(IntEnum):
             TSDataType.DOUBLE: np.dtype(">f8"),
             TSDataType.INT32: np.dtype(">i4"),
             TSDataType.INT64: np.dtype(">i8"),
-            TSDataType.TEXT: np.dtype("str"),
+            TSDataType.TEXT: str,
             TSDataType.TIMESTAMP: np.dtype(">i8"),
-            TSDataType.STRING: np.dtype("str"),
+            TSDataType.DATE: datetime.date,
+            TSDataType.STRING: str,
+            TSDataType.BLOB: bytes,
         }[self]
 
 
diff --git a/iotdb-client/client-py/iotdb/utils/IoTDBRpcDataSet.py b/iotdb-client/client-py/iotdb/utils/IoTDBRpcDataSet.py
index 2aa885125d8..73d4f317de6 100644
--- a/iotdb-client/client-py/iotdb/utils/IoTDBRpcDataSet.py
+++ b/iotdb-client/client-py/iotdb/utils/IoTDBRpcDataSet.py
@@ -24,6 +24,7 @@ import numpy as np
 import pandas as pd
 from thrift.transport import TTransport
 from iotdb.thrift.rpc.IClientRPCService import TSFetchResultsReq, TSCloseOperationReq
+from iotdb.tsfile.utils.DateUtils import parse_int_to_date
 from iotdb.utils.IoTDBConstants import TSDataType
 
 logger = logging.getLogger("IoTDB")
@@ -168,25 +169,31 @@ class IoTDBRpcDataSet(object):
             data_type = self.column_type_deduplicated_list[location]
             value_buffer = self.__query_data_set.valueList[location]
             value_buffer_len = len(value_buffer)
+            # DOUBLE
             if data_type == 4:
                 data_array = np.frombuffer(
                     value_buffer, np.dtype(np.double).newbyteorder(">")
                 )
+            # FLOAT
             elif data_type == 3:
                 data_array = np.frombuffer(
                     value_buffer, np.dtype(np.float32).newbyteorder(">")
                 )
+            # BOOLEAN
             elif data_type == 0:
                 data_array = np.frombuffer(value_buffer, np.dtype("?"))
-            elif data_type == 1:
+            # INT32, DATE
+            elif data_type == 1 or data_type == 9:
                 data_array = np.frombuffer(
                     value_buffer, np.dtype(np.int32).newbyteorder(">")
                 )
+            # INT64, TIMESTAMP
             elif data_type == 2 or data_type == 8:
                 data_array = np.frombuffer(
                     value_buffer, np.dtype(np.int64).newbyteorder(">")
                 )
-            elif data_type == 5 or data_type == 11:
+            # TEXT, STRING, BLOB
+            elif data_type == 5 or data_type == 11 or data_type == 10:
                 j = 0
                 offset = 0
                 data_array = []
@@ -208,10 +215,15 @@ class IoTDBRpcDataSet(object):
                 data_array = data_array.byteswap().view(
                     data_array.dtype.newbyteorder("<")
                 )
-            # self.__query_data_set.valueList[location] = None
             if len(data_array) < total_length:
-                # INT32 or INT64 or boolean
-                if data_type == 0 or data_type == 1 or data_type == 2:
+                # INT32, INT64, BOOLEAN, TIMESTAMP, DATE
+                if (
+                    data_type == 0
+                    or data_type == 1
+                    or data_type == 2
+                    or data_type == 8
+                    or data_type == 9
+                ):
                     tmp_array = np.full(total_length, np.nan, np.float32)
                 else:
                     tmp_array = np.full(total_length, None, dtype=object)
@@ -223,10 +235,13 @@ class IoTDBRpcDataSet(object):
                     bit_mask = bit_mask[:total_length]
                 tmp_array[bit_mask] = data_array
 
-                if data_type == 1:
+                # INT32, DATE
+                if data_type == 1 or data_type == 9:
                     tmp_array = pd.Series(tmp_array, dtype="Int32")
+                # INT64, TIMESTAMP
                 elif data_type == 2 or data_type == 8:
                     tmp_array = pd.Series(tmp_array, dtype="Int64")
+                # BOOLEAN
                 elif data_type == 0:
                     tmp_array = pd.Series(tmp_array, dtype="boolean")
                 data_array = tmp_array
@@ -251,7 +266,7 @@ class IoTDBRpcDataSet(object):
             return True
         return False
 
-    def resultset_to_pandas(self):
+    def result_set_to_pandas(self):
         result = {}
         for column_name in self.__column_name_list:
             result[column_name] = []
@@ -283,24 +298,30 @@ class IoTDBRpcDataSet(object):
                 data_type = self.column_type_deduplicated_list[location]
                 value_buffer = self.__query_data_set.valueList[location]
                 value_buffer_len = len(value_buffer)
+                # DOUBLE
                 if data_type == 4:
                     data_array = np.frombuffer(
                         value_buffer, np.dtype(np.double).newbyteorder(">")
                     )
+                # FLOAT
                 elif data_type == 3:
                     data_array = np.frombuffer(
                         value_buffer, np.dtype(np.float32).newbyteorder(">")
                     )
+                # BOOLEAN
                 elif data_type == 0:
                     data_array = np.frombuffer(value_buffer, np.dtype("?"))
+                # INT32
                 elif data_type == 1:
                     data_array = np.frombuffer(
                         value_buffer, np.dtype(np.int32).newbyteorder(">")
                     )
+                # INT64, TIMESTAMP
                 elif data_type == 2 or data_type == 8:
                     data_array = np.frombuffer(
                         value_buffer, np.dtype(np.int64).newbyteorder(">")
                     )
+                # TEXT, STRING
                 elif data_type == 5 or data_type == 11:
                     j = 0
                     offset = 0
@@ -317,7 +338,30 @@ class IoTDBRpcDataSet(object):
                         data_array.append(value)
                         j += 1
                         offset += length
-                    data_array = np.array(data_array, dtype=object)
+                    data_array = pd.Series(data_array).astype(str)
+                # BLOB
+                elif data_type == 10:
+                    j = 0
+                    offset = 0
+                    data_array = []
+                    while offset < value_buffer_len:
+                        length = int.from_bytes(
+                            value_buffer[offset : offset + 4],
+                            byteorder="big",
+                            signed=False,
+                        )
+                        offset += 4
+                        value = value_buffer[offset : offset + length]
+                        data_array.append(value)
+                        j += 1
+                        offset += length
+                    data_array = pd.Series(data_array)
+                # DATE
+                elif data_type == 9:
+                    data_array = np.frombuffer(
+                        value_buffer, np.dtype(np.int32).newbyteorder(">")
+                    )
+                    data_array = pd.Series(data_array).apply(parse_int_to_date)
                 else:
                     raise RuntimeError("unsupported data type {}.".format(data_type))
                 if data_array.dtype.byteorder == ">":
@@ -327,13 +371,26 @@ class IoTDBRpcDataSet(object):
                 self.__query_data_set.valueList[location] = None
                 tmp_array = []
                 if len(data_array) < total_length:
-                    if data_type == 1 or data_type == 2 or data_type == 8:
-                        tmp_array = np.full(total_length, np.nan, np.float32)
+                    # BOOLEAN, INT32, INT64, TIMESTAMP
+                    if (
+                        data_type == 0
+                        or data_type == 1
+                        or data_type == 2
+                        or data_type == 8
+                    ):
+                        tmp_array = np.full(total_length, np.nan, dtype=np.float32)
+                    # FLOAT, DOUBLE
                     elif data_type == 3 or data_type == 4:
-                        tmp_array = np.full(total_length, np.nan, data_array.dtype)
-                    elif data_type == 0:
-                        tmp_array = np.full(total_length, np.nan, np.float32)
-                    elif data_type == 5 or data_type == 11 or data_type == 10:
+                        tmp_array = np.full(
+                            total_length, np.nan, dtype=data_array.dtype
+                        )
+                    # TEXT, STRING, BLOB, DATE
+                    elif (
+                        data_type == 5
+                        or data_type == 11
+                        or data_type == 10
+                        or data_type == 9
+                    ):
                         tmp_array = np.full(total_length, None, dtype=data_array.dtype)
 
                     bitmap_buffer = self.__query_data_set.bitmapList[location]
diff --git a/iotdb-client/client-py/iotdb/utils/NumpyTablet.py b/iotdb-client/client-py/iotdb/utils/NumpyTablet.py
index f00b61de519..4ce623c9db9 100644
--- a/iotdb-client/client-py/iotdb/utils/NumpyTablet.py
+++ b/iotdb-client/client-py/iotdb/utils/NumpyTablet.py
@@ -18,8 +18,11 @@
 
 import struct
 
+import numpy as np
 from numpy import ndarray
 from typing import List
+
+from iotdb.tsfile.utils.DateUtils import parse_date_to_int
 from iotdb.utils.IoTDBConstants import TSDataType
 from iotdb.utils.BitMap import BitMap
 from iotdb.utils.Tablet import ColumnType
@@ -49,7 +52,7 @@ class NumpyTablet(object):
                      2,  id:1,  attr:1,   2.0
                      3,  id:2,  attr:2,   3.0
         Notice: The tablet will be sorted at the initialization by timestamps
-        :param insert_target_name: Str, DeviceId if using tree-view interfaces or TableName when using table-view interfaces.
+        :param insert_target_name: Str, DeviceId if using tree model or TableName when using table model.
         :param column_names: Str List, names of columns
         :param data_types: TSDataType List, specify value types for columns
         :param values: ndarray List, one ndarray contains the value of one column
@@ -128,12 +131,22 @@ class NumpyTablet(object):
         bs_len = 0
         bs_list = []
         for data_type, value in zip(self.__data_types, self.__values):
+            # BOOLEAN, INT32, INT64, FLOAT, DOUBLE, TIMESTAMP
+            if (
+                data_type == 0
+                or data_type == 1
+                or data_type == 2
+                or data_type == 3
+                or data_type == 4
+                or data_type == 8
+            ):
+                bs = value.tobytes()
             # TEXT, STRING, BLOB
-            if data_type == 5 or data_type == 11 or data_type == 10:
+            elif data_type == 5 or data_type == 11 or data_type == 10:
                 format_str_list = [">"]
                 values_tobe_packed = []
                 for str_list in value:
-                    # Fot TEXT, it's same as the original solution
+                    # For TEXT, it's same as the original solution
                     if isinstance(str_list, str):
                         value_bytes = bytes(str_list, "utf-8")
                     else:
@@ -145,11 +158,18 @@ class NumpyTablet(object):
                     values_tobe_packed.append(value_bytes)
                 format_str = "".join(format_str_list)
                 bs = struct.pack(format_str, *values_tobe_packed)
-            # Non-TEXT
+            # DATE
+            elif data_type == 9:
+                bs = (
+                    np.vectorize(parse_date_to_int)(value)
+                    .astype(np.dtype(">i4"))
+                    .tobytes()
+                )
             else:
-                bs = value.tobytes()
+                raise RuntimeError("Unsupported data type:" + str(data_type))
             bs_list.append(bs)
             bs_len += len(bs)
+
         if self.bitmaps is not None:
             format_str_list = [">"]
             values_tobe_packed = []
diff --git a/iotdb-client/client-py/iotdb/utils/SessionDataSet.py b/iotdb-client/client-py/iotdb/utils/SessionDataSet.py
index c69aca3ebbe..f4d63035efc 100644
--- a/iotdb-client/client-py/iotdb/utils/SessionDataSet.py
+++ b/iotdb-client/client-py/iotdb/utils/SessionDataSet.py
@@ -125,30 +125,32 @@ class SessionDataSet(object):
         self.iotdb_rpc_data_set.close()
 
     def todf(self) -> pd.DataFrame:
-        return resultset_to_pandas(self)
+        return result_set_to_pandas(self)
 
 
-def resultset_to_pandas(result_set: SessionDataSet) -> pd.DataFrame:
+def result_set_to_pandas(result_set: SessionDataSet) -> pd.DataFrame:
     """
     Transforms a SessionDataSet from IoTDB to a Pandas Data Frame
     Each Field from IoTDB is a column in Pandas
     :param result_set:
     :return:
     """
-    return result_set.iotdb_rpc_data_set.resultset_to_pandas()
+    return result_set.iotdb_rpc_data_set.result_set_to_pandas()
 
 
 def get_typed_point(field: Field, none_value=None):
     choices = {
         # In Case of Boolean, cast to 0 / 1
-        TSDataType.BOOLEAN: lambda field: 1 if field.get_bool_value() else 0,
-        TSDataType.TEXT: lambda field: field.get_string_value(),
-        TSDataType.FLOAT: lambda field: field.get_float_value(),
-        TSDataType.INT32: lambda field: field.get_int_value(),
-        TSDataType.DOUBLE: lambda field: field.get_double_value(),
-        TSDataType.INT64: lambda field: field.get_long_value(),
-        TSDataType.TIMESTAMP: lambda field: field.get_long_value(),
-        TSDataType.STRING: lambda field: field.get_string_value(),
+        TSDataType.BOOLEAN: lambda f: 1 if f.get_bool_value() else 0,
+        TSDataType.TEXT: lambda f: f.get_string_value(),
+        TSDataType.FLOAT: lambda f: f.get_float_value(),
+        TSDataType.INT32: lambda f: f.get_int_value(),
+        TSDataType.DOUBLE: lambda f: f.get_double_value(),
+        TSDataType.INT64: lambda f: f.get_long_value(),
+        TSDataType.TIMESTAMP: lambda f: f.get_long_value(),
+        TSDataType.STRING: lambda f: f.get_string_value(),
+        TSDataType.DATE: lambda f: f.get_date_value(),
+        TSDataType.BLOB: lambda f: f.get_binary_value(),
     }
 
     result_next_type: TSDataType = field.get_data_type()
diff --git a/iotdb-client/client-py/iotdb/utils/Tablet.py b/iotdb-client/client-py/iotdb/utils/Tablet.py
index 0f086530347..cbb6bc712d1 100644
--- a/iotdb-client/client-py/iotdb/utils/Tablet.py
+++ b/iotdb-client/client-py/iotdb/utils/Tablet.py
@@ -18,7 +18,9 @@
 
 import struct
 from enum import unique, IntEnum
-from typing import List
+from typing import List, Union
+
+from iotdb.tsfile.utils.DateUtils import parse_date_to_int
 from iotdb.utils.BitMap import BitMap
 from iotdb.utils.IoTDBConstants import TSDataType
 
@@ -59,7 +61,7 @@ class Tablet(object):
                      2,  id:1,  attr:1,   2.0
                      3,  id:2,  attr:2,   3.0
         Notice: The tablet will be sorted at the initialization by timestamps
-        :param insert_target_name: Str, DeviceId if using tree-view interfaces or TableName when using table-view interfaces.
+        :param insert_target_name: Str, DeviceId if using tree model or TableName when using table model.
         :param column_names: Str List, names of columns
         :param data_types: TSDataType List, specify value types for columns
         :param values: 2-D List, the values of each row should be the outer list element
@@ -126,13 +128,14 @@ class Tablet(object):
     def get_binary_values(self):
         format_str_list = [">"]
         values_tobe_packed = []
-        bitmaps = []
+        bitmaps: List[Union[BitMap, None]] = []
         has_none = False
         for i in range(self.__column_number):
             bitmap = None
             bitmaps.append(bitmap)
-            data_type_value = self.__data_types[i]
-            if data_type_value == 0:
+            data_type = self.__data_types[i]
+            # BOOLEAN
+            if data_type == 0:
                 format_str_list.append(str(self.__row_number))
                 format_str_list.append("?")
                 for j in range(self.__row_number):
@@ -142,8 +145,8 @@ class Tablet(object):
                         values_tobe_packed.append(False)
                         self.__mark_none_value(bitmaps, i, j)
                         has_none = True
-
-            elif data_type_value == 1:
+            # INT32
+            elif data_type == 1:
                 format_str_list.append(str(self.__row_number))
                 format_str_list.append("i")
                 for j in range(self.__row_number):
@@ -153,8 +156,8 @@ class Tablet(object):
                         values_tobe_packed.append(0)
                         self.__mark_none_value(bitmaps, i, j)
                         has_none = True
-
-            elif data_type_value == 2:
+            # INT64 or TIMESTAMP
+            elif data_type == 2 or data_type == 8:
                 format_str_list.append(str(self.__row_number))
                 format_str_list.append("q")
                 for j in range(self.__row_number):
@@ -164,8 +167,8 @@ class Tablet(object):
                         values_tobe_packed.append(0)
                         self.__mark_none_value(bitmaps, i, j)
                         has_none = True
-
-            elif data_type_value == 3:
+            # FLOAT
+            elif data_type == 3:
                 format_str_list.append(str(self.__row_number))
                 format_str_list.append("f")
                 for j in range(self.__row_number):
@@ -175,8 +178,8 @@ class Tablet(object):
                         values_tobe_packed.append(0)
                         self.__mark_none_value(bitmaps, i, j)
                         has_none = True
-
-            elif data_type_value == 4:
+            # DOUBLE
+            elif data_type == 4:
                 format_str_list.append(str(self.__row_number))
                 format_str_list.append("d")
                 for j in range(self.__row_number):
@@ -186,8 +189,8 @@ class Tablet(object):
                         values_tobe_packed.append(0)
                         self.__mark_none_value(bitmaps, i, j)
                         has_none = True
-
-            elif data_type_value == 5 or data_type_value == 11:
+            # TEXT, STRING, BLOB
+            elif data_type == 5 or data_type == 11 or data_type == 10:
                 for j in range(self.__row_number):
                     if self.__values[j][i] is not None:
                         if isinstance(self.__values[j][i], str):
@@ -209,6 +212,18 @@ class Tablet(object):
                         self.__mark_none_value(bitmaps, i, j)
                         has_none = True
 
+            elif data_type == 9:
+                format_str_list.append(str(self.__row_number))
+                format_str_list.append("i")
+                for j in range(self.__row_number):
+                    if self.__values[j][i] is not None:
+                        values_tobe_packed.append(
+                            parse_date_to_int(self.__values[j][i])
+                        )
+                    else:
+                        values_tobe_packed.append(0)
+                        self.__mark_none_value(bitmaps, i, j)
+                        has_none = True
             else:
                 raise RuntimeError("Unsupported data type:" + str(self.__data_types[i]))