Skip to content

Commit cbf621a

Browse files
authored
fix: Correct size limits for Decimal cast (#24252)
1 parent 73acd74 commit cbf621a

File tree

2 files changed

+26
-10
lines changed

2 files changed

+26
-10
lines changed

crates/polars-compute/src/cast/primitive_to.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -229,12 +229,12 @@ pub fn integer_to_decimal<T: NativeType + AsPrimitive<i128>>(
229229
to_precision: usize,
230230
to_scale: usize,
231231
) -> PrimitiveArray<i128> {
232-
let multiplier = 10_i128.pow(to_scale as u32);
232+
assert!(to_precision <= 38);
233+
assert!(to_scale <= 38);
233234

234-
let min_for_precision = 9_i128
235-
.saturating_pow(1 + to_precision as u32)
236-
.saturating_neg();
237-
let max_for_precision = 9_i128.saturating_pow(1 + to_precision as u32);
235+
let multiplier = 10_i128.pow(to_scale as u32);
236+
let max_for_precision = 10_i128.pow(to_precision as u32) - 1;
237+
let min_for_precision = -max_for_precision;
238238

239239
let values = from.iter().map(|x| {
240240
x.and_then(|x| {
@@ -274,13 +274,13 @@ where
274274
T: NativeType + Float + ToPrimitive,
275275
f64: AsPrimitive<T>,
276276
{
277+
assert!(to_precision <= 38);
278+
assert!(to_scale <= 38);
279+
277280
// 1.2 => 12
278281
let multiplier: T = (10_f64).powi(to_scale as i32).as_();
279-
280-
let min_for_precision = 9_i128
281-
.saturating_pow(1 + to_precision as u32)
282-
.saturating_neg();
283-
let max_for_precision = 9_i128.saturating_pow(1 + to_precision as u32);
282+
let max_for_precision = 10_i128.pow(to_precision as u32) - 1;
283+
let min_for_precision = -max_for_precision;
284284

285285
let values = from.iter().map(|x| {
286286
x.and_then(|x| {

py-polars/tests/unit/datatypes/test_decimal.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import pytest
1414

1515
import polars as pl
16+
from polars.exceptions import InvalidOperationError
1617
from polars.testing import assert_frame_equal, assert_series_equal
1718

1819

@@ -758,3 +759,18 @@ def test_decimal32_decimal64_22946() -> None:
758759
]
759760
),
760761
)
762+
763+
764+
def test_decimal_cast_limit() -> None:
765+
fits = pl.Series([10**38 - 1, -(10**38 - 1)])
766+
assert_series_equal(fits.cast(pl.Decimal(38, 0)).cast(pl.Int128), fits)
767+
768+
with pytest.raises(InvalidOperationError):
769+
fits.cast(pl.Decimal(39, 0))
770+
771+
too_large1 = pl.Series([10**38])
772+
too_large2 = pl.Series([-(10**38)])
773+
with pytest.raises(InvalidOperationError):
774+
too_large1.cast(pl.Decimal(38, 0))
775+
with pytest.raises(InvalidOperationError):
776+
too_large2.cast(pl.Decimal(38, 0))

0 commit comments

Comments
 (0)