This is an automated email from the ASF dual-hosted git repository.
jiangtian 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 72175750334 [Py-Client] support new data types (#13494)
72175750334 is described below
commit 721757503349a991466231d0b8886e6c92c1a33a
Author: Haonan <[email protected]>
AuthorDate: Fri Sep 13 10:08:42 2024 +0800
[Py-Client] support new data types (#13494)
* [Py-Client] support new data types
* add test
* recover useless change
* more change
---
iotdb-client/client-py/SessionExample.py | 53 ++++++-
iotdb-client/client-py/iotdb/Session.py | 33 ++++-
.../client-py/iotdb/tsfile/utils/DateUtils.py | 41 ++++++
iotdb-client/client-py/iotdb/utils/Field.py | 34 ++++-
.../client-py/iotdb/utils/IoTDBConstants.py | 7 +-
.../client-py/iotdb/utils/IoTDBRpcDataSet.py | 85 +++++++++--
iotdb-client/client-py/iotdb/utils/NumpyTablet.py | 30 +++-
iotdb-client/client-py/iotdb/utils/RowRecord.py | 8 +-
.../client-py/iotdb/utils/SessionDataSet.py | 24 ++--
iotdb-client/client-py/iotdb/utils/Tablet.py | 47 +++---
.../tests/integration/test_new_data_types.py | 157 +++++++++++++++++++++
11 files changed, 459 insertions(+), 60 deletions(-)
diff --git a/iotdb-client/client-py/SessionExample.py
b/iotdb-client/client-py/SessionExample.py
index c489fe7d03d..ca610de9a0c 100644
--- a/iotdb-client/client-py/SessionExample.py
+++ b/iotdb-client/client-py/SessionExample.py
@@ -18,7 +18,7 @@
# Uncomment the following line to use apache-iotdb module installed by pip3
import numpy as np
-
+from datetime import date
from iotdb.Session import Session
from iotdb.utils.BitMap import BitMap
from iotdb.utils.IoTDBConstants import TSDataType, TSEncoding, Compressor
@@ -360,6 +360,57 @@ with session.execute_last_data_query(
while session_data_set.has_next():
print(session_data_set.next())
+# insert tablet with new data types
+measurements_new_type = ["s_01", "s_02", "s_03", "s_04"]
+data_types_new_type = [
+ TSDataType.DATE,
+ TSDataType.TIMESTAMP,
+ TSDataType.BLOB,
+ TSDataType.STRING,
+]
+values_new_type = [
+ [date(2024, 1, 1), 1, b"\x12\x34", "test01"],
+ [date(2024, 1, 2), 2, b"\x12\x34", "test02"],
+ [date(2024, 1, 3), 3, b"\x12\x34", "test03"],
+ [date(2024, 1, 4), 4, b"\x12\x34", "test04"],
+]
+timestamps_new_type = [1, 2, 3, 4]
+tablet_new_type = Tablet(
+ "root.sg_test_01.d_04",
+ measurements_new_type,
+ data_types_new_type,
+ values_new_type,
+ timestamps_new_type,
+)
+session.insert_tablet(tablet_new_type)
+np_values_new_type = [
+ np.array([date(2024, 2, 4), date(2024, 3, 4), date(2024, 4, 4), date(2024,
5, 4)]),
+ np.array([5, 6, 7, 8], TSDataType.INT64.np_dtype()),
+ np.array([b"\x12\x34", b"\x12\x34", b"\x12\x34", b"\x12\x34"]),
+ np.array(["test01", "test02", "test03", "test04"]),
+]
+np_timestamps_new_type = np.array([5, 6, 7, 8], TSDataType.INT64.np_dtype())
+np_tablet_new_type = NumpyTablet(
+ "root.sg_test_01.d_04",
+ measurements_new_type,
+ data_types_new_type,
+ np_values_new_type,
+ np_timestamps_new_type,
+)
+session.insert_tablet(np_tablet_new_type)
+with session.execute_query_statement(
+ "select s_01,s_02,s_03,s_04 from root.sg_test_01.d_04"
+) as dataset:
+ print(dataset.get_column_names())
+ while dataset.has_next():
+ print(dataset.next())
+
+with session.execute_query_statement(
+ "select s_01,s_02,s_03,s_04 from root.sg_test_01.d_04"
+) as dataset:
+ df = dataset.todf()
+ print(df.to_string())
+
# delete database
session.delete_storage_group("root.sg_test_01")
diff --git a/iotdb-client/client-py/iotdb/Session.py
b/iotdb-client/client-py/iotdb/Session.py
index 098faf0d520..12545e6f7a2 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")
@@ -118,7 +119,7 @@ class Session(object):
fetch_size=DEFAULT_FETCH_SIZE,
zone_id=DEFAULT_ZONE_ID,
enable_redirection=True,
- sql_dialect=None,
+ sql_dialect=SQL_DIALECT,
database=None,
):
if node_urls is None:
@@ -1520,6 +1521,36 @@ class Session(object):
values_tobe_packed.append(b"\x05")
values_tobe_packed.append(len(value_bytes))
values_tobe_packed.append(value_bytes)
+ # TIMESTAMP
+ elif data_type == 8:
+ format_str_list.append("cq")
+ values_tobe_packed.append(b"\x08")
+ values_tobe_packed.append(value)
+ # DATE
+ elif data_type == 9:
+ format_str_list.append("ci")
+ values_tobe_packed.append(b"\x09")
+ values_tobe_packed.append(parse_date_to_int(value))
+ # BLOB
+ elif data_type == 10:
+ format_str_list.append("ci")
+ format_str_list.append(str(len(value)))
+ format_str_list.append("s")
+ values_tobe_packed.append(b"\x0a")
+ values_tobe_packed.append(len(value))
+ values_tobe_packed.append(value)
+ # STRING
+ elif data_type == 11:
+ if isinstance(value, str):
+ value_bytes = bytes(value, "utf-8")
+ else:
+ value_bytes = value
+ format_str_list.append("ci")
+ format_str_list.append(str(len(value_bytes)))
+ format_str_list.append("s")
+ values_tobe_packed.append(b"\x0b")
+ values_tobe_packed.append(len(value_bytes))
+ values_tobe_packed.append(value_bytes)
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..fdc1396c8fb 100644
--- a/iotdb-client/client-py/iotdb/utils/Field.py
+++ b/iotdb-client/client-py/iotdb/utils/Field.py
@@ -17,7 +17,8 @@
#
# for package
-from .IoTDBConstants import TSDataType
+from iotdb.utils.IoTDBConstants import TSDataType
+from iotdb.tsfile.utils.DateUtils import parse_int_to_date
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 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,13 +193,18 @@ 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)
- return self.value
+ elif data_type == 9:
+ return parse_int_to_date(self.value)
+ elif data_type == 5 or data_type == 10 or data_type == 11:
+ return self.value
+ else:
+ raise RuntimeError("Unsupported data type:" + str(data_type))
@staticmethod
def get_field(value, data_type):
diff --git a/iotdb-client/client-py/iotdb/utils/IoTDBConstants.py
b/iotdb-client/client-py/iotdb/utils/IoTDBConstants.py
index daae37d23ba..4b9082b5353 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.
#
+from datetime import date
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: date,
+ TSDataType.BLOB: bytes,
+ TSDataType.STRING: str,
}[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/RowRecord.py
b/iotdb-client/client-py/iotdb/utils/RowRecord.py
index 16a88f1edf9..91bcebf948b 100644
--- a/iotdb-client/client-py/iotdb/utils/RowRecord.py
+++ b/iotdb-client/client-py/iotdb/utils/RowRecord.py
@@ -17,15 +17,11 @@
#
# for package
-from .Field import Field
-
-# for debug
-# from IoTDBConstants import TSDataType
-# from Field import Field
+from iotdb.utils.Field import Field
class RowRecord(object):
- def __init__(self, timestamp, field_list=None):
+ def __init__(self, timestamp, field_list: list = None):
self.__timestamp = timestamp
self.__field_list = field_list
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..fbae5fe2293 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):
@@ -208,7 +211,19 @@ class Tablet(object):
values_tobe_packed.append(value_bytes)
self.__mark_none_value(bitmaps, i, j)
has_none = True
-
+ # DATE
+ 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]))
diff --git a/iotdb-client/client-py/tests/integration/test_new_data_types.py
b/iotdb-client/client-py/tests/integration/test_new_data_types.py
new file mode 100644
index 00000000000..3452d6c1b7b
--- /dev/null
+++ b/iotdb-client/client-py/tests/integration/test_new_data_types.py
@@ -0,0 +1,157 @@
+# 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
+
+import numpy as np
+
+from iotdb.Session import Session
+from iotdb.SessionPool import PoolConfig, create_session_pool
+from iotdb.utils.IoTDBConstants import TSDataType
+from iotdb.utils.NumpyTablet import NumpyTablet
+from iotdb.utils.Tablet import Tablet
+from iotdb.IoTDBContainer import IoTDBContainer
+
+
+def test_session():
+ session_test()
+
+
+def test_session_pool():
+ session_test(True)
+
+
+def session_test(use_session_pool=False):
+ with IoTDBContainer("iotdb:dev") as db:
+ db: IoTDBContainer
+
+ if use_session_pool:
+ pool_config = PoolConfig(
+ db.get_container_host_ip(),
+ db.get_exposed_port(6667),
+ "root",
+ "root",
+ None,
+ 1024,
+ "Asia/Shanghai",
+ 3,
+ )
+ session_pool = create_session_pool(pool_config, 1, 3000)
+ session = session_pool.get_session()
+ else:
+ session = Session(db.get_container_host_ip(),
db.get_exposed_port(6667))
+ session.open(False)
+
+ if not session.is_open():
+ print("can't open session")
+ exit(1)
+
+ device_id = "root.sg_test_01.d_04"
+ measurements_new_type = ["s_01", "s_02", "s_03", "s_04"]
+ data_types_new_type = [
+ TSDataType.DATE,
+ TSDataType.TIMESTAMP,
+ TSDataType.BLOB,
+ TSDataType.STRING,
+ ]
+ values_new_type = [
+ [date(2024, 1, 1), 1, b"\x12\x34", "test01"],
+ [date(2024, 1, 2), 2, b"\x12\x34", "test02"],
+ [date(2024, 1, 3), 3, b"\x12\x34", "test03"],
+ [date(2024, 1, 4), 4, b"\x12\x34", "test04"],
+ ]
+ timestamps_new_type = [1, 2, 3, 4]
+ tablet_new_type = Tablet(
+ device_id,
+ measurements_new_type,
+ data_types_new_type,
+ values_new_type,
+ timestamps_new_type,
+ )
+ session.insert_tablet(tablet_new_type)
+ np_values_new_type = [
+ np.array(
+ [date(2024, 1, 5), date(2024, 1, 6), date(2024, 1, 7),
date(2024, 1, 8)]
+ ),
+ np.array([5, 6, 7, 8], TSDataType.INT64.np_dtype()),
+ np.array([b"\x12\x34", b"\x12\x34", b"\x12\x34", b"\x12\x34"]),
+ np.array(["test05", "test06", "test07", "test08"]),
+ ]
+ np_timestamps_new_type = np.array([5, 6, 7, 8],
TSDataType.INT64.np_dtype())
+ np_tablet_new_type = NumpyTablet(
+ device_id,
+ measurements_new_type,
+ data_types_new_type,
+ np_values_new_type,
+ np_timestamps_new_type,
+ )
+ session.insert_tablet(np_tablet_new_type)
+ session.insert_records(
+ [device_id, device_id],
+ [9, 10],
+ [measurements_new_type, measurements_new_type],
+ [data_types_new_type, data_types_new_type],
+ [
+ [date(2024, 1, 9), 9, b"\x12\x34", "test09"],
+ [date(2024, 1, 10), 10, b"\x12\x34", "test010"],
+ ],
+ )
+
+ with session.execute_query_statement(
+ "select s_01,s_02,s_03,s_04 from root.sg_test_01.d_04"
+ ) as dataset:
+ print(dataset.get_column_names())
+ while dataset.has_next():
+ print(dataset.next())
+
+ with session.execute_query_statement(
+ "select s_01,s_02,s_03,s_04 from root.sg_test_01.d_04"
+ ) as dataset:
+ df = dataset.todf()
+ print(df.to_string())
+
+ with session.execute_query_statement(
+ "select s_01,s_02,s_03,s_04 from root.sg_test_01.d_04"
+ ) as dataset:
+ cnt = 0
+ while dataset.has_next():
+ row_record = dataset.next()
+ timestamp = row_record.get_timestamp()
+ assert row_record.get_fields()[0].get_date_value() == date(
+ 2024, 1, timestamp
+ )
+ assert (
+
row_record.get_fields()[1].get_object_value(TSDataType.TIMESTAMP)
+ == timestamp
+ )
+ assert row_record.get_fields()[2].get_binary_value() ==
b"\x12\x34"
+ assert row_record.get_fields()[3].get_string_value() ==
"test0" + str(
+ timestamp
+ )
+ cnt += 1
+ assert cnt == 10
+
+ with session.execute_query_statement(
+ "select s_01,s_02,s_03,s_04 from root.sg_test_01.d_04"
+ ) as dataset:
+ df = dataset.todf()
+ rows, columns = df.shape
+ assert rows == 10
+ assert columns == 5
+
+ # close session connection.
+ session.close()