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"}