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/11/28 10:12:38 UTC

(arrow-rs) branch master updated: Fix negative decimal string (#5128)

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 8a0b5cb252 Fix negative decimal string (#5128)
8a0b5cb252 is described below

commit 8a0b5cb25205a357c5f17a8af40e45019121c483
Author: Liang-Chi Hsieh <vi...@gmail.com>
AuthorDate: Tue Nov 28 02:12:32 2023 -0800

    Fix negative decimal string (#5128)
    
    * Fix negative cases
    
    * Fix
    
    * Fix
    
    * Fix clippy
    
    * Update arrow-cast/src/cast.rs
    
    Co-authored-by: Raphael Taylor-Davies <17...@users.noreply.github.com>
    
    * Update arrow-cast/src/cast.rs
    
    Co-authored-by: Raphael Taylor-Davies <17...@users.noreply.github.com>
    
    ---------
    
    Co-authored-by: Raphael Taylor-Davies <17...@users.noreply.github.com>
---
 arrow-cast/src/cast.rs | 90 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 88 insertions(+), 2 deletions(-)

diff --git a/arrow-cast/src/cast.rs b/arrow-cast/src/cast.rs
index 38b9fb4c34..8facb4f161 100644
--- a/arrow-cast/src/cast.rs
+++ b/arrow-cast/src/cast.rs
@@ -2596,11 +2596,33 @@ where
         )));
     }
 
-    let integers = parts[0].trim_start_matches('0');
+    let (negative, first_part) = if parts[0].is_empty() {
+        (false, parts[0])
+    } else {
+        match parts[0].as_bytes()[0] {
+            b'-' => (true, &parts[0][1..]),
+            b'+' => (false, &parts[0][1..]),
+            _ => (false, parts[0]),
+        }
+    };
+
+    let integers = first_part.trim_start_matches('0');
     let decimals = if parts.len() == 2 { parts[1] } else { "" };
 
+    if !integers.is_empty() && !integers.as_bytes()[0].is_ascii_digit() {
+        return Err(ArrowError::InvalidArgumentError(format!(
+            "Invalid decimal format: {value_str:?}"
+        )));
+    }
+
+    if !decimals.is_empty() && !decimals.as_bytes()[0].is_ascii_digit() {
+        return Err(ArrowError::InvalidArgumentError(format!(
+            "Invalid decimal format: {value_str:?}"
+        )));
+    }
+
     // Adjust decimal based on scale
-    let number_decimals = if decimals.len() > scale {
+    let mut number_decimals = if decimals.len() > scale {
         let decimal_number = i256::from_string(decimals).ok_or_else(|| {
             ArrowError::InvalidArgumentError(format!("Cannot parse decimal format: {value_str}"))
         })?;
@@ -2640,6 +2662,10 @@ where
         format!("{integers}{decimals}")
     };
 
+    if negative {
+        number_decimals.insert(0, '-');
+    }
+
     let value = i256::from_string(number_decimals.as_str()).ok_or_else(|| {
         ArrowError::InvalidArgumentError(format!(
             "Cannot convert {} to {}: Overflow",
@@ -8256,6 +8282,21 @@ mod tests {
         assert_eq!("0.00", decimal_arr.value_as_string(10));
         assert_eq!("0.00", decimal_arr.value_as_string(11));
         assert!(decimal_arr.is_null(12));
+        assert_eq!("-1.23", decimal_arr.value_as_string(13));
+        assert_eq!("-1.24", decimal_arr.value_as_string(14));
+        assert_eq!("0.00", decimal_arr.value_as_string(15));
+        assert_eq!("-123.00", decimal_arr.value_as_string(16));
+        assert_eq!("-123.23", decimal_arr.value_as_string(17));
+        assert_eq!("-0.12", decimal_arr.value_as_string(18));
+        assert_eq!("1.23", decimal_arr.value_as_string(19));
+        assert_eq!("1.24", decimal_arr.value_as_string(20));
+        assert_eq!("0.00", decimal_arr.value_as_string(21));
+        assert_eq!("123.00", decimal_arr.value_as_string(22));
+        assert_eq!("123.23", decimal_arr.value_as_string(23));
+        assert_eq!("0.12", decimal_arr.value_as_string(24));
+        assert!(decimal_arr.is_null(25));
+        assert!(decimal_arr.is_null(26));
+        assert!(decimal_arr.is_null(27));
 
         // Decimal256
         let output_type = DataType::Decimal256(76, 3);
@@ -8277,6 +8318,21 @@ mod tests {
         assert_eq!("0.000", decimal_arr.value_as_string(10));
         assert_eq!("0.000", decimal_arr.value_as_string(11));
         assert!(decimal_arr.is_null(12));
+        assert_eq!("-1.235", decimal_arr.value_as_string(13));
+        assert_eq!("-1.236", decimal_arr.value_as_string(14));
+        assert_eq!("0.000", decimal_arr.value_as_string(15));
+        assert_eq!("-123.000", decimal_arr.value_as_string(16));
+        assert_eq!("-123.234", decimal_arr.value_as_string(17));
+        assert_eq!("-0.123", decimal_arr.value_as_string(18));
+        assert_eq!("1.235", decimal_arr.value_as_string(19));
+        assert_eq!("1.236", decimal_arr.value_as_string(20));
+        assert_eq!("0.000", decimal_arr.value_as_string(21));
+        assert_eq!("123.000", decimal_arr.value_as_string(22));
+        assert_eq!("123.234", decimal_arr.value_as_string(23));
+        assert_eq!("0.123", decimal_arr.value_as_string(24));
+        assert!(decimal_arr.is_null(25));
+        assert!(decimal_arr.is_null(26));
+        assert!(decimal_arr.is_null(27));
     }
 
     #[test]
@@ -8295,6 +8351,21 @@ mod tests {
             Some(""),
             Some(" "),
             None,
+            Some("-1.23499999"),
+            Some("-1.23599999"),
+            Some("-0.00001"),
+            Some("-123"),
+            Some("-123.234000"),
+            Some("-000.123"),
+            Some("+1.23499999"),
+            Some("+1.23599999"),
+            Some("+0.00001"),
+            Some("+123"),
+            Some("+123.234000"),
+            Some("+000.123"),
+            Some("1.-23499999"),
+            Some("-1.-23499999"),
+            Some("--1.23499999"),
         ]);
         let array = Arc::new(str_array) as ArrayRef;
 
@@ -8317,6 +8388,21 @@ mod tests {
             Some(""),
             Some(" "),
             None,
+            Some("-1.23499999"),
+            Some("-1.23599999"),
+            Some("-0.00001"),
+            Some("-123"),
+            Some("-123.234000"),
+            Some("-000.123"),
+            Some("+1.23499999"),
+            Some("+1.23599999"),
+            Some("+0.00001"),
+            Some("+123"),
+            Some("+123.234000"),
+            Some("+000.123"),
+            Some("1.-23499999"),
+            Some("-1.-23499999"),
+            Some("--1.23499999"),
         ]);
         let array = Arc::new(str_array) as ArrayRef;