Skip to content

Commit

Permalink
Fix Decimal128 and Decimal256 types_check #274
Browse files Browse the repository at this point in the history
  • Loading branch information
xzkostyan committed Dec 19, 2021
1 parent 2650b6f commit 1140c75
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 9 deletions.
14 changes: 8 additions & 6 deletions clickhouse_driver/columns/decimalcolumn.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,22 @@
class DecimalColumn(FormatColumn):
py_types = (Decimal, float, int)
max_precision = None
int_size = None

def __init__(self, precision, scale, types_check=False, **kwargs):
self.precision = precision
self.scale = scale
super(DecimalColumn, self).__init__(**kwargs)

if types_check:
max_signed_int = (1 << (8 * self.int_size - 1)) - 1

def check_item(value):
if value < -max_signed_int or value > max_signed_int:
parts = str(value).split('.')
int_part = parts[0]
frac_part = parts[1] if len(parts) > 1 else ''

if len(int_part) > precision:
raise ColumnTypeMismatchException(value)

if len(frac_part) > scale:
raise ColumnTypeMismatchException(value)

self.check_item = check_item
Expand Down Expand Up @@ -80,13 +84,11 @@ def _read_data(self, n_items, buf, nulls_map=None):
class Decimal32Column(DecimalColumn):
format = 'i'
max_precision = 9
int_size = 4


class Decimal64Column(DecimalColumn):
format = 'q'
max_precision = 18
int_size = 8


class Decimal128Column(DecimalColumn, Int128Column):
Expand Down
24 changes: 21 additions & 3 deletions tests/columns/test_decimal.py
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ def test_max_precisions(self):

def test_nullable(self):
with self.create_table('a Nullable(Decimal32(3))'):
data = [(300.42, ), (None, ), ]
data = [(300.42, ), (None, )]
self.client.execute(
'INSERT INTO test (a) VALUES', data
)
Expand All @@ -158,7 +158,7 @@ def test_nullable(self):

def test_no_scale(self):
with self.create_table('a Decimal32(0)'):
data = [(2147483647, ), ]
data = [(2147483647, )]
self.client.execute(
'INSERT INTO test (a) VALUES', data
)
Expand All @@ -171,7 +171,7 @@ def test_no_scale(self):
self.assertEqual(inserted, [(Decimal('2147483647'), )])

def test_type_mismatch(self):
data = [(2147483649,), ]
data = [(2147483649, )]
with self.create_table('a Decimal32(0)'):
with self.assertRaises(errors.TypeMismatchError) as e:
self.client.execute(
Expand All @@ -187,6 +187,24 @@ def test_type_mismatch(self):

self.assertIn('Column a', str(e.exception))

def test_type_mismatch_scale(self):
data = [(1.234,)]
with self.create_table('a Decimal32(2)'):
with self.assertRaises(errors.TypeMismatchError) as e:
self.client.execute(
'INSERT INTO test (a) VALUES', data, types_check=True
)

self.assertIn('1.234 for column "a"', str(e.exception))

# Without types_check decimal will be cropped.
self.client.execute('INSERT INTO test (a) VALUES', data)
query = 'SELECT * FROM test'
inserted = self.emit_cli(query)
self.assertEqual(inserted, '1.23\n')
inserted = self.client.execute(query)
self.assertEqual(inserted, [(Decimal('1.23'), )])

def test_preserve_precision(self):
data = [(1.66, ), (1.15, )]

Expand Down

0 comments on commit 1140c75

Please sign in to comment.