IGNITE-9950 Python: Fixes for Decimal data type
This closes #5041
diff --git a/pyignite/datatypes/standard.py b/pyignite/datatypes/standard.py
index 6109c7a..5f3af74 100644
--- a/pyignite/datatypes/standard.py
+++ b/pyignite/datatypes/standard.py
@@ -16,6 +16,7 @@
import ctypes
from datetime import date, datetime, time, timedelta
import decimal
+from math import ceil
import uuid
from pyignite.constants import *
@@ -163,7 +164,7 @@
{
'_pack_': 1,
'_fields_': [
- ('data', ctypes.c_char * header.length),
+ ('data', ctypes.c_ubyte * header.length),
],
}
)
@@ -179,12 +180,18 @@
return None
sign = 1 if ctype_object.data[0] & 0x80 else 0
- data = bytes([ctype_object.data[0] & 0x7f]) + ctype_object.data[1:]
- result = decimal.Decimal(data.decode(PROTOCOL_STRING_ENCODING))
+ data = ctype_object.data[1:]
+ data.insert(0, ctype_object.data[0] & 0x7f)
+ # decode n-byte integer
+ result = sum([
+ [x for x in reversed(data)][i] * 0x100 ** i for i in
+ range(len(data))
+ ])
# apply scale
result = (
result
- * decimal.Decimal('10') ** decimal.Decimal(ctype_object.scale)
+ / decimal.Decimal('10')
+ ** decimal.Decimal(ctype_object.scale)
)
if sign:
# apply sign
@@ -197,12 +204,20 @@
return Null.from_python()
sign, digits, scale = value.normalize().as_tuple()
- data = bytearray([ord('0') + digit for digit in digits])
+ integer = int(''.join([str(d) for d in digits]))
+ # calculate number of bytes (at least one, and not forget the sign bit)
+ length = ceil((integer.bit_length() + 1)/8)
+ # write byte string
+ data = []
+ for i in range(length):
+ digit = integer % 0x100
+ integer //= 0x100
+ data.insert(0, digit)
+ # apply sign
if sign:
data[0] |= 0x80
else:
data[0] &= 0x7f
- length = len(digits)
header_class = cls.build_c_header()
data_class = type(
cls.__name__,
@@ -210,7 +225,7 @@
{
'_pack_': 1,
'_fields_': [
- ('data', ctypes.c_char * length),
+ ('data', ctypes.c_ubyte * length),
],
}
)
@@ -220,8 +235,9 @@
byteorder=PROTOCOL_BYTE_ORDER
)
data_object.length = length
- data_object.scale = scale
- data_object.data = bytes(data)
+ data_object.scale = -scale
+ for i in range(length):
+ data_object.data[i] = data[i]
return bytes(data_object)
diff --git a/setup.py b/setup.py
index 5d14dae..7419c97 100644
--- a/setup.py
+++ b/setup.py
@@ -65,7 +65,7 @@
if is_a_requirement(line):
requirements[section].append(line)
-with open('README.md', 'r') as readme_file:
+with open('README.md', 'r', encoding='utf-8') as readme_file:
long_description = readme_file.read()
setuptools.setup(