You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by tu...@apache.org on 2023/04/01 20:46:00 UTC

[arrow-rs] branch master updated: Support CAST from Decimal datatype to String (#3994)

This is an automated email from the ASF dual-hosted git repository.

tustvold 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 591f0ef45 Support CAST from Decimal datatype to String (#3994)
591f0ef45 is described below

commit 591f0ef45c8184c2cbf5d46fc1ddf81c207e55ee
Author: comphead <co...@users.noreply.github.com>
AuthorDate: Sat Apr 1 13:45:54 2023 -0700

    Support CAST from Decimal datatype to String (#3994)
    
    * Support CAST Decimal to Utf8
    
    * remove null
    
    * fmt
    
    * Apply suggestions from code review
    
    Co-authored-by: Raphael Taylor-Davies <17...@users.noreply.github.com>
    
    * comments
    
    ---------
    
    Co-authored-by: Raphael Taylor-Davies <17...@users.noreply.github.com>
    Co-authored-by: Raphael Taylor-Davies <r....@googlemail.com>
---
 arrow-cast/src/cast.rs    | 61 +++++++++++++++++++++++++++++++++++++++++++++++
 arrow/tests/array_cast.rs |  4 +---
 2 files changed, 62 insertions(+), 3 deletions(-)

diff --git a/arrow-cast/src/cast.rs b/arrow-cast/src/cast.rs
index e4f4370fd..5d7bea0e9 100644
--- a/arrow-cast/src/cast.rs
+++ b/arrow-cast/src/cast.rs
@@ -145,6 +145,9 @@ pub fn can_cast_types(from_type: &DataType, to_type: &DataType) -> bool {
         // decimal to signed numeric
         (Decimal128(_, _), Null | Int8 | Int16 | Int32 | Int64 | Float32 | Float64) |
         (Decimal256(_, _), Null | Int8 | Int16 | Int32 | Int64 | Float32 | Float64) => true,
+        // decimal to Utf8
+        (Decimal128(_, _), Utf8 | LargeUtf8) => true,
+        (Decimal256(_, _), Utf8 | LargeUtf8) => true,
         // Utf8 to decimal
         (Utf8 | LargeUtf8, Decimal128(_, _)) => true,
         (Utf8 | LargeUtf8, Decimal256(_, _)) => true,
@@ -826,6 +829,8 @@ pub fn cast_with_options(
                         x as f64 / 10_f64.powi(*scale as i32)
                     })
                 }
+                Utf8 => value_to_string::<i32>(array),
+                LargeUtf8 => value_to_string::<i64>(array),
                 Null => Ok(new_null_array(to_type, array.len())),
                 _ => Err(ArrowError::CastError(format!(
                     "Casting from {from_type:?} to {to_type:?} not supported"
@@ -893,6 +898,8 @@ pub fn cast_with_options(
                         x.to_f64().unwrap() / 10_f64.powi(*scale as i32)
                     })
                 }
+                Utf8 => value_to_string::<i32>(array),
+                LargeUtf8 => value_to_string::<i64>(array),
                 Null => Ok(new_null_array(to_type, array.len())),
                 _ => Err(ArrowError::CastError(format!(
                     "Casting from {from_type:?} to {to_type:?} not supported"
@@ -8146,6 +8153,60 @@ mod tests {
         assert_eq!(1672531200000000000, c.value(0));
     }
 
+    #[test]
+    fn test_cast_decimal_to_utf8() {
+        fn test_decimal_to_string<IN: ArrowPrimitiveType, OffsetSize: OffsetSizeTrait>(
+            output_type: DataType,
+            array: PrimitiveArray<IN>,
+        ) {
+            let b = cast(&array, &output_type).unwrap();
+
+            assert_eq!(b.data_type(), &output_type);
+            let c = b.as_string::<OffsetSize>();
+
+            assert_eq!("1123.454", c.value(0));
+            assert_eq!("2123.456", c.value(1));
+            assert_eq!("-3123.453", c.value(2));
+            assert_eq!("-3123.456", c.value(3));
+            assert_eq!("0.000", c.value(4));
+            assert_eq!("0.123", c.value(5));
+            assert_eq!("1234.567", c.value(6));
+            assert_eq!("-1234.567", c.value(7));
+            assert!(c.is_null(8));
+        }
+        let array128: Vec<Option<i128>> = vec![
+            Some(1123454),
+            Some(2123456),
+            Some(-3123453),
+            Some(-3123456),
+            Some(0),
+            Some(123),
+            Some(123456789),
+            Some(-123456789),
+            None,
+        ];
+
+        let array256: Vec<Option<i256>> =
+            array128.iter().map(|v| v.map(i256::from_i128)).collect();
+
+        test_decimal_to_string::<arrow_array::types::Decimal128Type, i32>(
+            DataType::Utf8,
+            create_decimal_array(array128.clone(), 7, 3).unwrap(),
+        );
+        test_decimal_to_string::<arrow_array::types::Decimal128Type, i64>(
+            DataType::LargeUtf8,
+            create_decimal_array(array128, 7, 3).unwrap(),
+        );
+        test_decimal_to_string::<arrow_array::types::Decimal256Type, i32>(
+            DataType::Utf8,
+            create_decimal256_array(array256.clone(), 7, 3).unwrap(),
+        );
+        test_decimal_to_string::<arrow_array::types::Decimal256Type, i64>(
+            DataType::LargeUtf8,
+            create_decimal256_array(array256, 7, 3).unwrap(),
+        );
+    }
+
     #[test]
     fn test_cast_numeric_to_decimal128_precision_overflow() {
         let array = Int64Array::from(vec![1234567]);
diff --git a/arrow/tests/array_cast.rs b/arrow/tests/array_cast.rs
index 2807bbd79..96a4f2b41 100644
--- a/arrow/tests/array_cast.rs
+++ b/arrow/tests/array_cast.rs
@@ -185,9 +185,7 @@ fn get_arrays_of_all_types() -> Vec<ArrayRef> {
         Arc::new(DurationMillisecondArray::from(vec![1000, 2000])),
         Arc::new(DurationMicrosecondArray::from(vec![1000, 2000])),
         Arc::new(DurationNanosecondArray::from(vec![1000, 2000])),
-        Arc::new(
-            create_decimal_array(vec![Some(1), Some(2), Some(3), None], 38, 0).unwrap(),
-        ),
+        Arc::new(create_decimal_array(vec![Some(1), Some(2), Some(3)], 38, 0).unwrap()),
         make_dictionary_primitive::<Int8Type, Decimal128Type>(vec![1, 2]),
         make_dictionary_primitive::<Int16Type, Decimal128Type>(vec![1, 2]),
         make_dictionary_primitive::<Int32Type, Decimal128Type>(vec![1, 2]),