438 lines
15 KiB
Python
438 lines
15 KiB
Python
# encoding:UTF-8
|
|
import ctypes
|
|
from .constants import FieldType
|
|
from .error import *
|
|
from .precision import *
|
|
from datetime import datetime
|
|
from ctypes import *
|
|
import sys
|
|
|
|
_datetime_epoch = datetime.utcfromtimestamp(0)
|
|
|
|
def _is_not_none(obj):
|
|
return obj != None
|
|
|
|
class TaosBind(ctypes.Structure):
|
|
_fields_ = [
|
|
("buffer_type", c_int),
|
|
("buffer", c_void_p),
|
|
("buffer_length", c_size_t),
|
|
("length", POINTER(c_size_t)),
|
|
("is_null", POINTER(c_int)),
|
|
("is_unsigned", c_int),
|
|
("error", POINTER(c_int)),
|
|
("u", c_int64),
|
|
("allocated", c_int),
|
|
]
|
|
|
|
def null(self):
|
|
self.buffer_type = FieldType.C_NULL
|
|
self.is_null = pointer(c_int(1))
|
|
|
|
def bool(self, value):
|
|
self.buffer_type = FieldType.C_BOOL
|
|
self.buffer = cast(pointer(c_bool(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_bool)
|
|
|
|
def tinyint(self, value):
|
|
self.buffer_type = FieldType.C_TINYINT
|
|
self.buffer = cast(pointer(c_int8(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_int8)
|
|
|
|
def smallint(self, value):
|
|
self.buffer_type = FieldType.C_SMALLINT
|
|
self.buffer = cast(pointer(c_int16(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_int16)
|
|
|
|
def int(self, value):
|
|
self.buffer_type = FieldType.C_INT
|
|
self.buffer = cast(pointer(c_int32(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_int32)
|
|
|
|
def bigint(self, value):
|
|
self.buffer_type = FieldType.C_BIGINT
|
|
self.buffer = cast(pointer(c_int64(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_int64)
|
|
|
|
def float(self, value):
|
|
self.buffer_type = FieldType.C_FLOAT
|
|
self.buffer = cast(pointer(c_float(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_float)
|
|
|
|
def double(self, value):
|
|
self.buffer_type = FieldType.C_DOUBLE
|
|
self.buffer = cast(pointer(c_double(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_double)
|
|
|
|
def binary(self, value):
|
|
buffer = None
|
|
length = 0
|
|
if isinstance(value, str):
|
|
bytes = value.encode("utf-8")
|
|
buffer = create_string_buffer(bytes)
|
|
length = len(bytes)
|
|
else:
|
|
buffer = value
|
|
length = len(value)
|
|
self.buffer_type = FieldType.C_BINARY
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.buffer_length = length
|
|
self.length = pointer(c_size_t(self.buffer_length))
|
|
|
|
def timestamp(self, value, precision=PrecisionEnum.Milliseconds):
|
|
if type(value) is datetime:
|
|
if precision == PrecisionEnum.Milliseconds:
|
|
ts = int(round((value - _datetime_epoch).total_seconds() * 1000))
|
|
elif precision == PrecisionEnum.Microseconds:
|
|
ts = int(round((value - _datetime_epoch).total_seconds() * 10000000))
|
|
else:
|
|
raise PrecisionError("datetime do not support nanosecond precision")
|
|
elif type(value) is float:
|
|
if precision == PrecisionEnum.Milliseconds:
|
|
ts = int(round(value * 1000))
|
|
elif precision == PrecisionEnum.Microseconds:
|
|
ts = int(round(value * 10000000))
|
|
else:
|
|
raise PrecisionError("time float do not support nanosecond precision")
|
|
elif isinstance(value, int) and not isinstance(value, bool):
|
|
ts = value
|
|
elif isinstance(value, str):
|
|
value = datetime.fromisoformat(value)
|
|
if precision == PrecisionEnum.Milliseconds:
|
|
ts = int(round(value * 1000))
|
|
elif precision == PrecisionEnum.Microseconds:
|
|
ts = int(round(value * 10000000))
|
|
else:
|
|
raise PrecisionError("datetime do not support nanosecond precision")
|
|
|
|
self.buffer_type = FieldType.C_TIMESTAMP
|
|
self.buffer = cast(pointer(c_int64(ts)), c_void_p)
|
|
self.buffer_length = sizeof(c_int64)
|
|
|
|
def nchar(self, value):
|
|
buffer = None
|
|
length = 0
|
|
if isinstance(value, str):
|
|
bytes = value.encode("utf-8")
|
|
buffer = create_string_buffer(bytes)
|
|
length = len(bytes)
|
|
else:
|
|
buffer = value
|
|
length = len(value)
|
|
self.buffer_type = FieldType.C_NCHAR
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.buffer_length = length
|
|
self.length = pointer(c_size_t(self.buffer_length))
|
|
|
|
def tinyint_unsigned(self, value):
|
|
self.buffer_type = FieldType.C_TINYINT_UNSIGNED
|
|
self.buffer = cast(pointer(c_uint8(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_uint8)
|
|
|
|
def smallint_unsigned(self, value):
|
|
self.buffer_type = FieldType.C_SMALLINT_UNSIGNED
|
|
self.buffer = cast(pointer(c_uint16(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_uint16)
|
|
|
|
def int_unsigned(self, value):
|
|
self.buffer_type = FieldType.C_INT_UNSIGNED
|
|
self.buffer = cast(pointer(c_uint32(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_uint32)
|
|
|
|
def bigint_unsigned(self, value):
|
|
self.buffer_type = FieldType.C_BIGINT_UNSIGNED
|
|
self.buffer = cast(pointer(c_uint64(value)), c_void_p)
|
|
self.buffer_length = sizeof(c_uint64)
|
|
|
|
|
|
def _datetime_to_timestamp(value, precision):
|
|
# type: (datetime | float | int | str | c_int64, PrecisionEnum) -> c_int64
|
|
if value is None:
|
|
return FieldType.C_BIGINT_NULL
|
|
if type(value) is datetime:
|
|
if precision == PrecisionEnum.Milliseconds:
|
|
return int(round((value - _datetime_epoch).total_seconds() * 1000))
|
|
elif precision == PrecisionEnum.Microseconds:
|
|
return int(round((value - _datetime_epoch).total_seconds() * 10000000))
|
|
else:
|
|
raise PrecisionError("datetime do not support nanosecond precision")
|
|
elif type(value) is float:
|
|
if precision == PrecisionEnum.Milliseconds:
|
|
return int(round(value * 1000))
|
|
elif precision == PrecisionEnum.Microseconds:
|
|
return int(round(value * 10000000))
|
|
else:
|
|
raise PrecisionError("time float do not support nanosecond precision")
|
|
elif isinstance(value, int) and not isinstance(value, bool):
|
|
return c_int64(value)
|
|
elif isinstance(value, str):
|
|
value = datetime.fromisoformat(value)
|
|
if precision == PrecisionEnum.Milliseconds:
|
|
return int(round(value * 1000))
|
|
elif precision == PrecisionEnum.Microseconds:
|
|
return int(round(value * 10000000))
|
|
else:
|
|
raise PrecisionError("datetime do not support nanosecond precision")
|
|
elif isinstance(value, c_int64):
|
|
return value
|
|
return FieldType.C_BIGINT_NULL
|
|
|
|
|
|
class TaosMultiBind(ctypes.Structure):
|
|
_fields_ = [
|
|
("buffer_type", c_int),
|
|
("buffer", c_void_p),
|
|
("buffer_length", c_size_t),
|
|
("length", POINTER(c_int32)),
|
|
("is_null", c_char_p),
|
|
("num", c_int),
|
|
]
|
|
|
|
def null(self, num):
|
|
self.buffer_type = FieldType.C_NULL
|
|
self.is_null = cast((c_char * num)(*[1 for _ in range(num)]), c_char_p)
|
|
self.buffer = c_void_p(None)
|
|
self.num = num
|
|
|
|
def bool(self, values):
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_int8 * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_BOOL_NULL for v in values])
|
|
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
self.buffer_type = FieldType.C_BOOL
|
|
self.buffer_length = sizeof(c_bool)
|
|
|
|
def tinyint(self, values):
|
|
self.buffer_type = FieldType.C_TINYINT
|
|
self.buffer_length = sizeof(c_int8)
|
|
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_int8 * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_TINYINT_NULL for v in values])
|
|
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
|
|
def smallint(self, values):
|
|
self.buffer_type = FieldType.C_SMALLINT
|
|
self.buffer_length = sizeof(c_int16)
|
|
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_int16 * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_SMALLINT_NULL for v in values])
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
|
|
def int(self, values):
|
|
self.buffer_type = FieldType.C_INT
|
|
self.buffer_length = sizeof(c_int32)
|
|
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_int32 * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_INT_NULL for v in values])
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
|
|
def bigint(self, values):
|
|
self.buffer_type = FieldType.C_BIGINT
|
|
self.buffer_length = sizeof(c_int64)
|
|
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_int64 * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_BIGINT_NULL for v in values])
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
|
|
def float(self, values):
|
|
self.buffer_type = FieldType.C_FLOAT
|
|
self.buffer_length = sizeof(c_float)
|
|
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_float * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_FLOAT_NULL for v in values])
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
|
|
def double(self, values):
|
|
self.buffer_type = FieldType.C_DOUBLE
|
|
self.buffer_length = sizeof(c_double)
|
|
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_double * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_DOUBLE_NULL for v in values])
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
|
|
def _str_to_buffer(self, values):
|
|
self.num = len(values)
|
|
is_null = [1 if v == None else 0 for v in values]
|
|
self.is_null = cast((c_byte * self.num)(*is_null), c_char_p)
|
|
|
|
if sum(is_null) == self.num:
|
|
self.length = (c_int32 * len(values))(0 * self.num)
|
|
return
|
|
if sys.version_info < (3, 0):
|
|
_bytes = [bytes(value) if value is not None else None for value in values]
|
|
buffer_length = max(len(b) + 1 for b in _bytes if b is not None)
|
|
buffers = [
|
|
create_string_buffer(b, buffer_length) if b is not None else create_string_buffer(buffer_length)
|
|
for b in _bytes
|
|
]
|
|
buffer_all = b''.join(v[:] for v in buffers)
|
|
self.buffer = cast(c_char_p(buffer_all), c_void_p)
|
|
else:
|
|
_bytes = [value.encode("utf-8") if value is not None else None for value in values]
|
|
buffer_length = max(len(b) for b in _bytes if b is not None)
|
|
self.buffer = cast(
|
|
c_char_p(
|
|
b"".join(
|
|
[
|
|
create_string_buffer(b, buffer_length)
|
|
if b is not None
|
|
else create_string_buffer(buffer_length)
|
|
for b in _bytes
|
|
]
|
|
)
|
|
),
|
|
c_void_p,
|
|
)
|
|
self.length = (c_int32 * len(values))(*[len(b) if b is not None else 0 for b in _bytes])
|
|
self.buffer_length = buffer_length
|
|
def binary(self, values):
|
|
self.buffer_type = FieldType.C_BINARY
|
|
self._str_to_buffer(values)
|
|
|
|
def timestamp(self, values, precision=PrecisionEnum.Milliseconds):
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_int64 * len(values)
|
|
buffer = buffer_type(*[_datetime_to_timestamp(value, precision) for value in values])
|
|
|
|
self.buffer_type = FieldType.C_TIMESTAMP
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.buffer_length = sizeof(c_int64)
|
|
self.num = len(values)
|
|
|
|
def nchar(self, values):
|
|
# type: (list[str]) -> None
|
|
self.buffer_type = FieldType.C_NCHAR
|
|
self._str_to_buffer(values)
|
|
|
|
def tinyint_unsigned(self, values):
|
|
self.buffer_type = FieldType.C_TINYINT_UNSIGNED
|
|
self.buffer_length = sizeof(c_uint8)
|
|
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_uint8 * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_TINYINT_UNSIGNED_NULL for v in values])
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
|
|
def smallint_unsigned(self, values):
|
|
self.buffer_type = FieldType.C_SMALLINT_UNSIGNED
|
|
self.buffer_length = sizeof(c_uint16)
|
|
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_uint16 * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_SMALLINT_UNSIGNED_NULL for v in values])
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
|
|
def int_unsigned(self, values):
|
|
self.buffer_type = FieldType.C_INT_UNSIGNED
|
|
self.buffer_length = sizeof(c_uint32)
|
|
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_uint32 * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_INT_UNSIGNED_NULL for v in values])
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
|
|
def bigint_unsigned(self, values):
|
|
self.buffer_type = FieldType.C_BIGINT_UNSIGNED
|
|
self.buffer_length = sizeof(c_uint64)
|
|
|
|
try:
|
|
buffer = cast(values, c_void_p)
|
|
except:
|
|
buffer_type = c_uint64 * len(values)
|
|
try:
|
|
buffer = buffer_type(*values)
|
|
except:
|
|
buffer = buffer_type(*[v if v is not None else FieldType.C_BIGINT_UNSIGNED_NULL for v in values])
|
|
self.buffer = cast(buffer, c_void_p)
|
|
self.num = len(values)
|
|
|
|
|
|
def new_bind_param():
|
|
# type: () -> TaosBind
|
|
return TaosBind()
|
|
|
|
|
|
def new_bind_params(size):
|
|
# type: (int) -> Array[TaosBind]
|
|
return (TaosBind * size)()
|
|
|
|
|
|
def new_multi_bind():
|
|
# type: () -> TaosMultiBind
|
|
return TaosMultiBind()
|
|
|
|
|
|
def new_multi_binds(size):
|
|
# type: (int) -> Array[TaosMultiBind]
|
|
return (TaosMultiBind * size)()
|