Skip to content

feat:use parse_decimal for generic_string_to_decimal conversion. #7191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 1 commit into
base: main
Choose a base branch
from
Draft
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
10 changes: 6 additions & 4 deletions arrow-cast/src/cast/decimal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
// under the License.

use crate::cast::*;
use crate::parse::*;

/// A utility trait that provides checked conversions between
/// decimal types inspired by [`NumCast`]
Expand Down Expand Up @@ -352,7 +353,7 @@ where
{
if cast_options.safe {
let iter = from.iter().map(|v| {
v.and_then(|v| parse_string_to_decimal_native::<T>(v, scale as usize).ok())
v.and_then(|v| parse_decimal::<T>(v, precision, scale).ok())
.and_then(|v| T::is_valid_decimal_precision(v, precision).then_some(v))
});
// Benefit:
Expand All @@ -368,12 +369,13 @@ where
.iter()
.map(|v| {
v.map(|v| {
parse_string_to_decimal_native::<T>(v, scale as usize)
parse_decimal::<T>(v, precision, scale)
.map_err(|_| {
ArrowError::CastError(format!(
"Cannot cast string '{}' to value of {:?} type",
"Cannot cast string '{}' to decimal type of precision {} and scale {}",
v,
T::DATA_TYPE,
precision,
scale
))
})
.and_then(|v| T::validate_decimal_precision(v, precision).map(|_| v))
Expand Down
44 changes: 34 additions & 10 deletions arrow-cast/src/cast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2383,6 +2383,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
use crate::parse::parse_decimal;
use arrow_buffer::{Buffer, IntervalDayTime, NullBuffer};
use chrono::NaiveDate;
use half::f16;
Expand Down Expand Up @@ -2556,6 +2557,22 @@ mod tests {
]
);
}
#[test]
fn test_cast_with_options_utf8_to_decimal() {
let array = StringArray::from(vec!["4e7"]);
let result = cast_with_options(
&array,
&DataType::Decimal128(10, 2),
&CastOptions {
safe: false,
format_options: FormatOptions::default(),
},
)
.unwrap();
let output_array = result.as_any().downcast_ref::<Decimal128Array>();
let result_128 = parse_decimal::<Decimal128Type>("40000000", 10, 2);
assert_eq!(output_array.unwrap().value(0), result_128.unwrap());
}

#[test]
fn test_cast_decimal128_to_decimal128() {
Expand Down Expand Up @@ -8763,16 +8780,17 @@ mod tests {
format_options: FormatOptions::default(),
};
let casted_err = cast_with_options(&array, &output_type, &option).unwrap_err();
assert!(casted_err
.to_string()
.contains("Cannot cast string '4.4.5' to value of Decimal128(38, 10) type"));
println!("{}", casted_err.to_string());
assert!(casted_err.to_string().contains(
"Cast error: Cannot cast string '4.4.5' to decimal type of precision 38 and scale 2"
));

let str_array = StringArray::from(vec![". 0.123"]);
let array = Arc::new(str_array) as ArrayRef;
let casted_err = cast_with_options(&array, &output_type, &option).unwrap_err();
assert!(casted_err
.to_string()
.contains("Cannot cast string '. 0.123' to value of Decimal128(38, 10) type"));
assert!(casted_err.to_string().contains(
"Cast error: Cannot cast string '. 0.123' to decimal type of precision 38 and scale 2"
));
}

fn test_cast_string_to_decimal128_overflow(overflow_array: ArrayRef) {
Expand All @@ -8788,7 +8806,7 @@ mod tests {
decimal_arr.value_as_string(3)
);
assert_eq!(
"100000000000000000000000000000000000.00",
"99999999999999999999999999999999999.99",
decimal_arr.value_as_string(4)
);
}
Expand Down Expand Up @@ -8816,7 +8834,10 @@ mod tests {
format_options: FormatOptions::default(),
},
);
assert_eq!("Invalid argument error: 100000000000 is too large to store in a Decimal128 of precision 10. Max is 9999999999", err.unwrap_err().to_string());
assert_eq!(
"Cast error: Cannot cast string '1000' to decimal type of precision 10 and scale 8",
err.unwrap_err().to_string()
);
}

#[test]
Expand Down Expand Up @@ -8869,7 +8890,7 @@ mod tests {
decimal_arr.value_as_string(3)
);
assert_eq!(
"100000000000000000000000000000000000.00",
"99999999999999999999999999999999999.99",
decimal_arr.value_as_string(4)
);
assert!(decimal_arr.is_null(5));
Expand Down Expand Up @@ -8899,7 +8920,10 @@ mod tests {
format_options: FormatOptions::default(),
},
);
assert_eq!("Invalid argument error: 100000000000 is too large to store in a Decimal256 of precision 10. Max is 9999999999", err.unwrap_err().to_string());
assert_eq!(
"Cast error: Cannot cast string '1000' to decimal type of precision 10 and scale 8",
err.unwrap_err().to_string()
);
}

#[test]
Expand Down
Loading