Skip to content

Commit 59d0f5b

Browse files
authored
fix(query): fix decimal overflow check (#13292)
1 parent e5751d4 commit 59d0f5b

File tree

2 files changed

+43
-4
lines changed

2 files changed

+43
-4
lines changed

src/query/functions/src/scalars/decimal.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -709,7 +709,7 @@ pub fn register(registry: &mut FunctionRegistry) {
709709
calc_domain: Box::new(move |ctx, d| {
710710
convert_to_decimal_domain(ctx, d[0].clone(), decimal_type)
711711
.map(|d| FunctionDomain::Domain(Domain::Decimal(d)))
712-
.unwrap_or(FunctionDomain::Full)
712+
.unwrap_or(FunctionDomain::MayThrow)
713713
}),
714714
eval: Box::new(move |args, ctx| {
715715
convert_to_decimal(&args[0], ctx, &from_type, decimal_type)
@@ -994,6 +994,7 @@ fn convert_to_decimal_domain(
994994
};
995995
let dest_size = dest_type.size();
996996
let res = convert_to_decimal(&value.as_ref(), &mut ctx, &from_type, dest_type);
997+
997998
if ctx.errors.is_some() {
998999
return None;
9991000
}
@@ -1313,8 +1314,9 @@ fn decimal_256_to_128(
13131314
.enumerate()
13141315
.map(|(row, x)| {
13151316
let x = x * i128::one();
1317+
13161318
match x.checked_div(factor) {
1317-
Some(x) if x <= max && x >= min => *x.low(),
1319+
Some(y) if (y <= max && y >= min) && !(y == 0 && x > 0) => *y.low(),
13181320
_ => {
13191321
ctx.set_error(row, concat!("Decimal overflow at line : ", line!()));
13201322
i128::one()
@@ -1344,7 +1346,28 @@ macro_rules! m_decimal_to_decimal {
13441346
} else {
13451347
let values: Vec<_> = if $from_size.scale > $dest_size.scale {
13461348
let factor = <$dest_type_name>::e(($from_size.scale - $dest_size.scale) as u32);
1347-
$buffer.iter().map(|x| x / factor).collect()
1349+
let max = <$dest_type_name>::max_for_precision($dest_size.precision);
1350+
let min = <$dest_type_name>::min_for_precision($dest_size.precision);
1351+
$buffer
1352+
.iter()
1353+
.enumerate()
1354+
.map(|(row, x)| {
1355+
let x = x * <$dest_type_name>::one();
1356+
1357+
match x.checked_div(factor) {
1358+
Some(y) if y <= max && y >= min && !(y == 0 && x > 0) => {
1359+
y as $dest_type_name
1360+
}
1361+
_ => {
1362+
$ctx.set_error(
1363+
row,
1364+
concat!("Decimal overflow at line : ", line!()),
1365+
);
1366+
<$dest_type_name>::one()
1367+
}
1368+
}
1369+
})
1370+
.collect()
13481371
} else {
13491372
let factor = <$dest_type_name>::e(($dest_size.scale - $from_size.scale) as u32);
13501373
let max = <$dest_type_name>::max_for_precision($dest_size.precision);

tests/sqllogictests/suites/base/11_data_type/11_0006_data_type_decimal

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -985,4 +985,20 @@ select * from t
985985
([NULL,NULL])
986986

987987
statement ok
988-
drop table t
988+
drop table t
989+
990+
991+
statement error 1001
992+
select to_decimal(2,1)(10.1);
993+
994+
statement error 1001
995+
select to_decimal(2,1)(10.11);
996+
997+
statement ok
998+
create table if not exists test_decimal_insert(num DECIMAL(2,1));
999+
1000+
statement error 1001
1001+
insert into test_decimal_insert values(10.9);
1002+
1003+
statement ok
1004+
drop table test_decimal_insert

0 commit comments

Comments
 (0)