Skip to content
14 changes: 12 additions & 2 deletions arrow-json/src/reader/boolean_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,20 @@ use arrow_array::ArrayRef;
use arrow_array::builder::BooleanBuilder;
use arrow_schema::ArrowError;

use crate::reader::ArrayDecoder;
use crate::reader::tape::{Tape, TapeElement};
use crate::reader::{ArrayDecoder, DecoderContext};

#[derive(Default)]
pub struct BooleanArrayDecoder {}
pub struct BooleanArrayDecoder {
ignore_type_conflicts: bool,
}
impl BooleanArrayDecoder {
pub fn new(ctx: &DecoderContext) -> Self {
Self {
ignore_type_conflicts: ctx.ignore_type_conflicts(),
}
}
}

impl ArrayDecoder for BooleanArrayDecoder {
fn decode(&mut self, tape: &Tape<'_>, pos: &[u32]) -> Result<ArrayRef, ArrowError> {
Expand All @@ -35,6 +44,7 @@ impl ArrayDecoder for BooleanArrayDecoder {
TapeElement::Null => builder.append_null(),
TapeElement::True => builder.append_value(true),
TapeElement::False => builder.append_value(false),
_ if self.ignore_type_conflicts => builder.append_null(),
_ => return Err(tape.error(*p, "boolean")),
}
}
Expand Down
54 changes: 29 additions & 25 deletions arrow-json/src/reader/decimal_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,23 @@ use arrow_array::types::DecimalType;
use arrow_cast::parse::parse_decimal;
use arrow_schema::ArrowError;

use crate::reader::ArrayDecoder;
use crate::reader::tape::{Tape, TapeElement};
use crate::reader::{ArrayDecoder, DecoderContext};

pub struct DecimalArrayDecoder<D: DecimalType> {
precision: u8,
scale: i8,
ignore_type_conflicts: bool,
// Invariant and Send
phantom: PhantomData<fn(D) -> D>,
}

impl<D: DecimalType> DecimalArrayDecoder<D> {
pub fn new(precision: u8, scale: i8) -> Self {
pub fn new(ctx: &DecoderContext, precision: u8, scale: i8) -> Self {
Self {
precision,
scale,
ignore_type_conflicts: ctx.ignore_type_conflicts(),
phantom: PhantomData,
}
}
Expand All @@ -51,46 +53,48 @@ where
fn decode(&mut self, tape: &Tape<'_>, pos: &[u32]) -> Result<ArrayRef, ArrowError> {
let mut builder = PrimitiveBuilder::<D>::with_capacity(pos.len());

#[allow(unused)] // initial value overwritten without ever being read
let mut anchor = String::default();
for p in pos {
match tape.get(*p) {
TapeElement::Null => builder.append_null(),
TapeElement::String(idx) => {
let s = tape.get_string(idx);
let value = parse_decimal::<D>(s, self.precision, self.scale)?;
builder.append_value(value)
}
TapeElement::Number(idx) => {
let s = tape.get_string(idx);
let value = parse_decimal::<D>(s, self.precision, self.scale)?;
builder.append_value(value)
let value = match tape.get(*p) {
TapeElement::Null => {
builder.append_null();
continue;
}
TapeElement::String(idx) | TapeElement::Number(idx) => tape.get_string(idx),
TapeElement::I64(high) => match tape.get(*p + 1) {
TapeElement::I32(low) => {
let val = (((high as i64) << 32) | (low as u32) as i64).to_string();
let value = parse_decimal::<D>(&val, self.precision, self.scale)?;
builder.append_value(value)
anchor = (((high as i64) << 32) | (low as u32) as i64).to_string();
anchor.as_str()
}
_ => unreachable!(),
},
TapeElement::I32(val) => {
let s = val.to_string();
let value = parse_decimal::<D>(&s, self.precision, self.scale)?;
builder.append_value(value)
anchor = val.to_string();
anchor.as_str()
}
TapeElement::F64(high) => match tape.get(*p + 1) {
TapeElement::F32(low) => {
let val = f64::from_bits(((high as u64) << 32) | low as u64).to_string();
let value = parse_decimal::<D>(&val, self.precision, self.scale)?;
builder.append_value(value)
anchor = f64::from_bits(((high as u64) << 32) | low as u64).to_string();
anchor.as_str()
}
_ => unreachable!(),
},
TapeElement::F32(val) => {
let s = f32::from_bits(val).to_string();
let value = parse_decimal::<D>(&s, self.precision, self.scale)?;
builder.append_value(value)
anchor = f32::from_bits(val).to_string();
anchor.as_str()
}
_ if self.ignore_type_conflicts => {
builder.append_null();
continue;
}
_ => return Err(tape.error(*p, "decimal")),
};

match parse_decimal::<D>(value, self.precision, self.scale) {
Ok(value) => builder.append_value(value),
Err(_) if self.ignore_type_conflicts => builder.append_null(),
Err(e) => return Err(e),
}
}

Expand Down
6 changes: 6 additions & 0 deletions arrow-json/src/reader/list_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub struct ListLikeArrayDecoder<O, const IS_VIEW: bool> {
field: FieldRef,
decoder: Box<dyn ArrayDecoder>,
phantom: PhantomData<O>,
ignore_type_conflicts: bool,
is_nullable: bool,
}

Expand All @@ -57,6 +58,7 @@ impl<O: OffsetSizeTrait, const IS_VIEW: bool> ListLikeArrayDecoder<O, IS_VIEW> {
field: field.clone(),
decoder,
phantom: Default::default(),
ignore_type_conflicts: ctx.ignore_type_conflicts(),
is_nullable,
})
}
Expand All @@ -83,6 +85,10 @@ impl<O: OffsetSizeTrait, const IS_VIEW: bool> ArrayDecoder for ListLikeArrayDeco
nulls.append(false);
*p + 1
}
(_, Some(nulls)) if self.ignore_type_conflicts => {
nulls.append(false);
*p + 1
}
_ => return Err(tape.error(*p, "[")),
};

Expand Down
6 changes: 6 additions & 0 deletions arrow-json/src/reader/map_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ pub struct MapArrayDecoder {
ordered: bool,
keys: Box<dyn ArrayDecoder>,
values: Box<dyn ArrayDecoder>,
ignore_type_conflicts: bool,
is_nullable: bool,
}

Expand Down Expand Up @@ -75,6 +76,7 @@ impl MapArrayDecoder {
ordered,
keys,
values,
ignore_type_conflicts: ctx.ignore_type_conflicts(),
is_nullable,
})
}
Expand Down Expand Up @@ -103,6 +105,10 @@ impl ArrayDecoder for MapArrayDecoder {
nulls.append(false);
p + 1
}
(_, Some(nulls)) if self.ignore_type_conflicts => {
nulls.append(false);
p + 1
}
_ => return Err(tape.error(p, "{")),
};

Expand Down
Loading
Loading