Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 48 additions & 47 deletions datafusion/functions/src/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,53 +199,62 @@ where

/// Converts Decimal128 components (value and scale) to an unscaled i128
pub fn decimal128_to_i128(value: i128, scale: i8) -> Result<i128, ArrowError> {
if scale < 0 {
Err(ArrowError::ComputeError(
"Negative scale is not supported".into(),
))
} else if scale == 0 {
Ok(value)
if scale == 0 {
return Ok(value);
}

let scale_abs = scale.unsigned_abs() as u32;

let factor = i128::from(10).checked_pow(scale_abs).ok_or_else(|| {
ArrowError::ComputeError(format!("Cannot get a power of {scale_abs}"))
})?;

if scale > 0 {
Ok(value / factor)
} else {
match i128::from(10).checked_pow(scale as u32) {
Some(divisor) => Ok(value / divisor),
None => Err(ArrowError::ComputeError(format!(
"Cannot get a power of {scale}"
))),
}
value.checked_mul(factor).ok_or_else(|| {
ArrowError::ComputeError("Overflow while applying negative scale".into())
})
}
}

pub fn decimal32_to_i32(value: i32, scale: i8) -> Result<i32, ArrowError> {
if scale < 0 {
Err(ArrowError::ComputeError(
"Negative scale is not supported".into(),
))
} else if scale == 0 {
Ok(value)
if scale == 0 {
return Ok(value);
}

let scale_abs = scale.unsigned_abs() as u32;

let factor = 10_i32.checked_pow(scale_abs).ok_or_else(|| {
ArrowError::ComputeError(format!("Cannot get a power of {scale_abs}"))
})?;

if scale > 0 {
Ok(value / factor)
} else {
match 10_i32.checked_pow(scale as u32) {
Some(divisor) => Ok(value / divisor),
None => Err(ArrowError::ComputeError(format!(
"Cannot get a power of {scale}"
))),
}
value.checked_mul(factor).ok_or_else(|| {
ArrowError::ComputeError("Overflow while applying negative scale".into())
})
}
}

pub fn decimal64_to_i64(value: i64, scale: i8) -> Result<i64, ArrowError> {
if scale < 0 {
Err(ArrowError::ComputeError(
"Negative scale is not supported".into(),
))
} else if scale == 0 {
Ok(value)
if scale == 0 {
return Ok(value);
}

let scale_abs = scale.unsigned_abs() as u32;

let factor = i64::from(10).checked_pow(scale_abs).ok_or_else(|| {
ArrowError::ComputeError(format!("Cannot get a power of {scale_abs}"))
})?;

if scale > 0 {
Ok(value / factor)
} else {
match i64::from(10).checked_pow(scale as u32) {
Some(divisor) => Ok(value / divisor),
None => Err(ArrowError::ComputeError(format!(
"Cannot get a power of {scale}"
))),
}
value.checked_mul(factor).ok_or_else(|| {
ArrowError::ComputeError("Overflow while applying negative scale".into())
})
}
}

Expand Down Expand Up @@ -388,7 +397,7 @@ pub mod test {
(1230, 1, Some(123)),
(123000, 3, Some(123)),
(1, 0, Some(1)),
(123, -3, None),
(123, -3, Some(123000)),
(123, i8::MAX, None),
(i128::MAX, 0, Some(i128::MAX)),
(i128::MAX, 3, Some(i128::MAX / 1000)),
Expand Down Expand Up @@ -417,11 +426,7 @@ pub mod test {
(1234567, 2, Either::Left(12345)),
(-1234567, 2, Either::Left(-12345)),
(1, 0, Either::Left(1)),
(
123,
-3,
Either::Right("Negative scale is not supported".into()),
),
(123, -3, Either::Left(123000)),
(
123,
i8::MAX,
Expand Down Expand Up @@ -460,11 +465,7 @@ pub mod test {
(123, 0, Either::Left(123)),
(1234567890, 2, Either::Left(12345678)),
(-1234567890, 2, Either::Left(-12345678)),
(
123,
-3,
Either::Right("Negative scale is not supported".into()),
),
(123, -3, Either::Left(123000)),
(
123,
i8::MAX,
Expand Down
15 changes: 15 additions & 0 deletions datafusion/sqllogictest/test_files/decimal.slt
Original file line number Diff line number Diff line change
Expand Up @@ -1217,3 +1217,18 @@ NULL

query error Arrow error: Invalid argument error: 1.10 is too large to store in a Decimal128 of precision 2. Max is 0.99
select cast(1.1 as decimal(2, 2)) + 1;

query I
SELECT CAST(123.45 AS INT);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these tests pass on main as well (so I don't think they cover the intended usecase)

----
123

query I
SELECT CAST(1e2 AS INT);
----
100

query I
SELECT CAST(1e4 AS INT);
----
10000