Skip to main content

parquet/arrow/array_reader/
primitive_array.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18use crate::arrow::array_reader::{ArrayReader, read_records, skip_records};
19use crate::arrow::record_reader::RecordReader;
20use crate::arrow::schema::parquet_to_arrow_field;
21use crate::basic::Type as PhysicalType;
22use crate::column::page::PageIterator;
23use crate::data_type::{DataType, Int96};
24use crate::errors::Result;
25use crate::schema::types::ColumnDescPtr;
26use arrow_array::{
27    Array, ArrayRef, BooleanArray, Date64Array, Decimal64Array, Decimal128Array, Decimal256Array,
28    Float32Array, Float64Array, Int8Array, Int16Array, Int32Array, Int64Array, PrimitiveArray,
29    UInt8Array, UInt16Array, builder::PrimitiveDictionaryBuilder, cast::AsArray, downcast_integer,
30    types::*,
31};
32use arrow_array::{
33    TimestampMicrosecondArray, TimestampMillisecondArray, TimestampNanosecondArray,
34    TimestampSecondArray, UInt32Array, UInt64Array,
35};
36use arrow_buffer::{BooleanBuffer, Buffer, NullBuffer, ScalarBuffer, i256};
37use arrow_schema::{DataType as ArrowType, TimeUnit};
38use std::any::Any;
39use std::sync::Arc;
40
41/// Provides conversion from `Vec<T>` to `Buffer`
42pub trait IntoBuffer {
43    fn into_buffer(self, target_type: &ArrowType) -> Buffer;
44}
45
46macro_rules! native_buffer {
47    ($($t:ty),*) => {
48        $(impl IntoBuffer for Vec<$t> {
49            fn into_buffer(self, _target_type: &ArrowType) -> Buffer {
50                Buffer::from_vec(self)
51            }
52        })*
53    };
54}
55native_buffer!(i8, i16, i32, i64, u8, u16, u32, u64, f32, f64);
56
57impl IntoBuffer for Vec<bool> {
58    fn into_buffer(self, _target_type: &ArrowType) -> Buffer {
59        BooleanBuffer::from(self.as_slice()).into_inner()
60    }
61}
62
63impl IntoBuffer for Vec<Int96> {
64    fn into_buffer(self, target_type: &ArrowType) -> Buffer {
65        let mut builder = Vec::with_capacity(self.len());
66        match target_type {
67            ArrowType::Timestamp(TimeUnit::Second, _) => {
68                builder.extend(self.iter().map(|x| x.to_seconds()));
69            }
70            ArrowType::Timestamp(TimeUnit::Millisecond, _) => {
71                builder.extend(self.iter().map(|x| x.to_millis()));
72            }
73            ArrowType::Timestamp(TimeUnit::Microsecond, _) => {
74                builder.extend(self.iter().map(|x| x.to_micros()));
75            }
76            ArrowType::Timestamp(TimeUnit::Nanosecond, _) => {
77                builder.extend(self.iter().map(|x| x.to_nanos()));
78            }
79            _ => unreachable!("Invalid target_type for Int96."),
80        }
81        Buffer::from_vec(builder)
82    }
83}
84
85/// Primitive array readers are leaves of array reader tree. They accept page iterator
86/// and read them into primitive arrays.
87pub struct PrimitiveArrayReader<T>
88where
89    T: DataType,
90    T::T: Copy + Default,
91    Vec<T::T>: IntoBuffer,
92{
93    data_type: ArrowType,
94    pages: Box<dyn PageIterator>,
95    def_levels_buffer: Option<Vec<i16>>,
96    rep_levels_buffer: Option<Vec<i16>>,
97    record_reader: RecordReader<T>,
98}
99
100impl<T> PrimitiveArrayReader<T>
101where
102    T: DataType,
103    T::T: Copy + Default,
104    Vec<T::T>: IntoBuffer,
105{
106    /// Construct primitive array reader.
107    ///
108    /// `padding_threshold` controls how null padding is applied. When
109    /// `None`, the reader pads all null positions (full padding). When
110    /// `Some(threshold)`, entries with `def < threshold` are excluded
111    /// from the value buffer (selective padding for list children).
112    pub fn new(
113        pages: Box<dyn PageIterator>,
114        column_desc: ColumnDescPtr,
115        arrow_type: Option<ArrowType>,
116        batch_size: usize,
117        padding_threshold: Option<i16>,
118    ) -> Result<Self> {
119        // Check if Arrow type is specified, else create it from Parquet type
120        let data_type = match arrow_type {
121            Some(t) => t,
122            None => parquet_to_arrow_field(column_desc.as_ref())?
123                .data_type()
124                .clone(),
125        };
126
127        let mut record_reader = RecordReader::<T>::new(column_desc, batch_size);
128        if let Some(threshold) = padding_threshold {
129            record_reader.set_padding_threshold(threshold);
130        }
131
132        Ok(Self {
133            data_type,
134            pages,
135            def_levels_buffer: None,
136            rep_levels_buffer: None,
137            record_reader,
138        })
139    }
140}
141
142/// Implementation of primitive array reader.
143impl<T> ArrayReader for PrimitiveArrayReader<T>
144where
145    T: DataType,
146    T::T: Copy + Default,
147    Vec<T::T>: IntoBuffer,
148{
149    fn as_any(&self) -> &dyn Any {
150        self
151    }
152
153    /// Returns data type of primitive array.
154    fn get_data_type(&self) -> &ArrowType {
155        &self.data_type
156    }
157
158    fn read_records(&mut self, batch_size: usize) -> Result<usize> {
159        read_records(&mut self.record_reader, self.pages.as_mut(), batch_size)
160    }
161
162    fn consume_batch(&mut self) -> Result<ArrayRef> {
163        let target_type = &self.data_type;
164
165        // Convert physical data to equivalent arrow type, and then perform
166        // coercion as needed
167        let len = self.record_reader.values_written();
168
169        let record_data = self
170            .record_reader
171            .consume_record_data()
172            .into_buffer(target_type);
173
174        let nulls = self
175            .record_reader
176            .consume_compact_bitmap()
177            .and_then(|b| NullBuffer::from_unsliced_buffer(b, len));
178
179        let array: ArrayRef = match T::get_physical_type() {
180            PhysicalType::BOOLEAN => Arc::new(BooleanArray::new(
181                BooleanBuffer::new(record_data, 0, len),
182                nulls,
183            )),
184            PhysicalType::INT32 => Arc::new(Int32Array::new(
185                ScalarBuffer::new(record_data, 0, len),
186                nulls,
187            )),
188            PhysicalType::INT64 => Arc::new(Int64Array::new(
189                ScalarBuffer::new(record_data, 0, len),
190                nulls,
191            )),
192            PhysicalType::FLOAT => Arc::new(Float32Array::new(
193                ScalarBuffer::new(record_data, 0, len),
194                nulls,
195            )),
196            PhysicalType::DOUBLE => Arc::new(Float64Array::new(
197                ScalarBuffer::new(record_data, 0, len),
198                nulls,
199            )),
200            PhysicalType::INT96 => Arc::new(Int64Array::new(
201                ScalarBuffer::new(record_data, 0, len),
202                nulls,
203            )),
204            PhysicalType::BYTE_ARRAY | PhysicalType::FIXED_LEN_BYTE_ARRAY => {
205                unreachable!("PrimitiveArrayReaders don't support complex physical types");
206            }
207        };
208
209        // Coerce the arrow type to the desired array type
210        let array = coerce_array(array, target_type)?;
211
212        // save definition and repetition buffers
213        self.def_levels_buffer = self.record_reader.consume_def_levels();
214        self.rep_levels_buffer = self.record_reader.consume_rep_levels();
215        self.record_reader.reset();
216        Ok(array)
217    }
218
219    fn skip_records(&mut self, num_records: usize) -> Result<usize> {
220        skip_records(&mut self.record_reader, self.pages.as_mut(), num_records)
221    }
222
223    fn get_def_levels(&self) -> Option<&[i16]> {
224        self.def_levels_buffer.as_deref()
225    }
226
227    fn get_rep_levels(&self) -> Option<&[i16]> {
228        self.rep_levels_buffer.as_deref()
229    }
230
231    fn max_def_level(&self) -> i16 {
232        self.record_reader.max_def_level()
233    }
234}
235
236/// Coerce the parquet physical type array to the target type
237///
238/// This should match the logic in schema::primitive::apply_hint
239fn coerce_array(array: ArrayRef, target_type: &ArrowType) -> Result<ArrayRef> {
240    if let ArrowType::Dictionary(key_type, value_type) = target_type {
241        let dictionary = pack_dictionary(key_type, array.as_ref())?;
242        let any_dictionary = dictionary.as_any_dictionary();
243
244        let coerced_values =
245            coerce_array(Arc::clone(any_dictionary.values()), value_type.as_ref())?;
246
247        return Ok(any_dictionary.with_values(coerced_values));
248    }
249
250    match array.data_type() {
251        ArrowType::Int32 => coerce_i32(array.as_primitive(), target_type),
252        ArrowType::Int64 => coerce_i64(array.as_primitive(), target_type),
253        ArrowType::Boolean | ArrowType::Float32 | ArrowType::Float64 => Ok(array),
254        _ => unreachable!("Cannot coerce array of type {}", array.data_type()),
255    }
256}
257
258fn coerce_i32(array: &Int32Array, target_type: &ArrowType) -> Result<ArrayRef> {
259    Ok(match target_type {
260        ArrowType::UInt8 => {
261            let array = array.unary(|i| i as u8) as UInt8Array;
262            Arc::new(array) as ArrayRef
263        }
264        ArrowType::Int8 => {
265            let array = array.unary(|i| i as i8) as Int8Array;
266            Arc::new(array) as ArrayRef
267        }
268        ArrowType::UInt16 => {
269            let array = array.unary(|i| i as u16) as UInt16Array;
270            Arc::new(array) as ArrayRef
271        }
272        ArrowType::Int16 => {
273            let array = array.unary(|i| i as i16) as Int16Array;
274            Arc::new(array) as ArrayRef
275        }
276        ArrowType::Int32 => Arc::new(array.clone()),
277        // follow C++ implementation and use overflow/reinterpret cast from  i32 to u32 which will map
278        // `i32::MIN..0` to `(i32::MAX as u32)..u32::MAX`
279        ArrowType::UInt32 => Arc::new(UInt32Array::new(
280            array.values().inner().clone().into(),
281            array.nulls().cloned(),
282        )) as ArrayRef,
283        ArrowType::Date32 => Arc::new(array.reinterpret_cast::<Date32Type>()) as _,
284        ArrowType::Date64 => {
285            let array: Date64Array = array.unary(|x| x as i64 * 86_400_000);
286            Arc::new(array) as ArrayRef
287        }
288        ArrowType::Time32(TimeUnit::Second) => {
289            Arc::new(array.reinterpret_cast::<Time32SecondType>()) as ArrayRef
290        }
291        ArrowType::Time32(TimeUnit::Millisecond) => {
292            Arc::new(array.reinterpret_cast::<Time32MillisecondType>()) as ArrayRef
293        }
294        ArrowType::Timestamp(time_unit, timezone) => match time_unit {
295            TimeUnit::Second => {
296                let array: TimestampSecondArray = array
297                    .unary(|x| x as i64)
298                    .with_timezone_opt(timezone.clone());
299                Arc::new(array) as _
300            }
301            TimeUnit::Millisecond => {
302                let array: TimestampMillisecondArray = array
303                    .unary(|x| x as i64)
304                    .with_timezone_opt(timezone.clone());
305                Arc::new(array) as _
306            }
307            TimeUnit::Microsecond => {
308                let array: TimestampMicrosecondArray = array
309                    .unary(|x| x as i64)
310                    .with_timezone_opt(timezone.clone());
311                Arc::new(array) as _
312            }
313            TimeUnit::Nanosecond => {
314                let array: TimestampNanosecondArray = array
315                    .unary(|x| x as i64)
316                    .with_timezone_opt(timezone.clone());
317                Arc::new(array) as _
318            }
319        },
320        ArrowType::Decimal32(p, s) => {
321            let array = array
322                .reinterpret_cast::<Decimal32Type>()
323                .with_precision_and_scale(*p, *s)?;
324            Arc::new(array) as ArrayRef
325        }
326        ArrowType::Decimal64(p, s) => {
327            let array: Decimal64Array =
328                array.unary(|i| i as i64).with_precision_and_scale(*p, *s)?;
329            Arc::new(array) as ArrayRef
330        }
331        ArrowType::Decimal128(p, s) => {
332            let array: Decimal128Array = array
333                .unary(|i| i as i128)
334                .with_precision_and_scale(*p, *s)?;
335            Arc::new(array) as ArrayRef
336        }
337        ArrowType::Decimal256(p, s) => {
338            let array: Decimal256Array = array
339                .unary(|i| i256::from_i128(i as i128))
340                .with_precision_and_scale(*p, *s)?;
341            Arc::new(array) as ArrayRef
342        }
343        _ => unreachable!("Cannot coerce i32 to {target_type}"),
344    })
345}
346
347fn coerce_i64(array: &Int64Array, target_type: &ArrowType) -> Result<ArrayRef> {
348    Ok(match target_type {
349        ArrowType::Int64 => Arc::new(array.clone()) as _,
350        // follow C++ implementation and use overflow/reinterpret cast from i64 to u64 which will map
351        // `i64::MIN..0` to `(i64::MAX as u64)..u64::MAX`
352        ArrowType::UInt64 => Arc::new(UInt64Array::new(
353            array.values().inner().clone().into(),
354            array.nulls().cloned(),
355        )) as ArrayRef,
356        ArrowType::Date64 => Arc::new(array.reinterpret_cast::<Date64Type>()) as _,
357        ArrowType::Time64(TimeUnit::Microsecond) => {
358            Arc::new(array.reinterpret_cast::<Time64MicrosecondType>()) as _
359        }
360        ArrowType::Time64(TimeUnit::Nanosecond) => {
361            Arc::new(array.reinterpret_cast::<Time64NanosecondType>()) as _
362        }
363        ArrowType::Duration(unit) => match unit {
364            TimeUnit::Second => Arc::new(array.reinterpret_cast::<DurationSecondType>()) as _,
365            TimeUnit::Millisecond => {
366                Arc::new(array.reinterpret_cast::<DurationMillisecondType>()) as _
367            }
368            TimeUnit::Microsecond => {
369                Arc::new(array.reinterpret_cast::<DurationMicrosecondType>()) as _
370            }
371            TimeUnit::Nanosecond => {
372                Arc::new(array.reinterpret_cast::<DurationNanosecondType>()) as _
373            }
374        },
375        ArrowType::Timestamp(time_unit, timezone) => match time_unit {
376            TimeUnit::Second => {
377                let array = array
378                    .reinterpret_cast::<TimestampSecondType>()
379                    .with_timezone_opt(timezone.clone());
380                Arc::new(array) as _
381            }
382            TimeUnit::Millisecond => {
383                let array = array
384                    .reinterpret_cast::<TimestampMillisecondType>()
385                    .with_timezone_opt(timezone.clone());
386                Arc::new(array) as _
387            }
388            TimeUnit::Microsecond => {
389                let array = array
390                    .reinterpret_cast::<TimestampMicrosecondType>()
391                    .with_timezone_opt(timezone.clone());
392                Arc::new(array) as _
393            }
394            TimeUnit::Nanosecond => {
395                let array = array
396                    .reinterpret_cast::<TimestampNanosecondType>()
397                    .with_timezone_opt(timezone.clone());
398                Arc::new(array) as _
399            }
400        },
401        ArrowType::Decimal64(p, s) => {
402            let array = array
403                .reinterpret_cast::<Decimal64Type>()
404                .with_precision_and_scale(*p, *s)?;
405            Arc::new(array) as _
406        }
407        ArrowType::Decimal128(p, s) => {
408            let array: Decimal128Array = array
409                .unary(|i| i as i128)
410                .with_precision_and_scale(*p, *s)?;
411            Arc::new(array) as _
412        }
413        ArrowType::Decimal256(p, s) => {
414            let array: Decimal256Array = array
415                .unary(|i| i256::from_i128(i as i128))
416                .with_precision_and_scale(*p, *s)?;
417            Arc::new(array) as _
418        }
419        _ => unreachable!("Cannot coerce i64 to {target_type}"),
420    })
421}
422
423macro_rules! pack_dictionary_helper {
424    ($t:ty, $values:ident) => {
425        match $values.data_type() {
426            ArrowType::Int32 => pack_dictionary_impl::<$t, Int32Type>($values.as_primitive()),
427            ArrowType::Int64 => pack_dictionary_impl::<$t, Int64Type>($values.as_primitive()),
428            ArrowType::Float32 => pack_dictionary_impl::<$t, Float32Type>($values.as_primitive()),
429            ArrowType::Float64 => pack_dictionary_impl::<$t, Float64Type>($values.as_primitive()),
430            _ => unreachable!("Invalid physical type"),
431        }
432    };
433}
434
435fn pack_dictionary(key: &ArrowType, values: &dyn Array) -> Result<ArrayRef> {
436    downcast_integer! {
437        key => (pack_dictionary_helper, values),
438        _ => unreachable!("Invalid key type"),
439    }
440}
441
442fn pack_dictionary_impl<K: ArrowDictionaryKeyType, V: ArrowPrimitiveType>(
443    values: &PrimitiveArray<V>,
444) -> Result<ArrayRef> {
445    let mut builder = PrimitiveDictionaryBuilder::<K, V>::with_capacity(1024, values.len());
446    builder.extend(values);
447    Ok(Arc::new(builder.finish()))
448}
449
450#[cfg(test)]
451mod tests {
452    use super::*;
453    use crate::arrow::array_reader::test_util::EmptyPageIterator;
454    use crate::arrow::arrow_reader::DEFAULT_BATCH_SIZE;
455    use crate::basic::Encoding;
456    use crate::column::page::Page;
457    use crate::data_type::{Int32Type, Int64Type};
458    use crate::schema::parser::parse_message_type;
459    use crate::schema::types::SchemaDescriptor;
460    use crate::util::InMemoryPageIterator;
461    use crate::util::test_common::rand_gen::make_pages;
462    use arrow::datatypes::ArrowPrimitiveType;
463    use arrow_array::{Array, Date32Array, PrimitiveArray};
464
465    use arrow::datatypes::DataType::{Date32, Decimal128};
466    use rand::distr::uniform::SampleUniform;
467    use std::collections::VecDeque;
468
469    #[allow(clippy::too_many_arguments)]
470    fn make_column_chunks<T: DataType>(
471        column_desc: ColumnDescPtr,
472        encoding: Encoding,
473        num_levels: usize,
474        min_value: T::T,
475        max_value: T::T,
476        def_levels: &mut Vec<i16>,
477        rep_levels: &mut Vec<i16>,
478        values: &mut Vec<T::T>,
479        page_lists: &mut Vec<Vec<Page>>,
480        use_v2: bool,
481        num_chunks: usize,
482    ) where
483        T::T: PartialOrd + SampleUniform + Copy,
484    {
485        for _i in 0..num_chunks {
486            let mut pages = VecDeque::new();
487            let mut data = Vec::new();
488            let mut page_def_levels = Vec::new();
489            let mut page_rep_levels = Vec::new();
490
491            make_pages::<T>(
492                column_desc.clone(),
493                encoding,
494                1,
495                num_levels,
496                min_value,
497                max_value,
498                &mut page_def_levels,
499                &mut page_rep_levels,
500                &mut data,
501                &mut pages,
502                use_v2,
503            );
504
505            def_levels.append(&mut page_def_levels);
506            rep_levels.append(&mut page_rep_levels);
507            values.append(&mut data);
508            page_lists.push(Vec::from(pages));
509        }
510    }
511
512    #[test]
513    fn test_primitive_array_reader_empty_pages() {
514        // Construct column schema
515        let message_type = "
516        message test_schema {
517          REQUIRED INT32 leaf;
518        }
519        ";
520
521        let schema = parse_message_type(message_type)
522            .map(|t| Arc::new(SchemaDescriptor::new(Arc::new(t))))
523            .unwrap();
524
525        let mut array_reader = PrimitiveArrayReader::<Int32Type>::new(
526            Box::<EmptyPageIterator>::default(),
527            schema.column(0),
528            None,
529            DEFAULT_BATCH_SIZE,
530            None,
531        )
532        .unwrap();
533
534        // expect no values to be read
535        let array = array_reader.next_batch(50).unwrap();
536        assert!(array.is_empty());
537    }
538
539    #[test]
540    fn test_primitive_array_reader_data() {
541        // Construct column schema
542        let message_type = "
543        message test_schema {
544          REQUIRED INT32 leaf;
545        }
546        ";
547
548        let schema = parse_message_type(message_type)
549            .map(|t| Arc::new(SchemaDescriptor::new(Arc::new(t))))
550            .unwrap();
551
552        let column_desc = schema.column(0);
553
554        // Construct page iterator
555        {
556            let mut data = Vec::new();
557            let mut page_lists = Vec::new();
558            make_column_chunks::<Int32Type>(
559                column_desc.clone(),
560                Encoding::PLAIN,
561                100,
562                1,
563                200,
564                &mut Vec::new(),
565                &mut Vec::new(),
566                &mut data,
567                &mut page_lists,
568                true,
569                2,
570            );
571            let page_iterator = InMemoryPageIterator::new(page_lists);
572
573            let mut array_reader = PrimitiveArrayReader::<Int32Type>::new(
574                Box::new(page_iterator),
575                column_desc,
576                None,
577                DEFAULT_BATCH_SIZE,
578                None,
579            )
580            .unwrap();
581
582            // Read first 50 values, which are all from the first column chunk
583            let array = array_reader.next_batch(50).unwrap();
584            let array = array.as_any().downcast_ref::<Int32Array>().unwrap();
585
586            assert_eq!(&Int32Array::from(data[0..50].to_vec()), array);
587
588            // Read next 100 values, the first 50 ones are from the first column chunk,
589            // and the last 50 ones are from the second column chunk
590            let array = array_reader.next_batch(100).unwrap();
591            let array = array.as_any().downcast_ref::<Int32Array>().unwrap();
592
593            assert_eq!(&Int32Array::from(data[50..150].to_vec()), array);
594
595            // Try to read 100 values, however there are only 50 values
596            let array = array_reader.next_batch(100).unwrap();
597            let array = array.as_any().downcast_ref::<Int32Array>().unwrap();
598
599            assert_eq!(&Int32Array::from(data[150..200].to_vec()), array);
600        }
601    }
602
603    macro_rules! test_primitive_array_reader_one_type {
604        (
605            $arrow_parquet_type:ty,
606            $physical_type:expr,
607            $converted_type_str:expr,
608            $result_arrow_type:ty,
609            $result_arrow_cast_type:ty,
610            $result_primitive_type:ty
611            $(, $timezone:expr)?
612        ) => {{
613            let message_type = format!(
614                "
615            message test_schema {{
616              REQUIRED {:?} leaf ({});
617          }}
618            ",
619                $physical_type, $converted_type_str
620            );
621            let schema = parse_message_type(&message_type)
622                .map(|t| Arc::new(SchemaDescriptor::new(Arc::new(t))))
623                .unwrap();
624
625            let column_desc = schema.column(0);
626
627            // Construct page iterator
628            {
629                let mut data = Vec::new();
630                let mut page_lists = Vec::new();
631                make_column_chunks::<$arrow_parquet_type>(
632                    column_desc.clone(),
633                    Encoding::PLAIN,
634                    100,
635                    1,
636                    200,
637                    &mut Vec::new(),
638                    &mut Vec::new(),
639                    &mut data,
640                    &mut page_lists,
641                    true,
642                    2,
643                );
644                let page_iterator = InMemoryPageIterator::new(page_lists);
645                let mut array_reader = PrimitiveArrayReader::<$arrow_parquet_type>::new(
646                    Box::new(page_iterator),
647                    column_desc.clone(),
648                    None,
649                    DEFAULT_BATCH_SIZE,
650                    None,
651                )
652                .expect("Unable to get array reader");
653
654                let array = array_reader
655                    .next_batch(50)
656                    .expect("Unable to get batch from reader");
657
658                let result_data_type = <$result_arrow_type>::DATA_TYPE;
659                let array = array
660                    .as_any()
661                    .downcast_ref::<PrimitiveArray<$result_arrow_type>>()
662                    .expect(
663                        format!(
664                            "Unable to downcast {:?} to {:?}",
665                            array.data_type(),
666                            result_data_type
667                        )
668                        .as_str(),
669                    )
670                    $(.clone().with_timezone($timezone))?
671                    ;
672
673                // create expected array as primitive, and cast to result type
674                #[expect(
675                    trivial_numeric_casts,
676                    reason = "the cast is a no-op when the source and result types are the same"
677                )]
678                let expected = PrimitiveArray::<$result_arrow_cast_type>::from(
679                    data[0..50]
680                        .iter()
681                        .map(|x| *x as $result_primitive_type)
682                        .collect::<Vec<$result_primitive_type>>(),
683                );
684                let expected = Arc::new(expected) as ArrayRef;
685                let expected = arrow::compute::cast(&expected, &result_data_type)
686                    .expect("Unable to cast expected array");
687                assert_eq!(expected.data_type(), &result_data_type);
688                let expected = expected
689                    .as_any()
690                    .downcast_ref::<PrimitiveArray<$result_arrow_type>>()
691                    .expect(
692                        format!(
693                            "Unable to downcast expected {:?} to {:?}",
694                            expected.data_type(),
695                            result_data_type
696                        )
697                        .as_str(),
698                    )
699                    $(.clone().with_timezone($timezone))?
700                    ;
701                assert_eq!(expected, array);
702            }
703        }};
704    }
705
706    #[test]
707    fn test_primitive_array_reader_temporal_types() {
708        test_primitive_array_reader_one_type!(
709            crate::data_type::Int32Type,
710            PhysicalType::INT32,
711            "DATE",
712            arrow::datatypes::Date32Type,
713            arrow::datatypes::Int32Type,
714            i32
715        );
716        test_primitive_array_reader_one_type!(
717            crate::data_type::Int32Type,
718            PhysicalType::INT32,
719            "TIME_MILLIS",
720            arrow::datatypes::Time32MillisecondType,
721            arrow::datatypes::Int32Type,
722            i32
723        );
724        test_primitive_array_reader_one_type!(
725            crate::data_type::Int64Type,
726            PhysicalType::INT64,
727            "TIME_MICROS",
728            arrow::datatypes::Time64MicrosecondType,
729            arrow::datatypes::Int64Type,
730            i64
731        );
732        test_primitive_array_reader_one_type!(
733            crate::data_type::Int64Type,
734            PhysicalType::INT64,
735            "TIMESTAMP_MILLIS",
736            arrow::datatypes::TimestampMillisecondType,
737            arrow::datatypes::Int64Type,
738            i64,
739            "UTC"
740        );
741        test_primitive_array_reader_one_type!(
742            crate::data_type::Int64Type,
743            PhysicalType::INT64,
744            "TIMESTAMP_MICROS",
745            arrow::datatypes::TimestampMicrosecondType,
746            arrow::datatypes::Int64Type,
747            i64,
748            "UTC"
749        );
750    }
751
752    #[test]
753    fn test_primitive_array_reader_def_and_rep_levels() {
754        // Construct column schema
755        let message_type = "
756        message test_schema {
757            REPEATED Group test_mid {
758                OPTIONAL INT32 leaf;
759            }
760        }
761        ";
762
763        let schema = parse_message_type(message_type)
764            .map(|t| Arc::new(SchemaDescriptor::new(Arc::new(t))))
765            .unwrap();
766
767        let column_desc = schema.column(0);
768
769        // Construct page iterator
770        {
771            let mut def_levels = Vec::new();
772            let mut rep_levels = Vec::new();
773            let mut page_lists = Vec::new();
774            make_column_chunks::<Int32Type>(
775                column_desc.clone(),
776                Encoding::PLAIN,
777                100,
778                1,
779                200,
780                &mut def_levels,
781                &mut rep_levels,
782                &mut Vec::new(),
783                &mut page_lists,
784                true,
785                2,
786            );
787
788            let page_iterator = InMemoryPageIterator::new(page_lists);
789
790            let mut array_reader = PrimitiveArrayReader::<Int32Type>::new(
791                Box::new(page_iterator),
792                column_desc,
793                None,
794                DEFAULT_BATCH_SIZE,
795                None,
796            )
797            .unwrap();
798
799            let mut accu_len: usize = 0;
800
801            // Read first 50 values, which are all from the first column chunk
802            let array = array_reader.next_batch(50).unwrap();
803            assert_eq!(
804                Some(&def_levels[accu_len..(accu_len + array.len())]),
805                array_reader.get_def_levels()
806            );
807            assert_eq!(
808                Some(&rep_levels[accu_len..(accu_len + array.len())]),
809                array_reader.get_rep_levels()
810            );
811            accu_len += array.len();
812
813            // Read next 100 values, the first 50 ones are from the first column chunk,
814            // and the last 50 ones are from the second column chunk
815            let array = array_reader.next_batch(100).unwrap();
816            assert_eq!(
817                Some(&def_levels[accu_len..(accu_len + array.len())]),
818                array_reader.get_def_levels()
819            );
820            assert_eq!(
821                Some(&rep_levels[accu_len..(accu_len + array.len())]),
822                array_reader.get_rep_levels()
823            );
824            accu_len += array.len();
825
826            // Try to read 100 values, however there are only 50 values
827            let array = array_reader.next_batch(100).unwrap();
828            assert_eq!(
829                Some(&def_levels[accu_len..(accu_len + array.len())]),
830                array_reader.get_def_levels()
831            );
832            assert_eq!(
833                Some(&rep_levels[accu_len..(accu_len + array.len())]),
834                array_reader.get_rep_levels()
835            );
836        }
837    }
838
839    #[test]
840    fn test_primitive_array_reader_decimal_types() {
841        // parquet `INT32` to decimal
842        let message_type = "
843            message test_schema {
844                REQUIRED INT32 decimal1 (DECIMAL(8,2));
845        }
846        ";
847        let schema = parse_message_type(message_type)
848            .map(|t| Arc::new(SchemaDescriptor::new(Arc::new(t))))
849            .unwrap();
850        let column_desc = schema.column(0);
851
852        // create the array reader
853        {
854            let mut data = Vec::new();
855            let mut page_lists = Vec::new();
856            make_column_chunks::<Int32Type>(
857                column_desc.clone(),
858                Encoding::PLAIN,
859                100,
860                -99999999,
861                99999999,
862                &mut Vec::new(),
863                &mut Vec::new(),
864                &mut data,
865                &mut page_lists,
866                true,
867                2,
868            );
869            let page_iterator = InMemoryPageIterator::new(page_lists);
870
871            let mut array_reader = PrimitiveArrayReader::<Int32Type>::new(
872                Box::new(page_iterator),
873                column_desc,
874                None,
875                DEFAULT_BATCH_SIZE,
876                None,
877            )
878            .unwrap();
879
880            // read data from the reader
881            // the data type is decimal(8,2)
882            let array = array_reader.next_batch(50).unwrap();
883            assert_eq!(array.data_type(), &Decimal128(8, 2));
884            let array = array.as_any().downcast_ref::<Decimal128Array>().unwrap();
885            let data_decimal_array = data[0..50]
886                .iter()
887                .copied()
888                .map(|v| Some(v as i128))
889                .collect::<Decimal128Array>()
890                .with_precision_and_scale(8, 2)
891                .unwrap();
892            assert_eq!(array, &data_decimal_array);
893
894            // not equal with different data type(precision and scale)
895            let data_decimal_array = data[0..50]
896                .iter()
897                .copied()
898                .map(|v| Some(v as i128))
899                .collect::<Decimal128Array>()
900                .with_precision_and_scale(9, 0)
901                .unwrap();
902            assert_ne!(array, &data_decimal_array)
903        }
904
905        // parquet `INT64` to decimal
906        let message_type = "
907            message test_schema {
908                REQUIRED INT64 decimal1 (DECIMAL(18,4));
909        }
910        ";
911        let schema = parse_message_type(message_type)
912            .map(|t| Arc::new(SchemaDescriptor::new(Arc::new(t))))
913            .unwrap();
914        let column_desc = schema.column(0);
915
916        // create the array reader
917        {
918            let mut data = Vec::new();
919            let mut page_lists = Vec::new();
920            make_column_chunks::<Int64Type>(
921                column_desc.clone(),
922                Encoding::PLAIN,
923                100,
924                -999999999999999999,
925                999999999999999999,
926                &mut Vec::new(),
927                &mut Vec::new(),
928                &mut data,
929                &mut page_lists,
930                true,
931                2,
932            );
933            let page_iterator = InMemoryPageIterator::new(page_lists);
934
935            let mut array_reader = PrimitiveArrayReader::<Int64Type>::new(
936                Box::new(page_iterator),
937                column_desc,
938                None,
939                DEFAULT_BATCH_SIZE,
940                None,
941            )
942            .unwrap();
943
944            // read data from the reader
945            // the data type is decimal(18,4)
946            let array = array_reader.next_batch(50).unwrap();
947            assert_eq!(array.data_type(), &Decimal128(18, 4));
948            let array = array.as_any().downcast_ref::<Decimal128Array>().unwrap();
949            let data_decimal_array = data[0..50]
950                .iter()
951                .copied()
952                .map(|v| Some(v as i128))
953                .collect::<Decimal128Array>()
954                .with_precision_and_scale(18, 4)
955                .unwrap();
956            assert_eq!(array, &data_decimal_array);
957
958            // not equal with different data type(precision and scale)
959            let data_decimal_array = data[0..50]
960                .iter()
961                .copied()
962                .map(|v| Some(v as i128))
963                .collect::<Decimal128Array>()
964                .with_precision_and_scale(34, 0)
965                .unwrap();
966            assert_ne!(array, &data_decimal_array)
967        }
968    }
969
970    #[test]
971    fn test_primitive_array_reader_date32_type() {
972        // parquet `INT32` to date
973        let message_type = "
974            message test_schema {
975                REQUIRED INT32 date1 (DATE);
976        }
977        ";
978        let schema = parse_message_type(message_type)
979            .map(|t| Arc::new(SchemaDescriptor::new(Arc::new(t))))
980            .unwrap();
981        let column_desc = schema.column(0);
982
983        // create the array reader
984        {
985            let mut data = Vec::new();
986            let mut page_lists = Vec::new();
987            make_column_chunks::<Int32Type>(
988                column_desc.clone(),
989                Encoding::PLAIN,
990                100,
991                -99999999,
992                99999999,
993                &mut Vec::new(),
994                &mut Vec::new(),
995                &mut data,
996                &mut page_lists,
997                true,
998                2,
999            );
1000            let page_iterator = InMemoryPageIterator::new(page_lists);
1001
1002            let mut array_reader = PrimitiveArrayReader::<Int32Type>::new(
1003                Box::new(page_iterator),
1004                column_desc,
1005                None,
1006                DEFAULT_BATCH_SIZE,
1007                None,
1008            )
1009            .unwrap();
1010
1011            // read data from the reader
1012            // the data type is date
1013            let array = array_reader.next_batch(50).unwrap();
1014            assert_eq!(array.data_type(), &Date32);
1015            let array = array.as_any().downcast_ref::<Date32Array>().unwrap();
1016            let data_date_array = data[0..50]
1017                .iter()
1018                .copied()
1019                .map(Some)
1020                .collect::<Date32Array>();
1021            assert_eq!(array, &data_date_array);
1022        }
1023    }
1024}