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/03/06 22:45:59 UTC

[arrow-rs] branch master updated: Support reading decimal arrays from json (#3805)

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 3df7c00a3 Support reading decimal arrays from json (#3805)
3df7c00a3 is described below

commit 3df7c00a358cff34da8bacd819e791892755d3a9
Author: bold <be...@specht.net>
AuthorDate: Mon Mar 6 23:45:51 2023 +0100

    Support reading decimal arrays from json (#3805)
    
    * support decimals in json reader
    
    * fix clippy
    
    * move decimal parsing to cast and improve impl
    
    * iterate over bytes instead of chars
    
    Co-authored-by: Raphael Taylor-Davies <17...@users.noreply.github.com>
    
    * make decimal string check private
    
    Co-authored-by: Raphael Taylor-Davies <17...@users.noreply.github.com>
    
    * replace macro by generics
    
    * Test cleanup
    
    * apply scale to integers
    
    ---------
    
    Co-authored-by: b.specht <be...@pentlandfirth.com>
    Co-authored-by: Raphael Taylor-Davies <17...@users.noreply.github.com>
    Co-authored-by: Raphael Taylor-Davies <r....@googlemail.com>
---
 arrow-cast/src/parse.rs         | 173 +++++++++++++++++++++++++++++++-
 arrow-csv/src/reader/mod.rs     | 212 +---------------------------------------
 arrow-json/src/reader.rs        | 150 +++++++++++++++++++++++++++-
 arrow-json/test/data/basic.json |  24 ++---
 4 files changed, 331 insertions(+), 228 deletions(-)

diff --git a/arrow-cast/src/parse.rs b/arrow-cast/src/parse.rs
index a48dd2bac..f498bf142 100644
--- a/arrow-cast/src/parse.rs
+++ b/arrow-cast/src/parse.rs
@@ -16,7 +16,8 @@
 // under the License.
 
 use arrow_array::types::*;
-use arrow_array::ArrowPrimitiveType;
+use arrow_array::{ArrowNativeTypeOp, ArrowPrimitiveType};
+use arrow_buffer::ArrowNativeType;
 use arrow_schema::ArrowError;
 use chrono::prelude::*;
 
@@ -459,10 +460,114 @@ impl Parser for Date64Type {
     }
 }
 
+/// Parse the string format decimal value to i128/i256 format and checking the precision and scale.
+/// The result value can't be out of bounds.
+pub fn parse_decimal<T: DecimalType>(
+    s: &str,
+    precision: u8,
+    scale: i8,
+) -> Result<T::Native, ArrowError> {
+    if !is_valid_decimal(s) {
+        return Err(ArrowError::ParseError(format!(
+            "can't parse the string value {s} to decimal"
+        )));
+    }
+    let mut offset = s.len();
+    let len = s.len();
+    let mut base = T::Native::usize_as(1);
+    let scale_usize = usize::from(scale as u8);
+
+    // handle the value after the '.' and meet the scale
+    let delimiter_position = s.find('.');
+    match delimiter_position {
+        None => {
+            // there is no '.'
+            base = T::Native::usize_as(10).pow_checked(scale as u32)?;
+        }
+        Some(mid) => {
+            // there is the '.'
+            if len - mid >= scale_usize + 1 {
+                // If the string value is "123.12345" and the scale is 2, we should just remain '.12' and drop the '345' value.
+                offset -= len - mid - 1 - scale_usize;
+            } else {
+                // If the string value is "123.12" and the scale is 4, we should append '00' to the tail.
+                base = T::Native::usize_as(10)
+                    .pow_checked((scale_usize + 1 + mid - len) as u32)?;
+            }
+        }
+    };
+
+    // each byte is digit、'-' or '.'
+    let bytes = s.as_bytes();
+    let mut negative = false;
+    let mut result = T::Native::usize_as(0);
+
+    bytes[0..offset]
+        .iter()
+        .rev()
+        .try_for_each::<_, Result<(), ArrowError>>(|&byte| {
+            match byte {
+                b'-' => {
+                    negative = true;
+                }
+                b'0'..=b'9' => {
+                    let add =
+                        T::Native::usize_as((byte - b'0') as usize).mul_checked(base)?;
+                    result = result.add_checked(add)?;
+                    base = base.mul_checked(T::Native::usize_as(10))?;
+                }
+                // because we have checked the string value
+                _ => (),
+            }
+            Ok(())
+        })?;
+
+    if negative {
+        result = result.neg_checked()?;
+    }
+
+    match T::validate_decimal_precision(result, precision) {
+        Ok(_) => Ok(result),
+        Err(e) => Err(ArrowError::ParseError(format!(
+            "parse decimal overflow: {e}"
+        ))),
+    }
+}
+
+fn is_valid_decimal(s: &str) -> bool {
+    let mut seen_dot = false;
+    let mut seen_digit = false;
+    let mut seen_sign = false;
+
+    for c in s.as_bytes() {
+        match c {
+            b'-' | b'+' => {
+                if seen_digit || seen_dot || seen_sign {
+                    return false;
+                }
+                seen_sign = true;
+            }
+            b'.' => {
+                if seen_dot {
+                    return false;
+                }
+                seen_dot = true;
+            }
+            b'0'..=b'9' => {
+                seen_digit = true;
+            }
+            _ => return false,
+        }
+    }
+
+    seen_digit
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
     use arrow_array::timezone::Tz;
+    use arrow_buffer::i256;
 
     #[test]
     fn string_to_timestamp_timezone() {
@@ -920,4 +1025,70 @@ mod tests {
             .map_err(|e| assert!(e.to_string().ends_with(ERR_NANOSECONDS_NOT_SUPPORTED)))
             .unwrap_err();
     }
+
+    #[test]
+    fn test_parse_decimal_with_parameter() {
+        let tests = [
+            ("123.123", 123123i128),
+            ("123.1234", 123123i128),
+            ("123.1", 123100i128),
+            ("123", 123000i128),
+            ("-123.123", -123123i128),
+            ("-123.1234", -123123i128),
+            ("-123.1", -123100i128),
+            ("-123", -123000i128),
+            ("0.0000123", 0i128),
+            ("12.", 12000i128),
+            ("-12.", -12000i128),
+            ("00.1", 100i128),
+            ("-00.1", -100i128),
+            ("12345678912345678.1234", 12345678912345678123i128),
+            ("-12345678912345678.1234", -12345678912345678123i128),
+            ("99999999999999999.999", 99999999999999999999i128),
+            ("-99999999999999999.999", -99999999999999999999i128),
+            (".123", 123i128),
+            ("-.123", -123i128),
+            ("123.", 123000i128),
+            ("-123.", -123000i128),
+        ];
+        for (s, i) in tests {
+            let result_128 = parse_decimal::<Decimal128Type>(s, 20, 3);
+            assert_eq!(i, result_128.unwrap());
+            let result_256 = parse_decimal::<Decimal256Type>(s, 20, 3);
+            assert_eq!(i256::from_i128(i), result_256.unwrap());
+        }
+        let can_not_parse_tests = ["123,123", ".", "123.123.123"];
+        for s in can_not_parse_tests {
+            let result_128 = parse_decimal::<Decimal128Type>(s, 20, 3);
+            assert_eq!(
+                format!("Parser error: can't parse the string value {s} to decimal"),
+                result_128.unwrap_err().to_string()
+            );
+            let result_256 = parse_decimal::<Decimal256Type>(s, 20, 3);
+            assert_eq!(
+                format!("Parser error: can't parse the string value {s} to decimal"),
+                result_256.unwrap_err().to_string()
+            );
+        }
+        let overflow_parse_tests = ["12345678", "12345678.9", "99999999.99"];
+        for s in overflow_parse_tests {
+            let result_128 = parse_decimal::<Decimal128Type>(s, 10, 3);
+            let expected_128 = "Parser error: parse decimal overflow";
+            let actual_128 = result_128.unwrap_err().to_string();
+
+            assert!(
+                actual_128.contains(expected_128),
+                "actual: '{actual_128}', expected: '{expected_128}'"
+            );
+
+            let result_256 = parse_decimal::<Decimal256Type>(s, 10, 3);
+            let expected_256 = "Parser error: parse decimal overflow";
+            let actual_256 = result_256.unwrap_err().to_string();
+
+            assert!(
+                actual_256.contains(expected_256),
+                "actual: '{actual_256}', expected: '{expected_256}'"
+            );
+        }
+    }
 }
diff --git a/arrow-csv/src/reader/mod.rs b/arrow-csv/src/reader/mod.rs
index 84d55c4ae..8b1cd2f79 100644
--- a/arrow-csv/src/reader/mod.rs
+++ b/arrow-csv/src/reader/mod.rs
@@ -44,10 +44,8 @@ mod records;
 
 use arrow_array::builder::PrimitiveBuilder;
 use arrow_array::types::*;
-use arrow_array::ArrowNativeTypeOp;
 use arrow_array::*;
-use arrow_buffer::ArrowNativeType;
-use arrow_cast::parse::Parser;
+use arrow_cast::parse::{parse_decimal, Parser};
 use arrow_schema::*;
 use lazy_static::lazy_static;
 use regex::{Regex, RegexSet};
@@ -72,8 +70,6 @@ lazy_static! {
         r"^\d{4}-\d\d-\d\d[T ]\d\d:\d\d:\d\d.\d{1,6}$", //Timestamp(Microsecond)
         r"^\d{4}-\d\d-\d\d[T ]\d\d:\d\d:\d\d.\d{1,9}$", //Timestamp(Nanosecond)
     ]).unwrap();
-    static ref PARSE_DECIMAL_RE: Regex =
-        Regex::new(r"^-?(\d+\.?\d*|\d*\.?\d+)$").unwrap();
 }
 
 #[derive(Default, Copy, Clone)]
@@ -823,7 +819,7 @@ fn build_decimal_array<T: DecimalType>(
             decimal_builder.append_null();
         } else {
             let decimal_value: Result<T::Native, _> =
-                parse_decimal_with_parameter::<T>(s, precision, scale);
+                parse_decimal::<T>(s, precision, scale);
             match decimal_value {
                 Ok(v) => {
                     decimal_builder.append_value(v);
@@ -841,127 +837,6 @@ fn build_decimal_array<T: DecimalType>(
     ))
 }
 
-// Parse the string format decimal value to i128/i256 format and checking the precision and scale.
-// The result value can't be out of bounds.
-fn parse_decimal_with_parameter<T: DecimalType>(
-    s: &str,
-    precision: u8,
-    scale: i8,
-) -> Result<T::Native, ArrowError> {
-    if PARSE_DECIMAL_RE.is_match(s) {
-        let mut offset = s.len();
-        let len = s.len();
-        let mut base = T::Native::usize_as(1);
-        let scale_usize = usize::from(scale as u8);
-
-        // handle the value after the '.' and meet the scale
-        let delimiter_position = s.find('.');
-        match delimiter_position {
-            None => {
-                // there is no '.'
-                base = T::Native::usize_as(10).pow_checked(scale as u32)?;
-            }
-            Some(mid) => {
-                // there is the '.'
-                if len - mid >= scale_usize + 1 {
-                    // If the string value is "123.12345" and the scale is 2, we should just remain '.12' and drop the '345' value.
-                    offset -= len - mid - 1 - scale_usize;
-                } else {
-                    // If the string value is "123.12" and the scale is 4, we should append '00' to the tail.
-                    base = T::Native::usize_as(10)
-                        .pow_checked((scale_usize + 1 + mid - len) as u32)?;
-                }
-            }
-        };
-
-        // each byte is digit、'-' or '.'
-        let bytes = s.as_bytes();
-        let mut negative = false;
-        let mut result = T::Native::usize_as(0);
-
-        bytes[0..offset]
-            .iter()
-            .rev()
-            .try_for_each::<_, Result<(), ArrowError>>(|&byte| {
-                match byte {
-                    b'-' => {
-                        negative = true;
-                    }
-                    b'0'..=b'9' => {
-                        let add = T::Native::usize_as((byte - b'0') as usize)
-                            .mul_checked(base)?;
-                        result = result.add_checked(add)?;
-                        base = base.mul_checked(T::Native::usize_as(10))?;
-                    }
-                    // because of the PARSE_DECIMAL_RE, bytes just contains digit、'-' and '.'.
-                    _ => (),
-                }
-                Ok(())
-            })?;
-
-        if negative {
-            result = result.neg_checked()?;
-        }
-
-        match T::validate_decimal_precision(result, precision) {
-            Ok(_) => Ok(result),
-            Err(e) => Err(ArrowError::ParseError(format!(
-                "parse decimal overflow: {e}"
-            ))),
-        }
-    } else {
-        Err(ArrowError::ParseError(format!(
-            "can't parse the string value {s} to decimal"
-        )))
-    }
-}
-
-// Parse the string format decimal value to i128 format without checking the precision and scale.
-// Like "125.12" to 12512_i128.
-#[cfg(test)]
-fn parse_decimal(s: &str) -> Result<i128, ArrowError> {
-    use std::ops::Neg;
-
-    if PARSE_DECIMAL_RE.is_match(s) {
-        let mut offset = s.len();
-        // each byte is digit、'-' or '.'
-        let bytes = s.as_bytes();
-        let mut negative = false;
-        let mut result: i128 = 0;
-        let mut base = 1;
-        while offset > 0 {
-            match bytes[offset - 1] {
-                b'-' => {
-                    negative = true;
-                }
-                b'.' => {
-                    // do nothing
-                }
-                b'0'..=b'9' => {
-                    result += i128::from(bytes[offset - 1] - b'0') * base;
-                    base *= 10;
-                }
-                _ => {
-                    return Err(ArrowError::ParseError(format!(
-                        "can't match byte {}",
-                        bytes[offset - 1]
-                    )));
-                }
-            }
-            offset -= 1;
-        }
-        if negative {
-            Ok(result.neg())
-        } else {
-            Ok(result)
-        }
-    } else {
-        Err(ArrowError::ParseError(format!(
-            "can't parse the string value {s} to decimal"
-        )))
-    }
-}
-
 // parses a specific column (col_idx) into an Arrow Array.
 fn build_primitive_array<T: ArrowPrimitiveType + Parser>(
     line_number: usize,
@@ -1268,7 +1143,6 @@ impl ReaderBuilder {
 mod tests {
     use super::*;
 
-    use arrow_buffer::i256;
     use std::io::{Cursor, Write};
     use tempfile::NamedTempFile;
 
@@ -1812,88 +1686,6 @@ mod tests {
         );
     }
 
-    #[test]
-    fn test_parse_decimal() {
-        let tests = [
-            ("123.00", 12300i128),
-            ("123.123", 123123i128),
-            ("0.0123", 123i128),
-            ("0.12300", 12300i128),
-            ("-5.123", -5123i128),
-            ("-45.432432", -45432432i128),
-        ];
-        for (s, i) in tests {
-            let result = parse_decimal(s);
-            assert_eq!(i, result.unwrap());
-        }
-    }
-
-    #[test]
-    fn test_parse_decimal_with_parameter() {
-        let tests = [
-            ("123.123", 123123i128),
-            ("123.1234", 123123i128),
-            ("123.1", 123100i128),
-            ("123", 123000i128),
-            ("-123.123", -123123i128),
-            ("-123.1234", -123123i128),
-            ("-123.1", -123100i128),
-            ("-123", -123000i128),
-            ("0.0000123", 0i128),
-            ("12.", 12000i128),
-            ("-12.", -12000i128),
-            ("00.1", 100i128),
-            ("-00.1", -100i128),
-            ("12345678912345678.1234", 12345678912345678123i128),
-            ("-12345678912345678.1234", -12345678912345678123i128),
-            ("99999999999999999.999", 99999999999999999999i128),
-            ("-99999999999999999.999", -99999999999999999999i128),
-            (".123", 123i128),
-            ("-.123", -123i128),
-            ("123.", 123000i128),
-            ("-123.", -123000i128),
-        ];
-        for (s, i) in tests {
-            let result_128 = parse_decimal_with_parameter::<Decimal128Type>(s, 20, 3);
-            assert_eq!(i, result_128.unwrap());
-            let result_256 = parse_decimal_with_parameter::<Decimal256Type>(s, 20, 3);
-            assert_eq!(i256::from_i128(i), result_256.unwrap());
-        }
-        let can_not_parse_tests = ["123,123", ".", "123.123.123"];
-        for s in can_not_parse_tests {
-            let result_128 = parse_decimal_with_parameter::<Decimal128Type>(s, 20, 3);
-            assert_eq!(
-                format!("Parser error: can't parse the string value {s} to decimal"),
-                result_128.unwrap_err().to_string()
-            );
-            let result_256 = parse_decimal_with_parameter::<Decimal256Type>(s, 20, 3);
-            assert_eq!(
-                format!("Parser error: can't parse the string value {s} to decimal"),
-                result_256.unwrap_err().to_string()
-            );
-        }
-        let overflow_parse_tests = ["12345678", "12345678.9", "99999999.99"];
-        for s in overflow_parse_tests {
-            let result_128 = parse_decimal_with_parameter::<Decimal128Type>(s, 10, 3);
-            let expected_128 = "Parser error: parse decimal overflow";
-            let actual_128 = result_128.unwrap_err().to_string();
-
-            assert!(
-                actual_128.contains(expected_128),
-                "actual: '{actual_128}', expected: '{expected_128}'"
-            );
-
-            let result_256 = parse_decimal_with_parameter::<Decimal256Type>(s, 10, 3);
-            let expected_256 = "Parser error: parse decimal overflow";
-            let actual_256 = result_256.unwrap_err().to_string();
-
-            assert!(
-                actual_256.contains(expected_256),
-                "actual: '{actual_256}', expected: '{expected_256}'"
-            );
-        }
-    }
-
     #[test]
     fn test_parse_timestamp_microseconds() {
         assert_eq!(
diff --git a/arrow-json/src/reader.rs b/arrow-json/src/reader.rs
index 3ac39c110..f4610eb34 100644
--- a/arrow-json/src/reader.rs
+++ b/arrow-json/src/reader.rs
@@ -58,8 +58,8 @@ use serde_json::{map::Map as JsonMap, Value};
 use arrow_array::builder::*;
 use arrow_array::types::*;
 use arrow_array::*;
-use arrow_buffer::{bit_util, Buffer, MutableBuffer};
-use arrow_cast::parse::Parser;
+use arrow_buffer::{bit_util, i256, Buffer, MutableBuffer};
+use arrow_cast::parse::{parse_decimal, Parser};
 use arrow_data::{ArrayData, ArrayDataBuilder};
 use arrow_schema::*;
 
@@ -1019,6 +1019,76 @@ impl Decoder {
         ))
     }
 
+    fn build_decimal128_array(
+        &self,
+        rows: &[Value],
+        col_name: &str,
+        precision: u8,
+        scale: i8,
+    ) -> Result<ArrayRef, ArrowError> {
+        Ok(Arc::new(
+            rows.iter()
+                .map(|row| {
+                    row.get(col_name).and_then(|value| {
+                        if value.is_i64() {
+                            let mul = 10i128.pow(scale as _);
+                            value
+                                .as_i64()
+                                .and_then(num::cast::cast)
+                                .map(|v: i128| v * mul)
+                        } else if value.is_u64() {
+                            let mul = 10i128.pow(scale as _);
+                            value
+                                .as_u64()
+                                .and_then(num::cast::cast)
+                                .map(|v: i128| v * mul)
+                        } else if value.is_string() {
+                            value.as_str().and_then(|s| {
+                                parse_decimal::<Decimal128Type>(s, precision, scale).ok()
+                            })
+                        } else {
+                            let mul = 10_f64.powi(scale as i32);
+                            value.as_f64().map(|f| (f * mul).round() as i128)
+                        }
+                    })
+                })
+                .collect::<Decimal128Array>()
+                .with_precision_and_scale(precision, scale)?,
+        ))
+    }
+
+    fn build_decimal256_array(
+        &self,
+        rows: &[Value],
+        col_name: &str,
+        precision: u8,
+        scale: i8,
+    ) -> Result<ArrayRef, ArrowError> {
+        let mul = 10_f64.powi(scale as i32);
+        Ok(Arc::new(
+            rows.iter()
+                .map(|row| {
+                    row.get(col_name).and_then(|value| {
+                        if value.is_i64() {
+                            let mul = i256::from_i128(10).pow_wrapping(scale as _);
+                            value.as_i64().map(|i| i256::from_i128(i as _) * mul)
+                        } else if value.is_u64() {
+                            let mul = i256::from_i128(10).pow_wrapping(scale as _);
+                            value.as_u64().map(|i| i256::from_i128(i as _) * mul)
+                        } else if value.is_string() {
+                            value.as_str().and_then(|s| {
+                                parse_decimal::<Decimal256Type>(s, precision, scale).ok()
+                            })
+                        } else {
+                            value.as_f64().and_then(|f| i256::from_f64(f * mul.round()))
+                        }
+                    })
+                })
+                .collect::<Decimal256Array>()
+                .with_precision_and_scale(precision, scale)?,
+        ))
+    }
+
     /// Build a nested GenericListArray from a list of unnested `Value`s
     fn build_nested_list_array<OffsetSize: OffsetSizeTrait>(
         &self,
@@ -1379,6 +1449,10 @@ impl Decoder {
                         field.data_type(),
                         map_field,
                     ),
+                    DataType::Decimal128(precision, scale) => self
+                        .build_decimal128_array(rows, field.name(), *precision, *scale),
+                    DataType::Decimal256(precision, scale) => self
+                        .build_decimal256_array(rows, field.name(), *precision, *scale),
                     _ => Err(ArrowError::JsonError(format!(
                         "{:?} type is not supported",
                         field.data_type()
@@ -1776,7 +1850,7 @@ mod tests {
         as_boolean_array, as_dictionary_array, as_primitive_array, as_string_array,
         as_struct_array,
     };
-    use arrow_buffer::ToByteSlice;
+    use arrow_buffer::{ArrowNativeType, ToByteSlice};
     use arrow_schema::DataType::{Dictionary, List};
     use flate2::read::GzDecoder;
     use std::fs::File;
@@ -1790,7 +1864,7 @@ mod tests {
             .unwrap();
         let batch = reader.next().unwrap().unwrap();
 
-        assert_eq!(5, batch.num_columns());
+        assert_eq!(6, batch.num_columns());
         assert_eq!(12, batch.num_rows());
 
         let schema = reader.schema();
@@ -3328,7 +3402,7 @@ mod tests {
         let mut sum_a = 0;
         for batch in reader {
             let batch = batch.unwrap();
-            assert_eq!(5, batch.num_columns());
+            assert_eq!(6, batch.num_columns());
             sum_num_rows += batch.num_rows();
             num_batches += 1;
             let batch_schema = batch.schema();
@@ -3352,4 +3426,70 @@ mod tests {
         let cloned = options.clone();
         assert_eq!(options, cloned);
     }
+
+    pub fn decimal_json_tests<T: DecimalType>(data_type: DataType) {
+        let schema = Schema::new(vec![
+            Field::new("a", data_type.clone(), true),
+            Field::new("b", data_type.clone(), true),
+            Field::new("f", data_type.clone(), true),
+        ]);
+
+        let builder = ReaderBuilder::new()
+            .with_schema(Arc::new(schema))
+            .with_batch_size(64);
+        let mut reader: Reader<File> = builder
+            .build::<File>(File::open("test/data/basic.json").unwrap())
+            .unwrap();
+        let batch = reader.next().unwrap().unwrap();
+
+        assert_eq!(3, batch.num_columns());
+        assert_eq!(12, batch.num_rows());
+
+        let schema = reader.schema();
+        let batch_schema = batch.schema();
+        assert_eq!(schema, batch_schema);
+
+        let a = schema.column_with_name("a").unwrap();
+        let b = schema.column_with_name("b").unwrap();
+        let f = schema.column_with_name("f").unwrap();
+        assert_eq!(&data_type, a.1.data_type());
+        assert_eq!(&data_type, b.1.data_type());
+        assert_eq!(&data_type, f.1.data_type());
+
+        let aa = batch
+            .column(a.0)
+            .as_any()
+            .downcast_ref::<PrimitiveArray<T>>()
+            .unwrap();
+        assert_eq!(T::Native::usize_as(100), aa.value(0));
+        assert_eq!(T::Native::usize_as(100), aa.value(3));
+        assert_eq!(T::Native::usize_as(500), aa.value(7));
+
+        let bb = batch
+            .column(b.0)
+            .as_any()
+            .downcast_ref::<PrimitiveArray<T>>()
+            .unwrap();
+        assert_eq!(T::Native::usize_as(200), bb.value(0));
+        assert_eq!(T::Native::usize_as(350).neg_wrapping(), bb.value(1));
+        assert_eq!(T::Native::usize_as(60), bb.value(8));
+
+        let ff = batch
+            .column(f.0)
+            .as_any()
+            .downcast_ref::<PrimitiveArray<T>>()
+            .unwrap();
+        assert_eq!(T::Native::usize_as(102), ff.value(0));
+        assert_eq!(T::Native::usize_as(30).neg_wrapping(), ff.value(1));
+        assert_eq!(T::Native::usize_as(137722), ff.value(2));
+
+        assert_eq!(T::Native::usize_as(133700), ff.value(3));
+        assert_eq!(T::Native::usize_as(9999999999), ff.value(7));
+    }
+
+    #[test]
+    fn test_decimal_from_json() {
+        decimal_json_tests::<Decimal128Type>(DataType::Decimal128(10, 2));
+        decimal_json_tests::<Decimal256Type>(DataType::Decimal256(10, 2));
+    }
 }
diff --git a/arrow-json/test/data/basic.json b/arrow-json/test/data/basic.json
index 556c39c46..8de246e1a 100644
--- a/arrow-json/test/data/basic.json
+++ b/arrow-json/test/data/basic.json
@@ -1,12 +1,12 @@
-{"a":1, "b":2.0, "c":false, "d":"4", "e":"1970-1-2"}
-{"a":-10, "b":-3.5, "c":true, "d":"4", "e": "1969-12-31"}
-{"a":2, "b":0.6, "c":false, "d":"text", "e": "1970-01-02 11:11:11"}
-{"a":1, "b":2.0, "c":false, "d":"4"}
-{"a":7, "b":-3.5, "c":true, "d":"4"}
-{"a":1, "b":0.6, "c":false, "d":"text"}
-{"a":1, "b":2.0, "c":false, "d":"4"}
-{"a":5, "b":-3.5, "c":true, "d":"4"}
-{"a":1, "b":0.6, "c":false, "d":"text"}
-{"a":1, "b":2.0, "c":false, "d":"4"}
-{"a":1, "b":-3.5, "c":true, "d":"4"}
-{"a":100000000000000, "b":0.6, "c":false, "d":"text"}
+{"a":1, "b":2.0, "c":false, "d":"4", "e":"1970-1-2", "f": "1.02"}
+{"a":-10, "b":-3.5, "c":true, "d":"4", "e": "1969-12-31", "f": "-0.3"}
+{"a":2, "b":0.6, "c":false, "d":"text", "e": "1970-01-02 11:11:11", "f": "1377.223"}
+{"a":1, "b":2.0, "c":false, "d":"4", "f": "1337.009"}
+{"a":7, "b":-3.5, "c":true, "d":"4", "f": "1"}
+{"a":1, "b":0.6, "c":false, "d":"text", "f": "1338"}
+{"a":1, "b":2.0, "c":false, "d":"4", "f": "12345829100000"}
+{"a":5, "b":-3.5, "c":true, "d":"4", "f": "99999999.99"}
+{"a":1, "b":0.6, "c":false, "d":"text", "f": "1"}
+{"a":1, "b":2.0, "c":false, "d":"4", "f": "1"}
+{"a":1, "b":-3.5, "c":true, "d":"4", "f": "1"}
+{"a":100000000000000, "b":0.6, "c":false, "d":"text", "f": "1"}