This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
The following commit(s) were added to refs/heads/master by this push:
new 522bd012f1 Fix string '0' cast to decimal with scale 0 (#6547)
522bd012f1 is described below
commit 522bd012f1b92419d9832180b609b0caf9fff35c
Author: Piotr Findeisen <[email protected]>
AuthorDate: Mon Oct 14 13:36:37 2024 +0200
Fix string '0' cast to decimal with scale 0 (#6547)
* Fix string '0' cast to decimal with scale 0
Before the change, the cast used to fail or return null, depending on
cast options.
* Add more test cases
---
arrow-cast/src/cast/decimal.rs | 47 ++++++++++++++++++++++-
arrow-cast/src/cast/mod.rs | 85 ++++++++++++++++++++++++++++++++++++++++++
2 files changed, 131 insertions(+), 1 deletion(-)
diff --git a/arrow-cast/src/cast/decimal.rs b/arrow-cast/src/cast/decimal.rs
index 637cbc4170..d6b2f884f7 100644
--- a/arrow-cast/src/cast/decimal.rs
+++ b/arrow-cast/src/cast/decimal.rs
@@ -250,7 +250,7 @@ where
}
};
- let integers = first_part.trim_start_matches('0');
+ let integers = first_part;
let decimals = if parts.len() == 2 { parts[1] } else { "" };
if !integers.is_empty() && !integers.as_bytes()[0].is_ascii_digit() {
@@ -567,3 +567,48 @@ where
let array = array.unary::<_, T>(op);
Ok(Arc::new(array))
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_parse_string_to_decimal_native() -> Result<(), ArrowError> {
+ assert_eq!(
+ parse_string_to_decimal_native::<Decimal128Type>("0", 0)?,
+ 0_i128
+ );
+ assert_eq!(
+ parse_string_to_decimal_native::<Decimal128Type>("0", 5)?,
+ 0_i128
+ );
+
+ assert_eq!(
+ parse_string_to_decimal_native::<Decimal128Type>("123", 0)?,
+ 123_i128
+ );
+ assert_eq!(
+ parse_string_to_decimal_native::<Decimal128Type>("123", 5)?,
+ 12300000_i128
+ );
+
+ assert_eq!(
+ parse_string_to_decimal_native::<Decimal128Type>("123.45", 0)?,
+ 123_i128
+ );
+ assert_eq!(
+ parse_string_to_decimal_native::<Decimal128Type>("123.45", 5)?,
+ 12345000_i128
+ );
+
+ assert_eq!(
+ parse_string_to_decimal_native::<Decimal128Type>("123.4567891",
0)?,
+ 123_i128
+ );
+ assert_eq!(
+ parse_string_to_decimal_native::<Decimal128Type>("123.4567891",
5)?,
+ 12345679_i128
+ );
+ Ok(())
+ }
+}
diff --git a/arrow-cast/src/cast/mod.rs b/arrow-cast/src/cast/mod.rs
index e3fad3da19..7abadf5793 100644
--- a/arrow-cast/src/cast/mod.rs
+++ b/arrow-cast/src/cast/mod.rs
@@ -8481,6 +8481,10 @@ mod tests {
assert!(decimal_arr.is_null(25));
assert!(decimal_arr.is_null(26));
assert!(decimal_arr.is_null(27));
+ assert_eq!("0.00", decimal_arr.value_as_string(28));
+ assert_eq!("0.00", decimal_arr.value_as_string(29));
+ assert_eq!("12345.00", decimal_arr.value_as_string(30));
+ assert_eq!(decimal_arr.len(), 31);
// Decimal256
let output_type = DataType::Decimal256(76, 3);
@@ -8517,6 +8521,10 @@ mod tests {
assert!(decimal_arr.is_null(25));
assert!(decimal_arr.is_null(26));
assert!(decimal_arr.is_null(27));
+ assert_eq!("0.000", decimal_arr.value_as_string(28));
+ assert_eq!("0.000", decimal_arr.value_as_string(29));
+ assert_eq!("12345.000", decimal_arr.value_as_string(30));
+ assert_eq!(decimal_arr.len(), 31);
}
#[test]
@@ -8550,10 +8558,30 @@ mod tests {
Some("1.-23499999"),
Some("-1.-23499999"),
Some("--1.23499999"),
+ Some("0"),
+ Some("000.000"),
+ Some("0000000000000000012345.000"),
]);
let array = Arc::new(str_array) as ArrayRef;
test_cast_string_to_decimal(array);
+
+ let test_cases = [
+ (None, None),
+ // (Some(""), None),
+ // (Some(" "), None),
+ (Some("0"), Some("0")),
+ (Some("000.000"), Some("0")),
+ (Some("12345"), Some("12345")),
+ (Some("000000000000000000000000000012345"), Some("12345")),
+ (Some("-123"), Some("-123")),
+ (Some("+123"), Some("123")),
+ ];
+ let inputs = test_cases.iter().map(|entry|
entry.0).collect::<Vec<_>>();
+ let expected = test_cases.iter().map(|entry|
entry.1).collect::<Vec<_>>();
+
+ let array = Arc::new(StringArray::from(inputs)) as ArrayRef;
+ test_cast_string_to_decimal_scale_zero(array, &expected);
}
#[test]
@@ -8587,10 +8615,67 @@ mod tests {
Some("1.-23499999"),
Some("-1.-23499999"),
Some("--1.23499999"),
+ Some("0"),
+ Some("000.000"),
+ Some("0000000000000000012345.000"),
]);
let array = Arc::new(str_array) as ArrayRef;
test_cast_string_to_decimal(array);
+
+ let test_cases = [
+ (None, None),
+ (Some(""), None),
+ (Some(" "), None),
+ (Some("0"), Some("0")),
+ (Some("000.000"), Some("0")),
+ (Some("12345"), Some("12345")),
+ (Some("000000000000000000000000000012345"), Some("12345")),
+ (Some("-123"), Some("-123")),
+ (Some("+123"), Some("123")),
+ ];
+ let inputs = test_cases.iter().map(|entry|
entry.0).collect::<Vec<_>>();
+ let expected = test_cases.iter().map(|entry|
entry.1).collect::<Vec<_>>();
+
+ let array = Arc::new(LargeStringArray::from(inputs)) as ArrayRef;
+ test_cast_string_to_decimal_scale_zero(array, &expected);
+ }
+
+ fn test_cast_string_to_decimal_scale_zero(
+ array: ArrayRef,
+ expected_as_string: &[Option<&str>],
+ ) {
+ // Decimal128
+ let output_type = DataType::Decimal128(38, 0);
+ assert!(can_cast_types(array.data_type(), &output_type));
+ let casted_array = cast(&array, &output_type).unwrap();
+ let decimal_arr = casted_array.as_primitive::<Decimal128Type>();
+ assert_decimal_array_contents(decimal_arr, expected_as_string);
+
+ // Decimal256
+ let output_type = DataType::Decimal256(76, 0);
+ assert!(can_cast_types(array.data_type(), &output_type));
+ let casted_array = cast(&array, &output_type).unwrap();
+ let decimal_arr = casted_array.as_primitive::<Decimal256Type>();
+ assert_decimal_array_contents(decimal_arr, expected_as_string);
+ }
+
+ fn assert_decimal_array_contents<T>(
+ array: &PrimitiveArray<T>,
+ expected_as_string: &[Option<&str>],
+ ) where
+ T: DecimalType + ArrowPrimitiveType,
+ {
+ assert_eq!(array.len(), expected_as_string.len());
+ for (i, expected) in expected_as_string.iter().enumerate() {
+ let actual = if array.is_null(i) {
+ None
+ } else {
+ Some(array.value_as_string(i))
+ };
+ let actual = actual.as_ref().map(|s| s.as_ref());
+ assert_eq!(*expected, actual, "Expected at position {}", i);
+ }
}
#[test]