You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by al...@apache.org on 2021/11/10 11:40:34 UTC

[arrow-rs] branch master updated: add checker for appending i128 to decimal builder (#928)

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 1945f6f  add checker for appending i128 to decimal builder (#928)
1945f6f is described below

commit 1945f6f96551e501010a4578295456a1f9f335e9
Author: Kun Liu <li...@apache.org>
AuthorDate: Wed Nov 10 19:40:29 2021 +0800

    add checker for appending i128 to decimal builder (#928)
    
    * add check for appending i128 to decimal builder
    
    * remove the ArrowError(DecimalError)
---
 arrow/src/array/array_binary.rs | 35 +++++++++++++++-
 arrow/src/array/builder.rs      | 89 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 123 insertions(+), 1 deletion(-)

diff --git a/arrow/src/array/array_binary.rs b/arrow/src/array/array_binary.rs
index 0592c04..ecf1850 100644
--- a/arrow/src/array/array_binary.rs
+++ b/arrow/src/array/array_binary.rs
@@ -1287,8 +1287,41 @@ mod tests {
     }
 
     #[test]
+    fn test_decimal_append_error_value() {
+        let mut decimal_builder = DecimalBuilder::new(10, 5, 3);
+        let mut result = decimal_builder.append_value(123456);
+        let mut error = result.unwrap_err();
+        assert_eq!(
+            "Invalid argument error: The value of 123456 i128 is not compatible with Decimal(5,3)",
+            error.to_string()
+        );
+        decimal_builder.append_value(12345).unwrap();
+        let arr = decimal_builder.finish();
+        assert_eq!("12.345", arr.value_as_string(0));
+
+        decimal_builder = DecimalBuilder::new(10, 2, 1);
+        result = decimal_builder.append_value(100);
+        error = result.unwrap_err();
+        assert_eq!(
+            "Invalid argument error: The value of 100 i128 is not compatible with Decimal(2,1)",
+            error.to_string()
+        );
+        decimal_builder.append_value(99).unwrap();
+        result = decimal_builder.append_value(-100);
+        error = result.unwrap_err();
+        assert_eq!(
+            "Invalid argument error: The value of -100 i128 is not compatible with Decimal(2,1)",
+            error.to_string()
+        );
+        decimal_builder.append_value(-99).unwrap();
+        let arr = decimal_builder.finish();
+        assert_eq!("9.9", arr.value_as_string(0));
+        assert_eq!("-9.9", arr.value_as_string(1));
+    }
+
+    #[test]
     fn test_decimal_array_value_as_string() {
-        let mut decimal_builder = DecimalBuilder::new(7, 5, 3);
+        let mut decimal_builder = DecimalBuilder::new(7, 6, 3);
         for value in [123450, -123450, 100, -100, 10, -10, 0] {
             decimal_builder.append_value(value).unwrap();
         }
diff --git a/arrow/src/array/builder.rs b/arrow/src/array/builder.rs
index 60f76d9..d08816c 100644
--- a/arrow/src/array/builder.rs
+++ b/arrow/src/array/builder.rs
@@ -1118,6 +1118,87 @@ pub struct FixedSizeBinaryBuilder {
     builder: FixedSizeListBuilder<UInt8Builder>,
 }
 
+const MAX_DECIMAL_FOR_EACH_PRECISION: [i128; 38] = [
+    9,
+    99,
+    999,
+    9999,
+    99999,
+    999999,
+    9999999,
+    99999999,
+    999999999,
+    9999999999,
+    99999999999,
+    999999999999,
+    9999999999999,
+    99999999999999,
+    999999999999999,
+    9999999999999999,
+    99999999999999999,
+    999999999999999999,
+    9999999999999999999,
+    99999999999999999999,
+    999999999999999999999,
+    9999999999999999999999,
+    99999999999999999999999,
+    999999999999999999999999,
+    9999999999999999999999999,
+    99999999999999999999999999,
+    999999999999999999999999999,
+    9999999999999999999999999999,
+    99999999999999999999999999999,
+    999999999999999999999999999999,
+    9999999999999999999999999999999,
+    99999999999999999999999999999999,
+    999999999999999999999999999999999,
+    9999999999999999999999999999999999,
+    99999999999999999999999999999999999,
+    999999999999999999999999999999999999,
+    9999999999999999999999999999999999999,
+    170141183460469231731687303715884105727,
+];
+const MIN_DECIMAL_FOR_EACH_PRECISION: [i128; 38] = [
+    -9,
+    -99,
+    -999,
+    -9999,
+    -99999,
+    -999999,
+    -9999999,
+    -99999999,
+    -999999999,
+    -9999999999,
+    -99999999999,
+    -999999999999,
+    -9999999999999,
+    -99999999999999,
+    -999999999999999,
+    -9999999999999999,
+    -99999999999999999,
+    -999999999999999999,
+    -9999999999999999999,
+    -99999999999999999999,
+    -999999999999999999999,
+    -9999999999999999999999,
+    -99999999999999999999999,
+    -999999999999999999999999,
+    -9999999999999999999999999,
+    -99999999999999999999999999,
+    -999999999999999999999999999,
+    -9999999999999999999999999999,
+    -99999999999999999999999999999,
+    -999999999999999999999999999999,
+    -9999999999999999999999999999999,
+    -99999999999999999999999999999999,
+    -999999999999999999999999999999999,
+    -9999999999999999999999999999999999,
+    -99999999999999999999999999999999999,
+    -999999999999999999999999999999999999,
+    -9999999999999999999999999999999999999,
+    -170141183460469231731687303715884105728,
+];
+
 ///
 /// Array Builder for [`DecimalArray`]
 ///
@@ -1431,6 +1512,14 @@ impl DecimalBuilder {
     /// distinct array element.
     #[inline]
     pub fn append_value(&mut self, value: i128) -> Result<()> {
+        if value > MAX_DECIMAL_FOR_EACH_PRECISION[self.precision - 1]
+            || value < MIN_DECIMAL_FOR_EACH_PRECISION[self.precision - 1]
+        {
+            return Err(ArrowError::InvalidArgumentError(format!(
+                "The value of {} i128 is not compatible with Decimal({},{})",
+                value, self.precision, self.scale
+            )));
+        }
         let value_as_bytes = Self::from_i128_to_fixed_size_bytes(
             value,
             self.builder.value_length() as usize,