Skip to main content

risingwave_common/array/arrow/
arrow_impl.rs

1// Copyright 2023 RisingWave Labs
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Converts between arrays and Apache Arrow arrays.
16//!
17//! This file acts as a template file for conversion code between
18//! arrays and different version of Apache Arrow.
19//!
20//! The conversion logic will be implemented for the arrow version specified in the outer mod by
21//! `super::arrow_xxx`, such as `super::arrow_array`.
22//!
23//! When we want to implement the conversion logic for an arrow version, we first
24//! create a new mod file, and rename the corresponding arrow package name to `arrow_xxx`
25//! using the `use` clause, and then declare a sub-mod and set its file path with attribute
26//! `#[path = "./arrow_impl.rs"]` so that the code in this template file can be embedded to
27//! the new mod file, and the conversion logic can be implemented for the corresponding arrow
28//! version.
29//!
30//! Example can be seen in `arrow_default.rs`, which is also as followed:
31//! ```ignore
32//! use {arrow_array, arrow_buffer, arrow_cast, arrow_schema};
33//!
34//! #[allow(clippy::duplicate_mod)]
35//! #[path = "./arrow_impl.rs"]
36//! mod arrow_impl;
37//! ```
38
39// Is this a bug? Why do we have these lints?
40#![allow(unused_imports)]
41#![allow(dead_code)]
42
43use std::fmt::Write;
44
45use arrow_array::array;
46use arrow_array::cast::AsArray;
47use arrow_buffer::OffsetBuffer;
48use arrow_schema::TimeUnit;
49use chrono::{DateTime, Timelike as _};
50use itertools::Itertools;
51
52use super::arrow_schema::IntervalUnit;
53// This is important because we want to use the arrow version specified by the outer mod.
54use super::{ArrowIntervalType, arrow_array, arrow_buffer, arrow_cast, arrow_schema};
55// Other import should always use the absolute path.
56use crate::array::*;
57use crate::types::{DataType as RwDataType, Scalar, *};
58use crate::util::iter_util::ZipEqFast;
59
60/// Defines how to convert RisingWave arrays to Arrow arrays.
61///
62/// This trait allows for customized conversion logic for different external systems using Arrow.
63/// The default implementation is based on the `From` implemented in this mod.
64pub trait ToArrow {
65    /// Converts RisingWave `DataChunk` to Arrow `RecordBatch` with specified schema.
66    ///
67    /// This function will try to convert the array if the type is not same with the schema.
68    fn to_record_batch(
69        &self,
70        schema: arrow_schema::SchemaRef,
71        chunk: &DataChunk,
72    ) -> Result<arrow_array::RecordBatch, ArrayError> {
73        // compact the chunk if it's not compacted
74        if !chunk.is_vis_compacted() {
75            let c = chunk.clone();
76            return self.to_record_batch(schema, &c.compact_vis());
77        }
78
79        // convert each column to arrow array
80        let columns: Vec<_> = chunk
81            .columns()
82            .iter()
83            .zip_eq_fast(schema.fields().iter())
84            .map(|(column, field)| self.to_array(field.data_type(), column))
85            .try_collect()?;
86
87        // create record batch
88        let opts =
89            arrow_array::RecordBatchOptions::default().with_row_count(Some(chunk.capacity()));
90        arrow_array::RecordBatch::try_new_with_options(schema, columns, &opts)
91            .map_err(ArrayError::to_arrow)
92    }
93
94    /// Converts RisingWave array to Arrow array.
95    fn to_array(
96        &self,
97        data_type: &arrow_schema::DataType,
98        array: &ArrayImpl,
99    ) -> Result<arrow_array::ArrayRef, ArrayError> {
100        let arrow_array = match array {
101            ArrayImpl::Bool(array) => self.bool_to_arrow(array),
102            ArrayImpl::Int16(array) => self.int16_to_arrow(array),
103            ArrayImpl::Int32(array) => self.int32_to_arrow(array),
104            ArrayImpl::Int64(array) => self.int64_to_arrow(array),
105            ArrayImpl::Int256(array) => self.int256_to_arrow(array),
106            ArrayImpl::Float32(array) => self.float32_to_arrow(array),
107            ArrayImpl::Float64(array) => self.float64_to_arrow(array),
108            ArrayImpl::Date(array) => self.date_to_arrow(array),
109            ArrayImpl::Time(array) => self.time_to_arrow(array),
110            ArrayImpl::Timestamp(array) => self.timestamp_to_arrow(array),
111            ArrayImpl::Timestamptz(array) => self.timestamptz_to_arrow(array),
112            ArrayImpl::Interval(array) => self.interval_to_arrow(array),
113            ArrayImpl::Utf8(array) => self.utf8_to_arrow(array),
114            ArrayImpl::Bytea(array) => self.bytea_to_arrow(array),
115            ArrayImpl::Decimal(array) => self.decimal_to_arrow(data_type, array),
116            ArrayImpl::Jsonb(array) => self.jsonb_to_arrow(array),
117            ArrayImpl::Serial(array) => self.serial_to_arrow(array),
118            ArrayImpl::List(array) => self.list_to_arrow(data_type, array),
119            ArrayImpl::Struct(array) => self.struct_to_arrow(data_type, array),
120            ArrayImpl::Map(array) => self.map_to_arrow(data_type, array),
121            ArrayImpl::Vector(inner) => self.vector_to_arrow(data_type, inner),
122        }?;
123        if arrow_array.data_type() != data_type {
124            arrow_cast::cast(&arrow_array, data_type).map_err(ArrayError::to_arrow)
125        } else {
126            Ok(arrow_array)
127        }
128    }
129
130    #[inline]
131    fn bool_to_arrow(&self, array: &BoolArray) -> Result<arrow_array::ArrayRef, ArrayError> {
132        Ok(Arc::new(arrow_array::BooleanArray::from(array)))
133    }
134
135    #[inline]
136    fn int16_to_arrow(&self, array: &I16Array) -> Result<arrow_array::ArrayRef, ArrayError> {
137        Ok(Arc::new(arrow_array::Int16Array::from(array)))
138    }
139
140    #[inline]
141    fn int32_to_arrow(&self, array: &I32Array) -> Result<arrow_array::ArrayRef, ArrayError> {
142        Ok(Arc::new(arrow_array::Int32Array::from(array)))
143    }
144
145    #[inline]
146    fn int64_to_arrow(&self, array: &I64Array) -> Result<arrow_array::ArrayRef, ArrayError> {
147        Ok(Arc::new(arrow_array::Int64Array::from(array)))
148    }
149
150    #[inline]
151    fn float32_to_arrow(&self, array: &F32Array) -> Result<arrow_array::ArrayRef, ArrayError> {
152        Ok(Arc::new(arrow_array::Float32Array::from(array)))
153    }
154
155    #[inline]
156    fn float64_to_arrow(&self, array: &F64Array) -> Result<arrow_array::ArrayRef, ArrayError> {
157        Ok(Arc::new(arrow_array::Float64Array::from(array)))
158    }
159
160    #[inline]
161    fn utf8_to_arrow(&self, array: &Utf8Array) -> Result<arrow_array::ArrayRef, ArrayError> {
162        Ok(Arc::new(arrow_array::StringArray::from(array)))
163    }
164
165    #[inline]
166    fn int256_to_arrow(&self, array: &Int256Array) -> Result<arrow_array::ArrayRef, ArrayError> {
167        Ok(Arc::new(arrow_array::Decimal256Array::from(array)))
168    }
169
170    #[inline]
171    fn date_to_arrow(&self, array: &DateArray) -> Result<arrow_array::ArrayRef, ArrayError> {
172        Ok(Arc::new(arrow_array::Date32Array::try_from(array)?))
173    }
174
175    #[inline]
176    fn timestamp_to_arrow(
177        &self,
178        array: &TimestampArray,
179    ) -> Result<arrow_array::ArrayRef, ArrayError> {
180        Ok(Arc::new(arrow_array::TimestampMicrosecondArray::try_from(
181            array,
182        )?))
183    }
184
185    #[inline]
186    fn timestamptz_to_arrow(
187        &self,
188        array: &TimestamptzArray,
189    ) -> Result<arrow_array::ArrayRef, ArrayError> {
190        Ok(Arc::new(
191            arrow_array::TimestampMicrosecondArray::try_from(array)?.with_timezone_utc(),
192        ))
193    }
194
195    #[inline]
196    fn time_to_arrow(&self, array: &TimeArray) -> Result<arrow_array::ArrayRef, ArrayError> {
197        Ok(Arc::new(arrow_array::Time64MicrosecondArray::try_from(
198            array,
199        )?))
200    }
201
202    #[inline]
203    fn interval_to_arrow(
204        &self,
205        array: &IntervalArray,
206    ) -> Result<arrow_array::ArrayRef, ArrayError> {
207        Ok(Arc::new(arrow_array::IntervalMonthDayNanoArray::try_from(
208            array,
209        )?))
210    }
211
212    #[inline]
213    fn bytea_to_arrow(&self, array: &BytesArray) -> Result<arrow_array::ArrayRef, ArrayError> {
214        Ok(Arc::new(arrow_array::BinaryArray::from(array)))
215    }
216
217    // Decimal values are stored as ASCII text representation in a string array.
218    #[inline]
219    fn decimal_to_arrow(
220        &self,
221        _data_type: &arrow_schema::DataType,
222        array: &DecimalArray,
223    ) -> Result<arrow_array::ArrayRef, ArrayError> {
224        Ok(Arc::new(arrow_array::StringArray::from(array)))
225    }
226
227    // JSON values are stored as text representation in a string array.
228    #[inline]
229    fn jsonb_to_arrow(&self, array: &JsonbArray) -> Result<arrow_array::ArrayRef, ArrayError> {
230        Ok(Arc::new(arrow_array::StringArray::from(array)))
231    }
232
233    #[inline]
234    fn serial_to_arrow(&self, array: &SerialArray) -> Result<arrow_array::ArrayRef, ArrayError> {
235        Ok(Arc::new(arrow_array::Int64Array::from(array)))
236    }
237
238    #[inline]
239    fn list_to_arrow(
240        &self,
241        data_type: &arrow_schema::DataType,
242        array: &ListArray,
243    ) -> Result<arrow_array::ArrayRef, ArrayError> {
244        let arrow_schema::DataType::List(field) = data_type else {
245            return Err(ArrayError::to_arrow("Invalid list type"));
246        };
247        let values = self.to_array(field.data_type(), array.values())?;
248        let offsets = OffsetBuffer::new(array.offsets().iter().map(|&o| o as i32).collect());
249        let nulls = (!array.null_bitmap().all()).then(|| array.null_bitmap().into());
250        Ok(Arc::new(arrow_array::ListArray::new(
251            field.clone(),
252            offsets,
253            values,
254            nulls,
255        )))
256    }
257
258    #[inline]
259    fn vector_to_arrow(
260        &self,
261        data_type: &arrow_schema::DataType,
262        array: &VectorArray,
263    ) -> Result<arrow_array::ArrayRef, ArrayError> {
264        let arrow_schema::DataType::List(field) = data_type else {
265            return Err(ArrayError::to_arrow("Invalid list type"));
266        };
267        if field.data_type() != &arrow_schema::DataType::Float32 {
268            return Err(ArrayError::to_arrow("Invalid list inner type for vector"));
269        }
270        let values = Arc::new(arrow_array::Float32Array::from(
271            array.as_raw_slice().to_vec(),
272        ));
273        let offsets = OffsetBuffer::new(array.offsets().iter().map(|&o| o as i32).collect());
274        let nulls = (!array.null_bitmap().all()).then(|| array.null_bitmap().into());
275        Ok(Arc::new(arrow_array::ListArray::new(
276            field.clone(),
277            offsets,
278            values,
279            nulls,
280        )))
281    }
282
283    #[inline]
284    fn struct_to_arrow(
285        &self,
286        data_type: &arrow_schema::DataType,
287        array: &StructArray,
288    ) -> Result<arrow_array::ArrayRef, ArrayError> {
289        let arrow_schema::DataType::Struct(fields) = data_type else {
290            return Err(ArrayError::to_arrow("Invalid struct type"));
291        };
292        // Use `try_new_with_length` so that empty-field structs keep their row count;
293        // `StructArray::new` panics for empty `fields` because it derives length from
294        // the child arrays.
295        let len = array.len();
296        let child_arrays = array
297            .fields()
298            .zip_eq_fast(fields)
299            .map(|(arr, field)| self.to_array(field.data_type(), arr))
300            .try_collect::<_, _, ArrayError>()?;
301        let nulls = Some(array.null_bitmap().into());
302        Ok(Arc::new(
303            arrow_array::StructArray::try_new_with_length(fields.clone(), child_arrays, nulls, len)
304                .map_err(ArrayError::from_arrow)?,
305        ))
306    }
307
308    #[inline]
309    fn map_to_arrow(
310        &self,
311        data_type: &arrow_schema::DataType,
312        array: &MapArray,
313    ) -> Result<arrow_array::ArrayRef, ArrayError> {
314        let arrow_schema::DataType::Map(field, ordered) = data_type else {
315            return Err(ArrayError::to_arrow("Invalid map type"));
316        };
317        if *ordered {
318            return Err(ArrayError::to_arrow("Sorted map is not supported"));
319        }
320        let values = self
321            .struct_to_arrow(field.data_type(), array.as_struct())?
322            .as_struct()
323            .clone();
324        let offsets = OffsetBuffer::new(array.offsets().iter().map(|&o| o as i32).collect());
325        let nulls = (!array.null_bitmap().all()).then(|| array.null_bitmap().into());
326        Ok(Arc::new(arrow_array::MapArray::new(
327            field.clone(),
328            offsets,
329            values,
330            nulls,
331            *ordered,
332        )))
333    }
334
335    /// Convert RisingWave data type to Arrow data type.
336    ///
337    /// This function returns a `Field` instead of `DataType` because some may be converted to
338    /// extension types which require additional metadata in the field.
339    fn to_arrow_field(
340        &self,
341        name: &str,
342        value: &DataType,
343    ) -> Result<arrow_schema::Field, ArrayError> {
344        let data_type = match value {
345            // using the inline function
346            DataType::Boolean => self.bool_type_to_arrow(),
347            DataType::Int16 => self.int16_type_to_arrow(),
348            DataType::Int32 => self.int32_type_to_arrow(),
349            DataType::Int64 => self.int64_type_to_arrow(),
350            DataType::Int256 => self.int256_type_to_arrow(),
351            DataType::Float32 => self.float32_type_to_arrow(),
352            DataType::Float64 => self.float64_type_to_arrow(),
353            DataType::Date => self.date_type_to_arrow(),
354            DataType::Time => self.time_type_to_arrow(),
355            DataType::Timestamp => self.timestamp_type_to_arrow(),
356            DataType::Timestamptz => self.timestamptz_type_to_arrow(),
357            DataType::Interval => self.interval_type_to_arrow(),
358            DataType::Varchar => self.varchar_type_to_arrow(),
359            DataType::Bytea => self.bytea_type_to_arrow(),
360            DataType::Serial => self.serial_type_to_arrow(),
361            DataType::Decimal => return Ok(self.decimal_type_to_arrow(name)),
362            DataType::Jsonb => return Ok(self.jsonb_type_to_arrow(name)),
363            DataType::Struct(fields) => self.struct_type_to_arrow(fields)?,
364            DataType::List(list) => self.list_type_to_arrow(list)?,
365            DataType::Map(map) => self.map_type_to_arrow(map)?,
366            DataType::Vector(_) => self.vector_type_to_arrow()?,
367        };
368        Ok(arrow_schema::Field::new(name, data_type, true))
369    }
370
371    #[inline]
372    fn bool_type_to_arrow(&self) -> arrow_schema::DataType {
373        arrow_schema::DataType::Boolean
374    }
375
376    #[inline]
377    fn int16_type_to_arrow(&self) -> arrow_schema::DataType {
378        arrow_schema::DataType::Int16
379    }
380
381    #[inline]
382    fn int32_type_to_arrow(&self) -> arrow_schema::DataType {
383        arrow_schema::DataType::Int32
384    }
385
386    #[inline]
387    fn int64_type_to_arrow(&self) -> arrow_schema::DataType {
388        arrow_schema::DataType::Int64
389    }
390
391    #[inline]
392    fn int256_type_to_arrow(&self) -> arrow_schema::DataType {
393        arrow_schema::DataType::Decimal256(arrow_schema::DECIMAL256_MAX_PRECISION, 0)
394    }
395
396    #[inline]
397    fn float32_type_to_arrow(&self) -> arrow_schema::DataType {
398        arrow_schema::DataType::Float32
399    }
400
401    #[inline]
402    fn float64_type_to_arrow(&self) -> arrow_schema::DataType {
403        arrow_schema::DataType::Float64
404    }
405
406    #[inline]
407    fn date_type_to_arrow(&self) -> arrow_schema::DataType {
408        arrow_schema::DataType::Date32
409    }
410
411    #[inline]
412    fn time_type_to_arrow(&self) -> arrow_schema::DataType {
413        arrow_schema::DataType::Time64(arrow_schema::TimeUnit::Microsecond)
414    }
415
416    #[inline]
417    fn timestamp_type_to_arrow(&self) -> arrow_schema::DataType {
418        arrow_schema::DataType::Timestamp(arrow_schema::TimeUnit::Microsecond, None)
419    }
420
421    #[inline]
422    fn timestamptz_type_to_arrow(&self) -> arrow_schema::DataType {
423        arrow_schema::DataType::Timestamp(
424            arrow_schema::TimeUnit::Microsecond,
425            Some("+00:00".into()),
426        )
427    }
428
429    #[inline]
430    fn interval_type_to_arrow(&self) -> arrow_schema::DataType {
431        arrow_schema::DataType::Interval(arrow_schema::IntervalUnit::MonthDayNano)
432    }
433
434    #[inline]
435    fn varchar_type_to_arrow(&self) -> arrow_schema::DataType {
436        arrow_schema::DataType::Utf8
437    }
438
439    #[inline]
440    fn jsonb_type_to_arrow(&self, name: &str) -> arrow_schema::Field {
441        arrow_schema::Field::new(name, arrow_schema::DataType::Utf8, true)
442            .with_metadata([("ARROW:extension:name".into(), "arrowudf.json".into())].into())
443    }
444
445    #[inline]
446    fn bytea_type_to_arrow(&self) -> arrow_schema::DataType {
447        arrow_schema::DataType::Binary
448    }
449
450    #[inline]
451    fn decimal_type_to_arrow(&self, name: &str) -> arrow_schema::Field {
452        arrow_schema::Field::new(name, arrow_schema::DataType::Utf8, true)
453            .with_metadata([("ARROW:extension:name".into(), "arrowudf.decimal".into())].into())
454    }
455
456    #[inline]
457    fn serial_type_to_arrow(&self) -> arrow_schema::DataType {
458        arrow_schema::DataType::Int64
459    }
460
461    #[inline]
462    fn list_type_to_arrow(
463        &self,
464        list_type: &ListType,
465    ) -> Result<arrow_schema::DataType, ArrayError> {
466        Ok(arrow_schema::DataType::List(Arc::new(
467            self.to_arrow_field("item", list_type.elem())?,
468        )))
469    }
470
471    #[inline]
472    fn struct_type_to_arrow(
473        &self,
474        fields: &StructType,
475    ) -> Result<arrow_schema::DataType, ArrayError> {
476        Ok(arrow_schema::DataType::Struct(
477            fields
478                .iter()
479                .map(|(name, ty)| self.to_arrow_field(name, ty))
480                .try_collect::<_, _, ArrayError>()?,
481        ))
482    }
483
484    #[inline]
485    fn map_type_to_arrow(&self, map_type: &MapType) -> Result<arrow_schema::DataType, ArrayError> {
486        let sorted = false;
487        // "key" is always non-null
488        let key = self
489            .to_arrow_field("key", map_type.key())?
490            .with_nullable(false);
491        let value = self.to_arrow_field("value", map_type.value())?;
492        Ok(arrow_schema::DataType::Map(
493            Arc::new(arrow_schema::Field::new(
494                "entries",
495                arrow_schema::DataType::Struct([Arc::new(key), Arc::new(value)].into()),
496                // "entries" is always non-null
497                false,
498            )),
499            sorted,
500        ))
501    }
502
503    #[inline]
504    fn vector_type_to_arrow(&self) -> Result<arrow_schema::DataType, ArrayError> {
505        Ok(arrow_schema::DataType::List(Arc::new(
506            self.to_arrow_field("item", &VECTOR_ITEM_TYPE)?,
507        )))
508    }
509}
510
511/// Defines how to convert Arrow arrays to RisingWave arrays.
512#[allow(clippy::wrong_self_convention)]
513pub trait FromArrow {
514    /// Converts Arrow `RecordBatch` to RisingWave `DataChunk`.
515    fn from_record_batch(&self, batch: &arrow_array::RecordBatch) -> Result<DataChunk, ArrayError> {
516        let mut columns = Vec::with_capacity(batch.num_columns());
517        for (array, field) in batch.columns().iter().zip_eq_fast(batch.schema().fields()) {
518            let column = Arc::new(self.from_array(field, array)?);
519            columns.push(column);
520        }
521        Ok(DataChunk::new(columns, batch.num_rows()))
522    }
523
524    /// Converts Arrow `Fields` to RisingWave `StructType`.
525    fn from_fields(&self, fields: &arrow_schema::Fields) -> Result<StructType, ArrayError> {
526        Ok(StructType::new(
527            fields
528                .iter()
529                .map(|f| Ok((f.name().clone(), self.from_field(f)?)))
530                .try_collect::<_, Vec<_>, ArrayError>()?,
531        ))
532    }
533
534    /// Converts Arrow `Field` to RisingWave `DataType`.
535    fn from_field(&self, field: &arrow_schema::Field) -> Result<DataType, ArrayError> {
536        use arrow_schema::DataType::*;
537        use arrow_schema::IntervalUnit::*;
538        use arrow_schema::TimeUnit::*;
539
540        // extension type
541        if let Some(type_name) = field.metadata().get("ARROW:extension:name") {
542            return self.from_extension_type(type_name, field.data_type());
543        }
544
545        Ok(match field.data_type() {
546            Boolean => DataType::Boolean,
547            Int16 => DataType::Int16,
548            Int32 => DataType::Int32,
549            Int64 => DataType::Int64,
550            Int8 => DataType::Int16,
551            UInt8 => DataType::Int16,
552            UInt16 => DataType::Int32,
553            UInt32 => DataType::Int64,
554            UInt64 => DataType::Decimal,
555            Float16 => DataType::Float32,
556            Float32 => DataType::Float32,
557            Float64 => DataType::Float64,
558            Decimal128(_, _) => DataType::Decimal,
559            Decimal256(_, _) => DataType::Int256,
560            Date32 => DataType::Date,
561            Time32(Second) | Time32(Millisecond) | Time64(Microsecond) | Time64(Nanosecond) => {
562                DataType::Time
563            }
564            Timestamp(Microsecond, None) => DataType::Timestamp,
565            Timestamp(Microsecond, Some(_)) => DataType::Timestamptz,
566            Timestamp(Second, None) => DataType::Timestamp,
567            Timestamp(Second, Some(_)) => DataType::Timestamptz,
568            Timestamp(Millisecond, None) => DataType::Timestamp,
569            Timestamp(Millisecond, Some(_)) => DataType::Timestamptz,
570            Timestamp(Nanosecond, None) => DataType::Timestamp,
571            Timestamp(Nanosecond, Some(_)) => DataType::Timestamptz,
572            Interval(MonthDayNano) => DataType::Interval,
573            Utf8 => DataType::Varchar,
574            Utf8View => DataType::Varchar,
575            Binary => DataType::Bytea,
576            // Iceberg `uuid` maps to `FixedSizeBinary(16)` and `fixed[L]` maps to
577            // `FixedSizeBinary(L)`. Both are represented as `Bytea` in RisingWave.
578            FixedSizeBinary(_) => self.from_fixed_size_binary()?,
579            LargeUtf8 => self.from_large_utf8()?,
580            LargeBinary => self.from_large_binary()?,
581            List(field) => DataType::list(self.from_field(field)?),
582            Struct(fields) => DataType::Struct(self.from_fields(fields)?),
583            Map(field, _is_sorted) => {
584                let entries = self.from_field(field)?;
585                DataType::Map(MapType::try_from_entries(entries).map_err(|e| {
586                    ArrayError::from_arrow(format!("invalid arrow map field: {field:?}, err: {e}"))
587                })?)
588            }
589            t => {
590                return Err(ArrayError::from_arrow(format!(
591                    "unsupported arrow data type: {t:?}"
592                )));
593            }
594        })
595    }
596
597    /// Converts Arrow `LargeUtf8` type to RisingWave data type.
598    fn from_large_utf8(&self) -> Result<DataType, ArrayError> {
599        Ok(DataType::Varchar)
600    }
601
602    /// Converts Arrow `LargeBinary` type to RisingWave data type.
603    fn from_large_binary(&self) -> Result<DataType, ArrayError> {
604        Ok(DataType::Bytea)
605    }
606
607    /// Converts Arrow `FixedSizeBinary` type to RisingWave data type.
608    fn from_fixed_size_binary(&self) -> Result<DataType, ArrayError> {
609        Ok(DataType::Bytea)
610    }
611
612    /// Converts Arrow extension type to RisingWave `DataType`.
613    fn from_extension_type(
614        &self,
615        type_name: &str,
616        physical_type: &arrow_schema::DataType,
617    ) -> Result<DataType, ArrayError> {
618        match (type_name, physical_type) {
619            ("arrowudf.decimal", arrow_schema::DataType::Utf8) => Ok(DataType::Decimal),
620            ("arrowudf.json", arrow_schema::DataType::Utf8) => Ok(DataType::Jsonb),
621            _ => Err(ArrayError::from_arrow(format!(
622                "unsupported extension type: {type_name:?}"
623            ))),
624        }
625    }
626
627    /// Converts Arrow `Array` to RisingWave `ArrayImpl`.
628    ///
629    /// `expected_field` is the declared-side field: it selects the extension decode and
630    /// authoritatively drives the alignment of nested struct/list/map children.
631    fn from_array(
632        &self,
633        expected_field: &arrow_schema::Field,
634        array: &arrow_array::ArrayRef,
635    ) -> Result<ArrayImpl, ArrayError> {
636        use arrow_schema::DataType::*;
637        use arrow_schema::IntervalUnit::*;
638        use arrow_schema::TimeUnit::*;
639
640        // extension type
641        if let Some(type_name) = expected_field.metadata().get("ARROW:extension:name") {
642            return self.from_extension_array(type_name, array);
643        }
644
645        match array.data_type() {
646            Boolean => self.from_bool_array(array.as_any().downcast_ref().unwrap()),
647            Int8 => self.from_int8_array(array.as_any().downcast_ref().unwrap()),
648            Int16 => self.from_int16_array(array.as_any().downcast_ref().unwrap()),
649            Int32 => self.from_int32_array(array.as_any().downcast_ref().unwrap()),
650            Int64 => self.from_int64_array(array.as_any().downcast_ref().unwrap()),
651            UInt8 => self.from_uint8_array(array.as_any().downcast_ref().unwrap()),
652            UInt16 => self.from_uint16_array(array.as_any().downcast_ref().unwrap()),
653            UInt32 => self.from_uint32_array(array.as_any().downcast_ref().unwrap()),
654
655            UInt64 => self.from_uint64_array(array.as_any().downcast_ref().unwrap()),
656            Decimal128(_, _) => self.from_decimal128_array(array.as_any().downcast_ref().unwrap()),
657            Decimal256(_, _) => self.from_int256_array(array.as_any().downcast_ref().unwrap()),
658            Float16 => self.from_float16_array(array.as_any().downcast_ref().unwrap()),
659            Float32 => self.from_float32_array(array.as_any().downcast_ref().unwrap()),
660            Float64 => self.from_float64_array(array.as_any().downcast_ref().unwrap()),
661            Date32 => self.from_date32_array(array.as_any().downcast_ref().unwrap()),
662            Time32(Second) => self.from_time32s_array(array.as_any().downcast_ref().unwrap()),
663            Time32(Millisecond) => self.from_time32ms_array(array.as_any().downcast_ref().unwrap()),
664            Time64(Microsecond) => self.from_time64us_array(array.as_any().downcast_ref().unwrap()),
665            Time64(Nanosecond) => self.from_time64ns_array(array.as_any().downcast_ref().unwrap()),
666            Timestamp(Second, None) => {
667                self.from_timestampsecond_array(array.as_any().downcast_ref().unwrap())
668            }
669            Timestamp(Second, Some(_)) => {
670                self.from_timestampsecond_some_array(array.as_any().downcast_ref().unwrap())
671            }
672            Timestamp(Millisecond, None) => {
673                self.from_timestampms_array(array.as_any().downcast_ref().unwrap())
674            }
675            Timestamp(Millisecond, Some(_)) => {
676                self.from_timestampms_some_array(array.as_any().downcast_ref().unwrap())
677            }
678            Timestamp(Microsecond, None) => {
679                self.from_timestampus_array(array.as_any().downcast_ref().unwrap())
680            }
681            Timestamp(Microsecond, Some(_)) => {
682                self.from_timestampus_some_array(array.as_any().downcast_ref().unwrap())
683            }
684            Timestamp(Nanosecond, None) => {
685                self.from_timestampns_array(array.as_any().downcast_ref().unwrap())
686            }
687            Timestamp(Nanosecond, Some(_)) => {
688                self.from_timestampns_some_array(array.as_any().downcast_ref().unwrap())
689            }
690            Interval(MonthDayNano) => {
691                self.from_interval_array(array.as_any().downcast_ref().unwrap())
692            }
693            Utf8 => self.from_utf8_array(array.as_any().downcast_ref().unwrap()),
694            Utf8View => self.from_utf8_view_array(array.as_any().downcast_ref().unwrap()),
695            Binary => self.from_binary_array(array.as_any().downcast_ref().unwrap()),
696            FixedSizeBinary(_) => {
697                self.from_fixed_size_binary_array(array.as_any().downcast_ref().unwrap())
698            }
699            LargeUtf8 => self.from_large_utf8_array(array.as_any().downcast_ref().unwrap()),
700            LargeBinary => self.from_large_binary_array(array.as_any().downcast_ref().unwrap()),
701            List(_) => self.from_list_array(expected_field, array.as_any().downcast_ref().unwrap()),
702            Struct(_) => {
703                self.from_struct_array(expected_field, array.as_any().downcast_ref().unwrap())
704            }
705            Map(_, _) => {
706                self.from_map_array(expected_field, array.as_any().downcast_ref().unwrap())
707            }
708            t => Err(ArrayError::from_arrow(format!(
709                "unsupported arrow data type: {t:?}",
710            ))),
711        }
712    }
713
714    /// Converts Arrow extension array to RisingWave `ArrayImpl`.
715    fn from_extension_array(
716        &self,
717        type_name: &str,
718        array: &arrow_array::ArrayRef,
719    ) -> Result<ArrayImpl, ArrayError> {
720        match type_name {
721            "arrowudf.decimal" => {
722                let array: &arrow_array::StringArray =
723                    array.as_any().downcast_ref().ok_or_else(|| {
724                        ArrayError::from_arrow(
725                            "expected string array for `arrowudf.decimal`".to_owned(),
726                        )
727                    })?;
728                Ok(ArrayImpl::Decimal(array.try_into()?))
729            }
730            "arrowudf.json" => {
731                let array: &arrow_array::StringArray =
732                    array.as_any().downcast_ref().ok_or_else(|| {
733                        ArrayError::from_arrow(
734                            "expected string array for `arrowudf.json`".to_owned(),
735                        )
736                    })?;
737                Ok(ArrayImpl::Jsonb(array.try_into()?))
738            }
739            _ => Err(ArrayError::from_arrow(format!(
740                "unsupported extension type: {type_name:?}"
741            ))),
742        }
743    }
744
745    fn from_bool_array(&self, array: &arrow_array::BooleanArray) -> Result<ArrayImpl, ArrayError> {
746        Ok(ArrayImpl::Bool(array.into()))
747    }
748
749    fn from_int16_array(&self, array: &arrow_array::Int16Array) -> Result<ArrayImpl, ArrayError> {
750        Ok(ArrayImpl::Int16(array.into()))
751    }
752
753    fn from_int8_array(&self, array: &arrow_array::Int8Array) -> Result<ArrayImpl, ArrayError> {
754        Ok(ArrayImpl::Int16(array.into()))
755    }
756
757    fn from_uint8_array(&self, array: &arrow_array::UInt8Array) -> Result<ArrayImpl, ArrayError> {
758        Ok(ArrayImpl::Int16(array.into()))
759    }
760
761    fn from_uint16_array(&self, array: &arrow_array::UInt16Array) -> Result<ArrayImpl, ArrayError> {
762        Ok(ArrayImpl::Int32(array.into()))
763    }
764
765    fn from_uint32_array(&self, array: &arrow_array::UInt32Array) -> Result<ArrayImpl, ArrayError> {
766        Ok(ArrayImpl::Int64(array.into()))
767    }
768
769    fn from_int32_array(&self, array: &arrow_array::Int32Array) -> Result<ArrayImpl, ArrayError> {
770        Ok(ArrayImpl::Int32(array.into()))
771    }
772
773    fn from_int64_array(&self, array: &arrow_array::Int64Array) -> Result<ArrayImpl, ArrayError> {
774        Ok(ArrayImpl::Int64(array.into()))
775    }
776
777    fn from_int256_array(
778        &self,
779        array: &arrow_array::Decimal256Array,
780    ) -> Result<ArrayImpl, ArrayError> {
781        Ok(ArrayImpl::Int256(array.into()))
782    }
783
784    fn from_decimal128_array(
785        &self,
786        array: &arrow_array::Decimal128Array,
787    ) -> Result<ArrayImpl, ArrayError> {
788        Ok(ArrayImpl::Decimal(array.try_into()?))
789    }
790
791    fn from_uint64_array(&self, array: &arrow_array::UInt64Array) -> Result<ArrayImpl, ArrayError> {
792        Ok(ArrayImpl::Decimal(array.try_into()?))
793    }
794
795    fn from_float16_array(
796        &self,
797        array: &arrow_array::Float16Array,
798    ) -> Result<ArrayImpl, ArrayError> {
799        Ok(ArrayImpl::Float32(array.try_into()?))
800    }
801
802    fn from_float32_array(
803        &self,
804        array: &arrow_array::Float32Array,
805    ) -> Result<ArrayImpl, ArrayError> {
806        Ok(ArrayImpl::Float32(array.into()))
807    }
808
809    fn from_float64_array(
810        &self,
811        array: &arrow_array::Float64Array,
812    ) -> Result<ArrayImpl, ArrayError> {
813        Ok(ArrayImpl::Float64(array.into()))
814    }
815
816    fn from_date32_array(&self, array: &arrow_array::Date32Array) -> Result<ArrayImpl, ArrayError> {
817        Ok(ArrayImpl::Date(array.try_into()?))
818    }
819
820    fn from_time32s_array(
821        &self,
822        array: &arrow_array::Time32SecondArray,
823    ) -> Result<ArrayImpl, ArrayError> {
824        Ok(ArrayImpl::Time(array.try_into()?))
825    }
826
827    fn from_time32ms_array(
828        &self,
829        array: &arrow_array::Time32MillisecondArray,
830    ) -> Result<ArrayImpl, ArrayError> {
831        Ok(ArrayImpl::Time(array.try_into()?))
832    }
833
834    fn from_time64us_array(
835        &self,
836        array: &arrow_array::Time64MicrosecondArray,
837    ) -> Result<ArrayImpl, ArrayError> {
838        Ok(ArrayImpl::Time(array.try_into()?))
839    }
840
841    fn from_time64ns_array(
842        &self,
843        array: &arrow_array::Time64NanosecondArray,
844    ) -> Result<ArrayImpl, ArrayError> {
845        Ok(ArrayImpl::Time(array.try_into()?))
846    }
847
848    fn from_timestampsecond_array(
849        &self,
850        array: &arrow_array::TimestampSecondArray,
851    ) -> Result<ArrayImpl, ArrayError> {
852        Ok(ArrayImpl::Timestamp(array.try_into()?))
853    }
854    fn from_timestampsecond_some_array(
855        &self,
856        array: &arrow_array::TimestampSecondArray,
857    ) -> Result<ArrayImpl, ArrayError> {
858        Ok(ArrayImpl::Timestamptz(array.try_into()?))
859    }
860
861    fn from_timestampms_array(
862        &self,
863        array: &arrow_array::TimestampMillisecondArray,
864    ) -> Result<ArrayImpl, ArrayError> {
865        Ok(ArrayImpl::Timestamp(array.try_into()?))
866    }
867
868    fn from_timestampms_some_array(
869        &self,
870        array: &arrow_array::TimestampMillisecondArray,
871    ) -> Result<ArrayImpl, ArrayError> {
872        Ok(ArrayImpl::Timestamptz(array.try_into()?))
873    }
874
875    fn from_timestampus_array(
876        &self,
877        array: &arrow_array::TimestampMicrosecondArray,
878    ) -> Result<ArrayImpl, ArrayError> {
879        Ok(ArrayImpl::Timestamp(array.try_into()?))
880    }
881
882    fn from_timestampus_some_array(
883        &self,
884        array: &arrow_array::TimestampMicrosecondArray,
885    ) -> Result<ArrayImpl, ArrayError> {
886        Ok(ArrayImpl::Timestamptz(array.try_into()?))
887    }
888
889    fn from_timestampns_array(
890        &self,
891        array: &arrow_array::TimestampNanosecondArray,
892    ) -> Result<ArrayImpl, ArrayError> {
893        Ok(ArrayImpl::Timestamp(array.try_into()?))
894    }
895
896    fn from_timestampns_some_array(
897        &self,
898        array: &arrow_array::TimestampNanosecondArray,
899    ) -> Result<ArrayImpl, ArrayError> {
900        Ok(ArrayImpl::Timestamptz(array.try_into()?))
901    }
902
903    fn from_interval_array(
904        &self,
905        array: &arrow_array::IntervalMonthDayNanoArray,
906    ) -> Result<ArrayImpl, ArrayError> {
907        Ok(ArrayImpl::Interval(array.try_into()?))
908    }
909
910    fn from_utf8_array(&self, array: &arrow_array::StringArray) -> Result<ArrayImpl, ArrayError> {
911        Ok(ArrayImpl::Utf8(array.into()))
912    }
913
914    fn from_utf8_view_array(
915        &self,
916        array: &arrow_array::StringViewArray,
917    ) -> Result<ArrayImpl, ArrayError> {
918        Ok(ArrayImpl::Utf8(array.into()))
919    }
920
921    fn from_binary_array(&self, array: &arrow_array::BinaryArray) -> Result<ArrayImpl, ArrayError> {
922        Ok(ArrayImpl::Bytea(array.into()))
923    }
924
925    fn from_large_utf8_array(
926        &self,
927        array: &arrow_array::LargeStringArray,
928    ) -> Result<ArrayImpl, ArrayError> {
929        Ok(ArrayImpl::Utf8(array.into()))
930    }
931
932    fn from_large_binary_array(
933        &self,
934        array: &arrow_array::LargeBinaryArray,
935    ) -> Result<ArrayImpl, ArrayError> {
936        Ok(ArrayImpl::Bytea(array.into()))
937    }
938
939    fn from_fixed_size_binary_array(
940        &self,
941        array: &arrow_array::FixedSizeBinaryArray,
942    ) -> Result<ArrayImpl, ArrayError> {
943        Ok(ArrayImpl::Bytea(array.iter().collect()))
944    }
945
946    /// Converts an Arrow `ListArray`, decoding elements by the expected element field so that
947    /// nested decode keeps following the declared schema. Falls back to the array's own element
948    /// field when the expected field does not describe a list.
949    fn from_list_array(
950        &self,
951        expected_field: &arrow_schema::Field,
952        array: &arrow_array::ListArray,
953    ) -> Result<ArrayImpl, ArrayError> {
954        use arrow_array::Array;
955        let elem_field = match (expected_field.data_type(), array.data_type()) {
956            (arrow_schema::DataType::List(elem), _) | (_, arrow_schema::DataType::List(elem)) => {
957                elem
958            }
959            _ => unreachable!("a list array must have a list data type"),
960        };
961        Ok(ArrayImpl::List(ListArray {
962            value: Box::new(self.from_array(elem_field, array.values())?),
963            bitmap: match array.nulls() {
964                Some(nulls) => nulls.iter().collect(),
965                None => Bitmap::ones(array.len()),
966            },
967            offsets: array.offsets().iter().map(|o| *o as u32).collect(),
968        }))
969    }
970
971    /// Converts an Arrow `StructArray` by the expected struct field: children align by name
972    /// (first occurrence, extras dropped), positionally when a name is missing but the arity
973    /// matches (an external UDF may label struct children differently, as its signature check
974    /// ignores nested field names), and error otherwise. Extensions are taken from the
975    /// expected side only.
976    ///
977    /// The result carries the expected field *names* with the *decoded* child types: the
978    /// expected field may be a lossy rendering of the declared type (e.g. iceberg has no
979    /// 16-bit int), so the decoded types are authoritative and any divergence from the
980    /// declared type stays visible to the callers' boundary checks.
981    ///
982    /// Falls back to the array's own fields when the expected field does not describe a struct.
983    fn from_struct_array(
984        &self,
985        expected_field: &arrow_schema::Field,
986        array: &arrow_array::StructArray,
987    ) -> Result<ArrayImpl, ArrayError> {
988        use std::collections::HashMap;
989
990        use arrow_array::Array;
991
992        let arrow_schema::DataType::Struct(actual_fields) = array.data_type() else {
993            unreachable!("a struct array must have a struct data type");
994        };
995        let expected_fields = match expected_field.data_type() {
996            arrow_schema::DataType::Struct(fields) => fields,
997            _ => actual_fields,
998        };
999
1000        let len = array.len();
1001        let decode_positionally = |fields: &arrow_schema::Fields| {
1002            array
1003                .columns()
1004                .iter()
1005                .zip_eq_fast(fields)
1006                .map(|(column, field)| self.from_array(field, column).map(Arc::new))
1007                .try_collect()
1008        };
1009        // Children decode by the expected field either way, so aligning names in order is
1010        // enough for the zip fast path — no deep field comparison needed.
1011        let names_aligned = expected_fields.len() == actual_fields.len()
1012            && expected_fields
1013                .iter()
1014                .zip_eq_fast(actual_fields.iter())
1015                .all(|(e, a)| e.name() == a.name());
1016        let columns: Vec<Arc<ArrayImpl>> = if names_aligned {
1017            decode_positionally(expected_fields)?
1018        } else {
1019            // First occurrence wins. The schema matcher rejects duplicate sibling names,
1020            // so on the parquet path this tie-break is never exercised.
1021            let mut actual_name_to_index = HashMap::new();
1022            for (idx, f) in actual_fields.iter().enumerate() {
1023                actual_name_to_index.entry(f.name().as_str()).or_insert(idx);
1024            }
1025            if expected_fields
1026                .iter()
1027                .all(|f| actual_name_to_index.contains_key(f.name().as_str()))
1028            {
1029                expected_fields
1030                    .iter()
1031                    .map(|expected_field| {
1032                        let idx = actual_name_to_index[expected_field.name().as_str()];
1033                        self.from_array(expected_field, &array.columns()[idx])
1034                            .map(Arc::new)
1035                    })
1036                    .try_collect()?
1037            } else if expected_fields.len() == actual_fields.len() {
1038                // Positional fallback for external UDFs. Unreachable on the parquet path:
1039                // the schema matcher requires every declared name to be present.
1040                decode_positionally(expected_fields)?
1041            } else {
1042                let names =
1043                    |fields: &arrow_schema::Fields| fields.iter().map(|f| f.name()).join(", ");
1044                return Err(ArrayError::from_arrow(format!(
1045                    "unable to align struct fields: expected [{}], actual [{}]",
1046                    names(expected_fields),
1047                    names(actual_fields),
1048                )));
1049            }
1050        };
1051
1052        Ok(ArrayImpl::Struct(StructArray::new(
1053            StructType::new(
1054                expected_fields
1055                    .iter()
1056                    .zip_eq_fast(columns.iter())
1057                    .map(|(f, c)| (f.name().clone(), c.data_type())),
1058            ),
1059            columns,
1060            (0..len).map(|i| array.is_valid(i)).collect(),
1061        )))
1062    }
1063
1064    /// Converts an Arrow `MapArray`, decoding entries by the expected entries field. Falls back
1065    /// to the array's own entries field when the expected field does not describe a map.
1066    fn from_map_array(
1067        &self,
1068        expected_field: &arrow_schema::Field,
1069        array: &arrow_array::MapArray,
1070    ) -> Result<ArrayImpl, ArrayError> {
1071        use arrow_array::Array;
1072        let expected_entries = match (expected_field.data_type(), array.data_type()) {
1073            (arrow_schema::DataType::Map(entries, _), _)
1074            | (_, arrow_schema::DataType::Map(entries, _)) => entries,
1075            _ => unreachable!("a map array must have a map data type"),
1076        };
1077        let struct_array = self.from_struct_array(expected_entries, array.entries())?;
1078        // RW restricts map key types, so deriving a map type from decoded entries is
1079        // fallible and `MapArray::data_type()` panics on an invalid key. Reject it here.
1080        MapType::try_from_entries(struct_array.data_type())
1081            .map_err(|e| ArrayError::from_arrow(format!("invalid arrow map array: {e}")))?;
1082        let list_array = ListArray {
1083            value: Box::new(struct_array),
1084            bitmap: match array.nulls() {
1085                Some(nulls) => nulls.iter().collect(),
1086                None => Bitmap::ones(array.len()),
1087            },
1088            offsets: array.offsets().iter().map(|o| *o as u32).collect(),
1089        };
1090
1091        Ok(ArrayImpl::Map(MapArray { inner: list_array }))
1092    }
1093}
1094
1095impl From<&Bitmap> for arrow_buffer::NullBuffer {
1096    fn from(bitmap: &Bitmap) -> Self {
1097        bitmap.iter().collect()
1098    }
1099}
1100
1101/// Implement bi-directional `From` between concrete array types.
1102macro_rules! converts {
1103    ($ArrayType:ty, $ArrowType:ty) => {
1104        impl From<&$ArrayType> for $ArrowType {
1105            fn from(array: &$ArrayType) -> Self {
1106                array.iter().collect()
1107            }
1108        }
1109        impl From<&$ArrowType> for $ArrayType {
1110            fn from(array: &$ArrowType) -> Self {
1111                array.iter().collect()
1112            }
1113        }
1114        impl From<&[$ArrowType]> for $ArrayType {
1115            fn from(arrays: &[$ArrowType]) -> Self {
1116                arrays.iter().flat_map(|a| a.iter()).collect()
1117            }
1118        }
1119    };
1120    // convert values using FromIntoArrow
1121    ($ArrayType:ty, $ArrowType:ty, @map) => {
1122        impl From<&$ArrayType> for $ArrowType {
1123            fn from(array: &$ArrayType) -> Self {
1124                array.iter().map(|o| o.map(|v| v.into_arrow())).collect()
1125            }
1126        }
1127        impl From<&$ArrowType> for $ArrayType {
1128            fn from(array: &$ArrowType) -> Self {
1129                array
1130                    .iter()
1131                    .map(|o| {
1132                        o.map(|v| {
1133                            <<$ArrayType as Array>::RefItem<'_> as FromIntoArrow>::from_arrow(v)
1134                        })
1135                    })
1136                    .collect()
1137            }
1138        }
1139        impl From<&[$ArrowType]> for $ArrayType {
1140            fn from(arrays: &[$ArrowType]) -> Self {
1141                arrays
1142                    .iter()
1143                    .flat_map(|a| a.iter())
1144                    .map(|o| {
1145                        o.map(|v| {
1146                            <<$ArrayType as Array>::RefItem<'_> as FromIntoArrow>::from_arrow(v)
1147                        })
1148                    })
1149                    .collect()
1150            }
1151        }
1152    };
1153    // convert values using TryFromIntoArrow
1154    ($ArrayType:ty, $ArrowType:ty, @try_map) => {
1155        impl TryFrom<&$ArrayType> for $ArrowType {
1156            type Error = ArrayError;
1157
1158            fn try_from(array: &$ArrayType) -> Result<Self, Self::Error> {
1159                // Collecting `Result`s loses the iterator's size hint, so build with an
1160                // explicit capacity instead.
1161                let mut builder = <$ArrowType>::builder(array.len());
1162                for o in array.iter() {
1163                    builder.append_option(o.map(|v| v.try_into_arrow()).transpose()?);
1164                }
1165                Ok(builder.finish())
1166            }
1167        }
1168        impl TryFrom<&$ArrowType> for $ArrayType {
1169            type Error = ArrayError;
1170
1171            fn try_from(array: &$ArrowType) -> Result<Self, Self::Error> {
1172                use arrow_array::Array as _;
1173
1174                let mut builder = <$ArrayType as Array>::Builder::new(array.len());
1175                for o in array.iter() {
1176                    builder.append(
1177                        o.map(<<$ArrayType as Array>::RefItem<'_> as TryFromIntoArrow>::try_from_arrow)
1178                            .transpose()?,
1179                    );
1180                }
1181                Ok(builder.finish())
1182            }
1183        }
1184    };
1185}
1186
1187/// Used to convert different types.
1188macro_rules! converts_with_type {
1189    ($ArrayType:ty, $ArrowType:ty, $FromType:ty, $ToType:ty) => {
1190        impl From<&$ArrayType> for $ArrowType {
1191            fn from(array: &$ArrayType) -> Self {
1192                let values: Vec<Option<$ToType>> =
1193                    array.iter().map(|x| x.map(|v| v as $ToType)).collect();
1194                <$ArrowType>::from_iter(values)
1195            }
1196        }
1197
1198        impl From<&$ArrowType> for $ArrayType {
1199            fn from(array: &$ArrowType) -> Self {
1200                let values: Vec<Option<$FromType>> =
1201                    array.iter().map(|x| x.map(|v| v as $FromType)).collect();
1202                <$ArrayType>::from_iter(values)
1203            }
1204        }
1205
1206        impl From<&[$ArrowType]> for $ArrayType {
1207            fn from(arrays: &[$ArrowType]) -> Self {
1208                let values: Vec<Option<$FromType>> = arrays
1209                    .iter()
1210                    .flat_map(|a| a.iter().map(|x| x.map(|v| v as $FromType)))
1211                    .collect();
1212                <$ArrayType>::from_iter(values)
1213            }
1214        }
1215    };
1216}
1217
1218macro_rules! converts_with_time_unit {
1219    ($ArrayType:ty, $ArrowType:ident, $time_unit:ident) => {
1220        impl TryFrom<&$ArrayType> for arrow_array::$ArrowType {
1221            type Error = ArrayError;
1222
1223            fn try_from(array: &$ArrayType) -> Result<Self, Self::Error> {
1224                let mut builder = arrow_array::$ArrowType::builder(array.len());
1225                for o in array.iter() {
1226                    builder.append_option(
1227                        o.map(|v| into_arrow_temporal_value(v, TimeUnit::$time_unit))
1228                            .transpose()?,
1229                    );
1230                }
1231                Ok(builder.finish())
1232            }
1233        }
1234
1235        impl TryFrom<&arrow_array::$ArrowType> for $ArrayType {
1236            type Error = ArrayError;
1237
1238            fn try_from(array: &arrow_array::$ArrowType) -> Result<Self, Self::Error> {
1239                Self::try_from(std::slice::from_ref(array))
1240            }
1241        }
1242
1243        impl TryFrom<&[arrow_array::$ArrowType]> for $ArrayType {
1244            type Error = ArrayError;
1245
1246            fn try_from(arrays: &[arrow_array::$ArrowType]) -> Result<Self, Self::Error> {
1247                use arrow_array::Array as _;
1248
1249                let mut builder =
1250                    <$ArrayType as Array>::Builder::new(arrays.iter().map(|a| a.len()).sum());
1251                for o in arrays.iter().flat_map(|a| a.iter()) {
1252                    builder.append(
1253                        o.map(|v| try_from_arrow_temporal_value(v, TimeUnit::$time_unit))
1254                            .transpose()?,
1255                    );
1256                }
1257                Ok(builder.finish())
1258            }
1259        }
1260    };
1261}
1262
1263converts!(BoolArray, arrow_array::BooleanArray);
1264converts!(I16Array, arrow_array::Int16Array);
1265converts!(I32Array, arrow_array::Int32Array);
1266converts!(I64Array, arrow_array::Int64Array);
1267converts!(F32Array, arrow_array::Float32Array, @map);
1268converts!(F64Array, arrow_array::Float64Array, @map);
1269converts!(BytesArray, arrow_array::BinaryArray);
1270converts!(BytesArray, arrow_array::LargeBinaryArray);
1271converts!(Utf8Array, arrow_array::StringArray);
1272converts!(Utf8Array, arrow_array::LargeStringArray);
1273converts!(Utf8Array, arrow_array::StringViewArray);
1274converts!(DateArray, arrow_array::Date32Array, @try_map);
1275converts!(IntervalArray, arrow_array::IntervalMonthDayNanoArray, @try_map);
1276converts!(SerialArray, arrow_array::Int64Array, @map);
1277
1278converts_with_type!(I16Array, arrow_array::Int8Array, i16, i8);
1279converts_with_type!(I16Array, arrow_array::UInt8Array, i16, u8);
1280converts_with_type!(I32Array, arrow_array::UInt16Array, i32, u16);
1281converts_with_type!(I64Array, arrow_array::UInt32Array, i64, u32);
1282
1283converts_with_time_unit!(TimeArray, Time32SecondArray, Second);
1284converts_with_time_unit!(TimeArray, Time32MillisecondArray, Millisecond);
1285converts_with_time_unit!(TimeArray, Time64MicrosecondArray, Microsecond);
1286converts_with_time_unit!(TimeArray, Time64NanosecondArray, Nanosecond);
1287
1288converts_with_time_unit!(TimestampArray, TimestampSecondArray, Second);
1289converts_with_time_unit!(TimestampArray, TimestampMillisecondArray, Millisecond);
1290converts_with_time_unit!(TimestampArray, TimestampMicrosecondArray, Microsecond);
1291converts_with_time_unit!(TimestampArray, TimestampNanosecondArray, Nanosecond);
1292
1293converts_with_time_unit!(TimestamptzArray, TimestampSecondArray, Second);
1294converts_with_time_unit!(TimestamptzArray, TimestampMillisecondArray, Millisecond);
1295converts_with_time_unit!(TimestamptzArray, TimestampMicrosecondArray, Microsecond);
1296converts_with_time_unit!(TimestamptzArray, TimestampNanosecondArray, Nanosecond);
1297
1298/// Converts RisingWave value from and into Arrow value.
1299trait FromIntoArrow {
1300    /// The corresponding element type in the Arrow array.
1301    type ArrowType;
1302    fn from_arrow(value: Self::ArrowType) -> Self;
1303    fn into_arrow(self) -> Self::ArrowType;
1304}
1305
1306/// Like [`FromIntoArrow`], for values whose Arrow representation does not cover the whole
1307/// RisingWave domain, or vice versa.
1308trait TryFromIntoArrow: Sized {
1309    /// The corresponding element type in the Arrow array.
1310    type ArrowType;
1311    fn try_from_arrow(value: Self::ArrowType) -> Result<Self, ArrayError>;
1312    fn try_into_arrow(self) -> Result<Self::ArrowType, ArrayError>;
1313}
1314
1315/// Converts a RisingWave temporal scalar to and from Arrow's physical primitive
1316/// value using an Arrow time unit.
1317trait TemporalArrowConvert<ArrowNative>: Sized {
1318    fn try_from_arrow_with_time_unit(
1319        value: ArrowNative,
1320        time_unit: TimeUnit,
1321    ) -> Result<Self, ArrayError>;
1322    fn into_arrow_with_time_unit(self, time_unit: TimeUnit) -> Result<ArrowNative, ArrayError>;
1323}
1324
1325fn try_from_arrow_temporal_value<Value, ArrowNative>(
1326    value: ArrowNative,
1327    time_unit: TimeUnit,
1328) -> Result<Value, ArrayError>
1329where
1330    Value: TemporalArrowConvert<ArrowNative>,
1331{
1332    Value::try_from_arrow_with_time_unit(value, time_unit)
1333}
1334
1335fn into_arrow_temporal_value<Value, ArrowNative>(
1336    value: Value,
1337    time_unit: TimeUnit,
1338) -> Result<ArrowNative, ArrayError>
1339where
1340    Value: TemporalArrowConvert<ArrowNative>,
1341{
1342    value.into_arrow_with_time_unit(time_unit)
1343}
1344
1345impl FromIntoArrow for Serial {
1346    type ArrowType = i64;
1347
1348    fn from_arrow(value: Self::ArrowType) -> Self {
1349        value.into()
1350    }
1351
1352    fn into_arrow(self) -> Self::ArrowType {
1353        self.into()
1354    }
1355}
1356
1357impl FromIntoArrow for F32 {
1358    type ArrowType = f32;
1359
1360    fn from_arrow(value: Self::ArrowType) -> Self {
1361        value.into()
1362    }
1363
1364    fn into_arrow(self) -> Self::ArrowType {
1365        self.into()
1366    }
1367}
1368
1369impl FromIntoArrow for F64 {
1370    type ArrowType = f64;
1371
1372    fn from_arrow(value: Self::ArrowType) -> Self {
1373        value.into()
1374    }
1375
1376    fn into_arrow(self) -> Self::ArrowType {
1377        self.into()
1378    }
1379}
1380
1381impl TryFromIntoArrow for Date {
1382    type ArrowType = i32;
1383
1384    #[allow(deprecated)]
1385    fn try_from_arrow(value: Self::ArrowType) -> Result<Self, ArrayError> {
1386        arrow_array::types::Date32Type::to_naive_date_opt(value)
1387            .map(Date)
1388            .ok_or_else(|| ArrayError::from_arrow(format!("invalid Arrow date {value}")))
1389    }
1390
1391    fn try_into_arrow(self) -> Result<Self::ArrowType, ArrayError> {
1392        Ok(arrow_array::types::Date32Type::from_naive_date(self.0))
1393    }
1394}
1395
1396/// Arrow `Time32` arrays are defined only for second and millisecond units.
1397impl TemporalArrowConvert<i32> for Time {
1398    fn try_from_arrow_with_time_unit(value: i32, time_unit: TimeUnit) -> Result<Self, ArrayError> {
1399        u32::try_from(value)
1400            .ok()
1401            .and_then(|v| match time_unit {
1402                TimeUnit::Second => Time::with_secs_nano(v, 0).ok(),
1403                TimeUnit::Millisecond => Time::with_milli(v).ok(),
1404                unit => unreachable!("{unit:?} is not a Time32 unit"),
1405            })
1406            .ok_or_else(|| invalid_arrow_temporal_value(value, time_unit))
1407    }
1408
1409    fn into_arrow_with_time_unit(self, time_unit: TimeUnit) -> Result<i32, ArrayError> {
1410        Ok(match time_unit {
1411            TimeUnit::Second => self.0.num_seconds_from_midnight() as i32,
1412            TimeUnit::Millisecond => {
1413                (self.0.num_seconds_from_midnight() * 1_000 + self.0.nanosecond() / 1_000_000)
1414                    as i32
1415            }
1416            unit => unreachable!("{unit:?} is not a Time32 unit"),
1417        })
1418    }
1419}
1420
1421/// Arrow `Time64` arrays are defined only for microsecond and nanosecond units.
1422///
1423/// RisingWave's `time` is microsecond-precision, so nanoseconds are truncated.
1424impl TemporalArrowConvert<i64> for Time {
1425    fn try_from_arrow_with_time_unit(value: i64, time_unit: TimeUnit) -> Result<Self, ArrayError> {
1426        u64::try_from(value)
1427            .ok()
1428            .and_then(|v| match time_unit {
1429                TimeUnit::Microsecond => Time::with_micro(v).ok(),
1430                TimeUnit::Nanosecond => Time::with_micro(v / 1_000).ok(),
1431                unit => unreachable!("{unit:?} is not a Time64 unit"),
1432            })
1433            .ok_or_else(|| invalid_arrow_temporal_value(value, time_unit))
1434    }
1435
1436    fn into_arrow_with_time_unit(self, time_unit: TimeUnit) -> Result<i64, ArrayError> {
1437        Ok(match time_unit {
1438            TimeUnit::Microsecond => self.micros_of_day() as i64,
1439            TimeUnit::Nanosecond => self.nanos_of_day() as i64,
1440            unit => unreachable!("{unit:?} is not a Time64 unit"),
1441        })
1442    }
1443}
1444
1445impl TemporalArrowConvert<i64> for Timestamp {
1446    fn try_from_arrow_with_time_unit(value: i64, time_unit: TimeUnit) -> Result<Self, ArrayError> {
1447        match time_unit {
1448            TimeUnit::Second => Timestamp::with_secs_nsecs(value, 0)
1449                .map_err(|_| invalid_arrow_temporal_value(value, time_unit)),
1450            TimeUnit::Millisecond => Timestamp::with_millis(value)
1451                .map_err(|_| invalid_arrow_temporal_value(value, time_unit)),
1452            TimeUnit::Microsecond => Timestamp::with_micros(value)
1453                .map_err(|_| invalid_arrow_temporal_value(value, time_unit)),
1454            TimeUnit::Nanosecond => Ok(Timestamp::with_nanos(value)),
1455        }
1456    }
1457
1458    fn into_arrow_with_time_unit(self, time_unit: TimeUnit) -> Result<i64, ArrayError> {
1459        match time_unit {
1460            TimeUnit::Second => Ok(self.0.and_utc().timestamp()),
1461            TimeUnit::Millisecond => Ok(self.0.and_utc().timestamp_millis()),
1462            TimeUnit::Microsecond => Ok(self.0.and_utc().timestamp_micros()),
1463            TimeUnit::Nanosecond => self
1464                .0
1465                .and_utc()
1466                .timestamp_nanos_opt()
1467                .ok_or_else(|| arrow_temporal_value_overflow(self, time_unit)),
1468        }
1469    }
1470}
1471
1472impl TemporalArrowConvert<i64> for Timestamptz {
1473    fn try_from_arrow_with_time_unit(value: i64, time_unit: TimeUnit) -> Result<Self, ArrayError> {
1474        match time_unit {
1475            TimeUnit::Second => Timestamptz::from_secs(value)
1476                .ok_or_else(|| invalid_arrow_temporal_value(value, time_unit)),
1477            TimeUnit::Millisecond => Timestamptz::from_millis(value)
1478                .ok_or_else(|| invalid_arrow_temporal_value(value, time_unit)),
1479            TimeUnit::Microsecond => Timestamptz::from_micros(value)
1480                .ok_or_else(|| invalid_arrow_temporal_value(value, time_unit)),
1481            TimeUnit::Nanosecond => Ok(Timestamptz::from_nanos(value)),
1482        }
1483    }
1484
1485    fn into_arrow_with_time_unit(self, time_unit: TimeUnit) -> Result<i64, ArrayError> {
1486        match time_unit {
1487            TimeUnit::Second => Ok(self.timestamp()),
1488            TimeUnit::Millisecond => Ok(self.timestamp_millis()),
1489            TimeUnit::Microsecond => Ok(self.timestamp_micros()),
1490            TimeUnit::Nanosecond => self
1491                .timestamp_nanos()
1492                .ok_or_else(|| arrow_temporal_value_overflow(self, time_unit)),
1493        }
1494    }
1495}
1496
1497fn invalid_arrow_temporal_value<T: std::fmt::Display>(value: T, time_unit: TimeUnit) -> ArrayError {
1498    ArrayError::from_arrow(format!(
1499        "invalid Arrow temporal value {value} for unit {time_unit:?}"
1500    ))
1501}
1502
1503fn arrow_temporal_value_overflow<T: std::fmt::Display>(
1504    value: T,
1505    time_unit: TimeUnit,
1506) -> ArrayError {
1507    ArrayError::to_arrow(format!(
1508        "temporal value {value} overflows Arrow unit {time_unit:?}"
1509    ))
1510}
1511
1512impl TryFromIntoArrow for Interval {
1513    type ArrowType = ArrowIntervalType;
1514
1515    /// RisingWave's `interval` is microsecond-precision, so nanoseconds are truncated.
1516    fn try_from_arrow(value: Self::ArrowType) -> Result<Self, ArrayError> {
1517        Ok(Interval::from_month_day_usec(
1518            value.months,
1519            value.days,
1520            value.nanoseconds / 1_000,
1521        ))
1522    }
1523
1524    fn try_into_arrow(self) -> Result<Self::ArrowType, ArrayError> {
1525        Ok(ArrowIntervalType {
1526            months: self.months(),
1527            days: self.days(),
1528            nanoseconds: self.usecs().checked_mul(1_000).ok_or_else(|| {
1529                ArrayError::to_arrow(format!(
1530                    "interval with {} microseconds is out of range for Arrow",
1531                    self.usecs()
1532                ))
1533            })?,
1534        })
1535    }
1536}
1537
1538impl From<&DecimalArray> for arrow_array::LargeBinaryArray {
1539    fn from(array: &DecimalArray) -> Self {
1540        let mut builder =
1541            arrow_array::builder::LargeBinaryBuilder::with_capacity(array.len(), array.len() * 8);
1542        for value in array.iter() {
1543            builder.append_option(value.map(|d| d.to_string()));
1544        }
1545        builder.finish()
1546    }
1547}
1548
1549impl From<&DecimalArray> for arrow_array::StringArray {
1550    fn from(array: &DecimalArray) -> Self {
1551        let mut builder =
1552            arrow_array::builder::StringBuilder::with_capacity(array.len(), array.len() * 8);
1553        for value in array.iter() {
1554            builder.append_option(value.map(|d| d.to_string()));
1555        }
1556        builder.finish()
1557    }
1558}
1559
1560// This arrow decimal type is used by iceberg source to read iceberg decimal into RW decimal.
1561impl TryFrom<&arrow_array::Decimal128Array> for DecimalArray {
1562    type Error = ArrayError;
1563
1564    fn try_from(array: &arrow_array::Decimal128Array) -> Result<Self, Self::Error> {
1565        if array.scale() < 0 {
1566            bail!("support negative scale for arrow decimal")
1567        }
1568
1569        // Calculate the max value based on the Arrow decimal's precision
1570        // When writing Inf to Arrow Decimal128(precision, scale), we use 10^precision - 1
1571        let precision = array.precision();
1572        let max_value = 10_i128.pow(precision as u32) - 1;
1573
1574        let from_arrow = |value| {
1575            const NAN: i128 = i128::MIN + 1;
1576            let res = match value {
1577                // Check for special values using Arrow Decimal's max value, not i128::MAX
1578                NAN => Decimal::NaN,
1579                v if v == max_value => Decimal::PositiveInf,
1580                v if v == -max_value => Decimal::NegativeInf,
1581                i128::MAX => Decimal::PositiveInf, // Fallback for old data
1582                i128::MIN => Decimal::NegativeInf, // Fallback for old data
1583                _ => Decimal::truncated_i128_and_scale(value, array.scale() as u32)
1584                    .ok_or_else(|| ArrayError::from_arrow("decimal overflow"))?,
1585            };
1586            Ok(res)
1587        };
1588        array
1589            .iter()
1590            .map(|o| o.map(from_arrow).transpose())
1591            .collect::<Result<Self, Self::Error>>()
1592    }
1593}
1594
1595// Since RisingWave does not support UInt type, convert UInt64Array to Decimal.
1596impl TryFrom<&arrow_array::UInt64Array> for DecimalArray {
1597    type Error = ArrayError;
1598
1599    fn try_from(array: &arrow_array::UInt64Array) -> Result<Self, Self::Error> {
1600        let from_arrow = |value| {
1601            // Convert the value to a Decimal with scale 0
1602            let res = Decimal::from(value);
1603            Ok(res)
1604        };
1605
1606        // Map over the array and convert each value
1607        array
1608            .iter()
1609            .map(|o| o.map(from_arrow).transpose())
1610            .collect::<Result<Self, Self::Error>>()
1611    }
1612}
1613
1614impl TryFrom<&arrow_array::Float16Array> for F32Array {
1615    type Error = ArrayError;
1616
1617    fn try_from(array: &arrow_array::Float16Array) -> Result<Self, Self::Error> {
1618        let from_arrow = |value| Ok(f32::from(value));
1619
1620        array
1621            .iter()
1622            .map(|o| o.map(from_arrow).transpose())
1623            .collect::<Result<Self, Self::Error>>()
1624    }
1625}
1626
1627impl TryFrom<&arrow_array::LargeBinaryArray> for DecimalArray {
1628    type Error = ArrayError;
1629
1630    fn try_from(array: &arrow_array::LargeBinaryArray) -> Result<Self, Self::Error> {
1631        array
1632            .iter()
1633            .map(|o| {
1634                o.map(|s| {
1635                    let s = std::str::from_utf8(s)
1636                        .map_err(|_| ArrayError::from_arrow(format!("invalid decimal: {s:?}")))?;
1637                    s.parse()
1638                        .map_err(|_| ArrayError::from_arrow(format!("invalid decimal: {s:?}")))
1639                })
1640                .transpose()
1641            })
1642            .try_collect()
1643    }
1644}
1645
1646impl TryFrom<&arrow_array::StringArray> for DecimalArray {
1647    type Error = ArrayError;
1648
1649    fn try_from(array: &arrow_array::StringArray) -> Result<Self, Self::Error> {
1650        array
1651            .iter()
1652            .map(|o| {
1653                o.map(|s| {
1654                    s.parse()
1655                        .map_err(|_| ArrayError::from_arrow(format!("invalid decimal: {s:?}")))
1656                })
1657                .transpose()
1658            })
1659            .try_collect()
1660    }
1661}
1662
1663impl From<&JsonbArray> for arrow_array::StringArray {
1664    fn from(array: &JsonbArray) -> Self {
1665        let mut builder =
1666            arrow_array::builder::StringBuilder::with_capacity(array.len(), array.len() * 16);
1667        for value in array.iter() {
1668            match value {
1669                Some(jsonb) => {
1670                    write!(&mut builder, "{}", jsonb).unwrap();
1671                    builder.append_value("");
1672                }
1673                None => builder.append_null(),
1674            }
1675        }
1676        builder.finish()
1677    }
1678}
1679
1680impl TryFrom<&arrow_array::StringArray> for JsonbArray {
1681    type Error = ArrayError;
1682
1683    fn try_from(array: &arrow_array::StringArray) -> Result<Self, Self::Error> {
1684        array
1685            .iter()
1686            .map(|o| {
1687                o.map(|s| {
1688                    s.parse()
1689                        .map_err(|_| ArrayError::from_arrow(format!("invalid json: {s}")))
1690                })
1691                .transpose()
1692            })
1693            .try_collect()
1694    }
1695}
1696
1697impl From<&IntervalArray> for arrow_array::StringArray {
1698    fn from(array: &IntervalArray) -> Self {
1699        let mut builder =
1700            arrow_array::builder::StringBuilder::with_capacity(array.len(), array.len() * 16);
1701        for value in array.iter() {
1702            match value {
1703                Some(interval) => {
1704                    write!(&mut builder, "{}", interval).unwrap();
1705                    builder.append_value("");
1706                }
1707                None => builder.append_null(),
1708            }
1709        }
1710        builder.finish()
1711    }
1712}
1713
1714impl From<&JsonbArray> for arrow_array::LargeStringArray {
1715    fn from(array: &JsonbArray) -> Self {
1716        let mut builder =
1717            arrow_array::builder::LargeStringBuilder::with_capacity(array.len(), array.len() * 16);
1718        for value in array.iter() {
1719            match value {
1720                Some(jsonb) => {
1721                    write!(&mut builder, "{}", jsonb).unwrap();
1722                    builder.append_value("");
1723                }
1724                None => builder.append_null(),
1725            }
1726        }
1727        builder.finish()
1728    }
1729}
1730
1731impl TryFrom<&arrow_array::LargeStringArray> for JsonbArray {
1732    type Error = ArrayError;
1733
1734    fn try_from(array: &arrow_array::LargeStringArray) -> Result<Self, Self::Error> {
1735        array
1736            .iter()
1737            .map(|o| {
1738                o.map(|s| {
1739                    s.parse()
1740                        .map_err(|_| ArrayError::from_arrow(format!("invalid json: {s}")))
1741                })
1742                .transpose()
1743            })
1744            .try_collect()
1745    }
1746}
1747
1748impl From<arrow_buffer::i256> for Int256 {
1749    fn from(value: arrow_buffer::i256) -> Self {
1750        let buffer = value.to_be_bytes();
1751        Int256::from_be_bytes(buffer)
1752    }
1753}
1754
1755impl<'a> From<Int256Ref<'a>> for arrow_buffer::i256 {
1756    fn from(val: Int256Ref<'a>) -> Self {
1757        let buffer = val.to_be_bytes();
1758        arrow_buffer::i256::from_be_bytes(buffer)
1759    }
1760}
1761
1762impl From<&Int256Array> for arrow_array::Decimal256Array {
1763    fn from(array: &Int256Array) -> Self {
1764        array
1765            .iter()
1766            .map(|o| o.map(arrow_buffer::i256::from))
1767            .collect()
1768    }
1769}
1770
1771impl From<&arrow_array::Decimal256Array> for Int256Array {
1772    fn from(array: &arrow_array::Decimal256Array) -> Self {
1773        let values = array.iter().map(|o| o.map(Int256::from)).collect_vec();
1774
1775        values
1776            .iter()
1777            .map(|i| i.as_ref().map(|v| v.as_scalar_ref()))
1778            .collect()
1779    }
1780}
1781
1782/// This function checks whether the schema of a Parquet file matches the user-defined schema in RisingWave.
1783/// It handles the following special cases:
1784/// - Arrow's `timestamp(_, None)` types (all four time units) match with RisingWave's `Timestamp` type.
1785/// - Arrow's `timestamp(_, Some)` matches with RisingWave's `Timestamptz` type.
1786/// - Since RisingWave does not have an `UInt` type:
1787///   - Arrow's `UInt8` matches with RisingWave's `Int16`.
1788///   - Arrow's `UInt16` matches with RisingWave's `Int32`.
1789///   - Arrow's `UInt32` matches with RisingWave's `Int64`.
1790///   - Arrow's `UInt64` matches with RisingWave's `Decimal`.
1791/// - Arrow's `Float16` matches with RisingWave's `Float32`.
1792///
1793/// Nested data type matching:
1794/// - Struct: Arrow's `Struct` type matches with RisingWave's `Struct` type recursively, requiring that all expected fields exist and match by name and type. Extra Arrow fields are allowed, but a declared name matching multiple Arrow siblings is ambiguous and rejected.
1795/// - List: Arrow's `List` type matches with RisingWave's `List` type recursively, requiring the same element type.
1796/// - Map: Arrow's `Map` type matches with RisingWave's `Map` type recursively, requiring the key and value types to match, and the inner struct must have exactly two fields named "key" and "value".
1797pub fn is_parquet_schema_match_source_schema(
1798    arrow_data_type: &arrow_schema::DataType,
1799    rw_data_type: &crate::types::DataType,
1800) -> bool {
1801    use arrow_schema::DataType as ArrowType;
1802
1803    use crate::types::{DataType as RwType, MapType, StructType};
1804
1805    match (arrow_data_type, rw_data_type) {
1806        // Primitive type matching and special cases
1807        (ArrowType::Boolean, RwType::Boolean)
1808        | (ArrowType::Int8 | ArrowType::Int16 | ArrowType::UInt8, RwType::Int16)
1809        | (ArrowType::Int32 | ArrowType::UInt16, RwType::Int32)
1810        | (ArrowType::Int64 | ArrowType::UInt32, RwType::Int64)
1811        | (ArrowType::UInt64 | ArrowType::Decimal128(_, _), RwType::Decimal)
1812        | (ArrowType::Decimal256(_, _), RwType::Int256)
1813        | (ArrowType::Float16 | ArrowType::Float32, RwType::Float32)
1814        | (ArrowType::Float64, RwType::Float64)
1815        | (ArrowType::Timestamp(_, None), RwType::Timestamp)
1816        | (ArrowType::Timestamp(_, Some(_)), RwType::Timestamptz)
1817        | (ArrowType::Date32, RwType::Date)
1818        | (ArrowType::Time32(_) | ArrowType::Time64(_), RwType::Time)
1819        | (ArrowType::Interval(arrow_schema::IntervalUnit::MonthDayNano), RwType::Interval)
1820        | (ArrowType::Utf8 | ArrowType::LargeUtf8, RwType::Varchar)
1821        | (
1822            ArrowType::Binary | ArrowType::LargeBinary | ArrowType::FixedSizeBinary(_),
1823            RwType::Bytea,
1824        ) => true,
1825
1826        // Struct type recursive matching
1827        // Arrow's Struct matches RisingWave's Struct if all expected field names exist and types
1828        // match recursively. Extra Arrow fields are allowed and field order is ignored.
1829        (ArrowType::Struct(arrow_fields), RwType::Struct(rw_struct)) => {
1830            if arrow_fields.len() < rw_struct.len() {
1831                return false;
1832            }
1833            for (rw_name, rw_ty) in rw_struct.iter() {
1834                let mut candidates = arrow_fields.iter().filter(|f| f.name() == rw_name);
1835                let Some(arrow_field) = candidates.next() else {
1836                    return false;
1837                };
1838                // Parquet permits duplicate sibling names; which one holds the data is
1839                // ambiguous, so reject the match.
1840                if candidates.next().is_some() {
1841                    return false;
1842                }
1843                if !is_parquet_schema_match_source_schema(arrow_field.data_type(), rw_ty) {
1844                    return false;
1845                }
1846            }
1847            true
1848        }
1849        // List type recursive matching
1850        // Arrow's List matches RisingWave's List if the element type matches recursively
1851        (ArrowType::List(arrow_field), RwType::List(rw_list_ty)) => {
1852            is_parquet_schema_match_source_schema(arrow_field.data_type(), rw_list_ty.elem())
1853        }
1854        // Map type recursive matching
1855        // Arrow's Map matches RisingWave's Map if the key and value types match recursively,
1856        // and the inner struct has exactly two fields named "key" and "value"
1857        (ArrowType::Map(arrow_field, _), RwType::Map(rw_map_ty)) => {
1858            if let ArrowType::Struct(fields) = arrow_field.data_type() {
1859                if fields.len() != 2 {
1860                    return false;
1861                }
1862                let key_field = &fields[0];
1863                let value_field = &fields[1];
1864                if key_field.name() != "key" || value_field.name() != "value" {
1865                    return false;
1866                }
1867                let (rw_key_ty, rw_value_ty) = (rw_map_ty.key(), rw_map_ty.value());
1868                is_parquet_schema_match_source_schema(key_field.data_type(), rw_key_ty)
1869                    && is_parquet_schema_match_source_schema(value_field.data_type(), rw_value_ty)
1870            } else {
1871                false
1872            }
1873        }
1874        // Fallback: types do not match
1875        _ => false,
1876    }
1877}
1878#[cfg(test)]
1879mod tests {
1880
1881    use arrow_schema::{DataType as ArrowType, Field as ArrowField};
1882
1883    use super::*;
1884    use crate::types::{DataType as RwType, MapType, StructType};
1885
1886    /// A default-only `FromArrow` for exercising the shared decode logic.
1887    struct Dummy;
1888    impl FromArrow for Dummy {}
1889
1890    #[test]
1891    fn test_struct_schema_match() {
1892        // Arrow: struct<f1: Double, f2: Utf8>
1893
1894        let arrow_struct = ArrowType::Struct(
1895            vec![
1896                ArrowField::new("f1", ArrowType::Float64, true),
1897                ArrowField::new("f2", ArrowType::Utf8, true),
1898            ]
1899            .into(),
1900        );
1901        // RW: struct<f1 Double, f2 Varchar>
1902        let rw_struct = RwType::Struct(StructType::new(vec![
1903            ("f1".to_owned(), RwType::Float64),
1904            ("f2".to_owned(), RwType::Varchar),
1905        ]));
1906        assert!(is_parquet_schema_match_source_schema(
1907            &arrow_struct,
1908            &rw_struct
1909        ));
1910
1911        // Arrow is a superset of RW struct fields.
1912        let arrow_struct_superset = ArrowType::Struct(
1913            vec![
1914                ArrowField::new("f1", ArrowType::Float64, true),
1915                ArrowField::new("f2", ArrowType::Utf8, true),
1916                ArrowField::new("f3", ArrowType::Int32, true),
1917            ]
1918            .into(),
1919        );
1920        assert!(is_parquet_schema_match_source_schema(
1921            &arrow_struct_superset,
1922            &rw_struct
1923        ));
1924
1925        // Field order is ignored for struct matching.
1926        let arrow_struct_reordered = ArrowType::Struct(
1927            vec![
1928                ArrowField::new("f2", ArrowType::Utf8, true),
1929                ArrowField::new("f1", ArrowType::Float64, true),
1930            ]
1931            .into(),
1932        );
1933        assert!(is_parquet_schema_match_source_schema(
1934            &arrow_struct_reordered,
1935            &rw_struct
1936        ));
1937
1938        // Field names do not match
1939        let arrow_struct2 = ArrowType::Struct(
1940            vec![
1941                ArrowField::new("f1", ArrowType::Float64, true),
1942                ArrowField::new("f3", ArrowType::Utf8, true),
1943            ]
1944            .into(),
1945        );
1946        assert!(!is_parquet_schema_match_source_schema(
1947            &arrow_struct2,
1948            &rw_struct
1949        ));
1950    }
1951
1952    #[test]
1953    fn test_struct_duplicate_sibling_names_reject_match() {
1954        let rw_struct = RwType::Struct(StructType::new(vec![("f1".to_owned(), RwType::Float64)]));
1955
1956        // A declared name matching multiple Arrow siblings is ambiguous, even when the
1957        // duplicates carry the same type.
1958        for dup_type in [ArrowType::Float64, ArrowType::Utf8] {
1959            let arrow_struct = ArrowType::Struct(
1960                vec![
1961                    ArrowField::new("f1", ArrowType::Float64, true),
1962                    ArrowField::new("f1", dup_type, true),
1963                ]
1964                .into(),
1965            );
1966            assert!(!is_parquet_schema_match_source_schema(
1967                &arrow_struct,
1968                &rw_struct
1969            ));
1970        }
1971
1972        // Duplicates among extra (undeclared) fields are irrelevant: they are dropped anyway.
1973        let arrow_struct = ArrowType::Struct(
1974            vec![
1975                ArrowField::new("f1", ArrowType::Float64, true),
1976                ArrowField::new("extra", ArrowType::Int32, true),
1977                ArrowField::new("extra", ArrowType::Utf8, true),
1978            ]
1979            .into(),
1980        );
1981        assert!(is_parquet_schema_match_source_schema(
1982            &arrow_struct,
1983            &rw_struct
1984        ));
1985    }
1986
1987    #[test]
1988    fn test_struct_projection_from_arrow() {
1989        use itertools::Itertools;
1990
1991        // Actual Arrow struct: struct<foo:int32, bar:utf8, baz:int32>
1992        let actual_fields: arrow_schema::Fields = vec![
1993            ArrowField::new("foo", ArrowType::Int32, true),
1994            ArrowField::new("bar", ArrowType::Utf8, true),
1995            ArrowField::new("baz", ArrowType::Int32, true),
1996        ]
1997        .into();
1998        let foo: arrow_array::ArrayRef =
1999            Arc::new(arrow_array::Int32Array::from(vec![Some(10), Some(20)]));
2000        let bar: arrow_array::ArrayRef =
2001            Arc::new(arrow_array::StringArray::from(vec![Some("a"), Some("b")]));
2002        let baz: arrow_array::ArrayRef =
2003            Arc::new(arrow_array::Int32Array::from(vec![Some(100), Some(200)]));
2004        let actual_struct = arrow_array::StructArray::new(actual_fields, vec![foo, bar, baz], None);
2005        let actual_struct_ref: arrow_array::ArrayRef = Arc::new(actual_struct);
2006
2007        // Expected struct in RW schema (via to_arrow_field): struct<foo:int32, bar:utf8>
2008        let expected_field = ArrowField::new(
2009            "s",
2010            ArrowType::Struct(
2011                vec![
2012                    ArrowField::new("foo", ArrowType::Int32, true),
2013                    ArrowField::new("bar", ArrowType::Utf8, true),
2014                ]
2015                .into(),
2016            ),
2017            true,
2018        );
2019
2020        let array_impl = Dummy
2021            .from_array(&expected_field, &actual_struct_ref)
2022            .unwrap();
2023
2024        let ArrayImpl::Struct(s) = array_impl else {
2025            panic!("expected RW StructArray");
2026        };
2027
2028        let DataType::Struct(st) = s.data_type() else {
2029            panic!("expected RW struct type");
2030        };
2031        assert_eq!(st.len(), 2);
2032        assert_eq!(st.iter().map(|(n, _)| n).collect_vec(), vec!["foo", "bar"]);
2033
2034        let v0 = s.value_at(0).unwrap().to_owned_scalar();
2035        let v1 = s.value_at(1).unwrap().to_owned_scalar();
2036        assert_eq!(
2037            v0,
2038            StructValue::new(vec![
2039                Some(ScalarImpl::Int32(10)),
2040                Some(ScalarImpl::Utf8("a".into()))
2041            ])
2042        );
2043        assert_eq!(
2044            v1,
2045            StructValue::new(vec![
2046                Some(ScalarImpl::Int32(20)),
2047                Some(ScalarImpl::Utf8("b".into()))
2048            ])
2049        );
2050    }
2051
2052    /// Builds a two-element `list<struct>` array from the given element fields and columns.
2053    fn build_list_of_struct(
2054        elem_fields: arrow_schema::Fields,
2055        columns: Vec<arrow_array::ArrayRef>,
2056    ) -> arrow_array::ArrayRef {
2057        use std::sync::Arc;
2058        let elem_struct = arrow_array::StructArray::new(elem_fields.clone(), columns, None);
2059        Arc::new(arrow_array::ListArray::new(
2060            Arc::new(ArrowField::new(
2061                "element",
2062                ArrowType::Struct(elem_fields),
2063                true,
2064            )),
2065            arrow_buffer::OffsetBuffer::new(vec![0, 2].into()),
2066            Arc::new(elem_struct),
2067            None,
2068        ))
2069    }
2070
2071    #[test]
2072    fn test_list_element_struct_decodes_by_declared_field() {
2073        // File: list<struct<b utf8, a int32, extra int32>> — reordered and a superset of the
2074        // declared element struct.
2075        let file_array = build_list_of_struct(
2076            vec![
2077                ArrowField::new("b", ArrowType::Utf8, true),
2078                ArrowField::new("a", ArrowType::Int32, true),
2079                ArrowField::new("extra", ArrowType::Int32, true),
2080            ]
2081            .into(),
2082            vec![
2083                Arc::new(arrow_array::StringArray::from(vec![Some("x"), Some("y")])),
2084                Arc::new(arrow_array::Int32Array::from(vec![Some(1), Some(2)])),
2085                Arc::new(arrow_array::Int32Array::from(vec![Some(9), Some(8)])),
2086            ],
2087        );
2088        // Declared: list<struct<a int, b varchar>>.
2089        let declared_elem: arrow_schema::Fields = vec![
2090            ArrowField::new("a", ArrowType::Int32, true),
2091            ArrowField::new("b", ArrowType::Utf8, true),
2092        ]
2093        .into();
2094        let declared_field = ArrowField::new(
2095            "l",
2096            ArrowType::List(Arc::new(ArrowField::new(
2097                "element",
2098                ArrowType::Struct(declared_elem),
2099                true,
2100            ))),
2101            true,
2102        );
2103
2104        let converted = Dummy.from_array(&declared_field, &file_array).unwrap();
2105        assert_eq!(
2106            converted.data_type(),
2107            RwType::list(RwType::Struct(StructType::new(vec![
2108                ("a", RwType::Int32),
2109                ("b", RwType::Varchar),
2110            ])))
2111        );
2112        let ArrayImpl::List(list) = &converted else {
2113            panic!("expected list array");
2114        };
2115        let ArrayImpl::Struct(elems) = list.values() else {
2116            panic!("expected struct elements");
2117        };
2118        assert_eq!(
2119            elems.value_at(0).unwrap().to_owned_scalar(),
2120            StructValue::new(vec![
2121                Some(ScalarImpl::Int32(1)),
2122                Some(ScalarImpl::Utf8("x".into())),
2123            ])
2124        );
2125        assert_eq!(
2126            elems.value_at(1).unwrap().to_owned_scalar(),
2127            StructValue::new(vec![
2128                Some(ScalarImpl::Int32(2)),
2129                Some(ScalarImpl::Utf8("y".into())),
2130            ])
2131        );
2132    }
2133
2134    /// Decodes a struct array against a declared struct with the given fields.
2135    fn decode_struct(
2136        declared_fields: Vec<arrow_schema::Field>,
2137        actual: arrow_array::StructArray,
2138    ) -> Result<ArrayImpl, ArrayError> {
2139        let declared = ArrowField::new("s", ArrowType::Struct(declared_fields.into()), true);
2140        let array: arrow_array::ArrayRef = Arc::new(actual);
2141        Dummy.from_array(&declared, &array)
2142    }
2143
2144    #[test]
2145    fn test_struct_name_mismatch_same_arity_decodes_positionally() {
2146        // An external UDF may label struct children differently from the declared return
2147        // type; the correspondence defined by the signature check is positional.
2148        let actual_fields: arrow_schema::Fields = vec![
2149            ArrowField::new("total", ArrowType::Int32, true),
2150            ArrowField::new("count", ArrowType::Utf8, true),
2151        ]
2152        .into();
2153        let array = arrow_array::StructArray::new(
2154            actual_fields,
2155            vec![
2156                Arc::new(arrow_array::Int32Array::from(vec![Some(42)])),
2157                Arc::new(arrow_array::StringArray::from(vec![Some("x")])),
2158            ],
2159            None,
2160        );
2161
2162        let converted = decode_struct(
2163            vec![
2164                ArrowField::new("sum", ArrowType::Int32, true),
2165                ArrowField::new("cnt", ArrowType::Utf8, true),
2166            ],
2167            array,
2168        )
2169        .unwrap();
2170        assert_eq!(
2171            converted.data_type(),
2172            RwType::Struct(StructType::new(vec![
2173                ("sum", RwType::Int32),
2174                ("cnt", RwType::Varchar),
2175            ]))
2176        );
2177        let ArrayImpl::Struct(structs) = &converted else {
2178            panic!("expected struct array");
2179        };
2180        assert_eq!(
2181            structs.value_at(0).unwrap().to_owned_scalar(),
2182            StructValue::new(vec![
2183                Some(ScalarImpl::Int32(42)),
2184                Some(ScalarImpl::Utf8("x".into())),
2185            ])
2186        );
2187    }
2188
2189    #[test]
2190    fn test_struct_unalignable_fields_error() {
2191        // A declared name is missing and the arity differs: neither by-name nor positional
2192        // alignment applies.
2193        let array = arrow_array::StructArray::new(
2194            vec![ArrowField::new("a", ArrowType::Int32, true)].into(),
2195            vec![Arc::new(arrow_array::Int32Array::from(vec![Some(1)]))],
2196            None,
2197        );
2198
2199        let err = decode_struct(
2200            vec![
2201                ArrowField::new("a", ArrowType::Int32, true),
2202                ArrowField::new("b", ArrowType::Utf8, true),
2203            ],
2204            array,
2205        )
2206        .unwrap_err();
2207        assert!(
2208            err.to_string()
2209                .contains("unable to align struct fields: expected [a, b], actual [a]"),
2210            "unexpected error: {err}"
2211        );
2212    }
2213
2214    #[test]
2215    fn test_struct_child_type_divergence_stamped_honestly() {
2216        // Same child name, different type: the result must report the decoded child type,
2217        // not the expected one, so callers' boundary checks can see the divergence.
2218        let array = arrow_array::StructArray::new(
2219            vec![ArrowField::new("a", ArrowType::Utf8, true)].into(),
2220            vec![Arc::new(arrow_array::StringArray::from(vec![Some("oops")]))],
2221            None,
2222        );
2223
2224        let converted =
2225            decode_struct(vec![ArrowField::new("a", ArrowType::Int64, true)], array).unwrap();
2226        assert_eq!(
2227            converted.data_type(),
2228            RwType::Struct(StructType::new(vec![("a", RwType::Varchar)]))
2229        );
2230    }
2231
2232    #[test]
2233    fn test_struct_child_decodes_despite_lossy_expected_field() {
2234        // The parquet path renders a declared `struct<a smallint>` through the iceberg-lossy
2235        // to_arrow_field as struct<a: Int32>. A foreign file storing a genuine Int16 child
2236        // must still decode to Int16 with correct values instead of erroring.
2237        let array = arrow_array::StructArray::new(
2238            vec![ArrowField::new("a", ArrowType::Int16, true)].into(),
2239            vec![Arc::new(arrow_array::Int16Array::from(vec![
2240                Some(7),
2241                Some(-3),
2242            ]))],
2243            None,
2244        );
2245
2246        let converted =
2247            decode_struct(vec![ArrowField::new("a", ArrowType::Int32, true)], array).unwrap();
2248        assert_eq!(
2249            converted.data_type(),
2250            RwType::Struct(StructType::new(vec![("a", RwType::Int16)]))
2251        );
2252        let ArrayImpl::Struct(structs) = &converted else {
2253            panic!("expected struct array");
2254        };
2255        assert_eq!(
2256            structs.value_at(0).unwrap().to_owned_scalar(),
2257            StructValue::new(vec![Some(ScalarImpl::Int16(7))])
2258        );
2259    }
2260
2261    #[test]
2262    fn test_struct_duplicate_sibling_names_decode_first_occurrence() {
2263        // The by-name decode must consult the same child as the schema matcher (the first
2264        // occurrence), never a later duplicate of a different type.
2265        let actual_fields: arrow_schema::Fields = vec![
2266            ArrowField::new("a", ArrowType::Int32, true),
2267            ArrowField::new("a", ArrowType::Utf8, true),
2268            ArrowField::new("b", ArrowType::Utf8, true),
2269        ]
2270        .into();
2271        let array = arrow_array::StructArray::new(
2272            actual_fields,
2273            vec![
2274                Arc::new(arrow_array::Int32Array::from(vec![Some(1)])),
2275                Arc::new(arrow_array::StringArray::from(vec![Some("dup")])),
2276                Arc::new(arrow_array::StringArray::from(vec![Some("x")])),
2277            ],
2278            None,
2279        );
2280
2281        let converted = decode_struct(
2282            vec![
2283                ArrowField::new("a", ArrowType::Int32, true),
2284                ArrowField::new("b", ArrowType::Utf8, true),
2285            ],
2286            array,
2287        )
2288        .unwrap();
2289        let ArrayImpl::Struct(structs) = &converted else {
2290            panic!("expected struct array");
2291        };
2292        assert_eq!(
2293            structs.value_at(0).unwrap().to_owned_scalar(),
2294            StructValue::new(vec![
2295                Some(ScalarImpl::Int32(1)),
2296                Some(ScalarImpl::Utf8("x".into())),
2297            ])
2298        );
2299    }
2300
2301    #[test]
2302    fn test_extension_decode_follows_declared_field_under_list() {
2303        let json_meta: std::collections::HashMap<String, String> = [(
2304            "ARROW:extension:name".to_owned(),
2305            "arrowudf.json".to_owned(),
2306        )]
2307        .into();
2308        let strings: arrow_array::ArrayRef = Arc::new(arrow_array::StringArray::from(vec![
2309            Some(r#"{"k":1}"#),
2310            Some("2"),
2311        ]));
2312        let make_list = |elem_field: ArrowField, values: arrow_array::ArrayRef| {
2313            Arc::new(arrow_array::ListArray::new(
2314                Arc::new(elem_field),
2315                arrow_buffer::OffsetBuffer::new(vec![0, 2].into()),
2316                values,
2317                None,
2318            )) as arrow_array::ArrayRef
2319        };
2320        let plain_elem = ArrowField::new("element", ArrowType::Utf8, true);
2321        let json_elem = plain_elem.clone().with_metadata(json_meta);
2322
2323        // A file-side extension is ignored when the declared element is plain varchar.
2324        let file_json = make_list(json_elem.clone(), strings.clone());
2325        let declared_plain =
2326            ArrowField::new("l", ArrowType::List(Arc::new(plain_elem.clone())), true);
2327        let converted = Dummy.from_array(&declared_plain, &file_json).unwrap();
2328        assert_eq!(converted.data_type(), RwType::list(RwType::Varchar));
2329
2330        // A declared-side extension drives the decode even when the file element is plain.
2331        let file_plain = make_list(plain_elem, strings);
2332        let declared_json = ArrowField::new("l", ArrowType::List(Arc::new(json_elem)), true);
2333        let converted = Dummy.from_array(&declared_json, &file_plain).unwrap();
2334        assert_eq!(converted.data_type(), RwType::list(RwType::Jsonb));
2335    }
2336
2337    #[test]
2338    fn test_map_value_struct_decodes_by_declared_field() {
2339        // File: map<utf8, struct<y int32, x int32>>; declared value struct is the subset
2340        // struct<x int32>.
2341        let value_fields: arrow_schema::Fields = vec![
2342            ArrowField::new("y", ArrowType::Int32, true),
2343            ArrowField::new("x", ArrowType::Int32, true),
2344        ]
2345        .into();
2346        let entries_fields: arrow_schema::Fields = vec![
2347            ArrowField::new("key", ArrowType::Utf8, false),
2348            ArrowField::new("value", ArrowType::Struct(value_fields.clone()), true),
2349        ]
2350        .into();
2351        let value_struct = arrow_array::StructArray::new(
2352            value_fields,
2353            vec![
2354                Arc::new(arrow_array::Int32Array::from(vec![Some(7)])),
2355                Arc::new(arrow_array::Int32Array::from(vec![Some(42)])),
2356            ],
2357            None,
2358        );
2359        let entries = arrow_array::StructArray::new(
2360            entries_fields.clone(),
2361            vec![
2362                Arc::new(arrow_array::StringArray::from(vec![Some("k")])),
2363                Arc::new(value_struct),
2364            ],
2365            None,
2366        );
2367        let file_map: arrow_array::ArrayRef = Arc::new(arrow_array::MapArray::new(
2368            Arc::new(ArrowField::new(
2369                "entries",
2370                ArrowType::Struct(entries_fields),
2371                false,
2372            )),
2373            arrow_buffer::OffsetBuffer::new(vec![0, 1].into()),
2374            entries,
2375            None,
2376            false,
2377        ));
2378
2379        let declared_value =
2380            ArrowType::Struct(vec![ArrowField::new("x", ArrowType::Int32, true)].into());
2381        let declared_field = ArrowField::new(
2382            "m",
2383            ArrowType::Map(
2384                Arc::new(ArrowField::new(
2385                    "entries",
2386                    ArrowType::Struct(
2387                        vec![
2388                            ArrowField::new("key", ArrowType::Utf8, false),
2389                            ArrowField::new("value", declared_value, true),
2390                        ]
2391                        .into(),
2392                    ),
2393                    false,
2394                )),
2395                false,
2396            ),
2397            true,
2398        );
2399
2400        let converted = Dummy.from_array(&declared_field, &file_map).unwrap();
2401        assert_eq!(
2402            converted.data_type(),
2403            RwType::Map(MapType::from_kv(
2404                RwType::Varchar,
2405                RwType::Struct(StructType::new(vec![("x", RwType::Int32)])),
2406            ))
2407        );
2408        let ArrayImpl::Map(map) = &converted else {
2409            panic!("expected map array");
2410        };
2411        let ArrayImpl::Struct(entries) = map.inner.values() else {
2412            panic!("expected struct entries");
2413        };
2414        assert_eq!(
2415            entries.value_at(0).unwrap().to_owned_scalar(),
2416            StructValue::new(vec![
2417                Some(ScalarImpl::Utf8("k".into())),
2418                Some(ScalarImpl::Struct(StructValue::new(vec![Some(
2419                    ScalarImpl::Int32(42)
2420                )]))),
2421            ])
2422        );
2423    }
2424
2425    #[test]
2426    fn test_map_invalid_key_type_errors() {
2427        // A float64 map key is representable in arrow but not in RW's `MapType`;
2428        // decode must reject it instead of building a map whose `data_type()` panics.
2429        let entries_fields: arrow_schema::Fields = vec![
2430            ArrowField::new("key", ArrowType::Float64, false),
2431            ArrowField::new("value", ArrowType::Int32, true),
2432        ]
2433        .into();
2434        let entries = arrow_array::StructArray::new(
2435            entries_fields.clone(),
2436            vec![
2437                Arc::new(arrow_array::Float64Array::from(vec![Some(1.5)])),
2438                Arc::new(arrow_array::Int32Array::from(vec![Some(42)])),
2439            ],
2440            None,
2441        );
2442        let entries_field = Arc::new(ArrowField::new(
2443            "entries",
2444            ArrowType::Struct(entries_fields),
2445            false,
2446        ));
2447        let file_map: arrow_array::ArrayRef = Arc::new(arrow_array::MapArray::new(
2448            entries_field.clone(),
2449            arrow_buffer::OffsetBuffer::new(vec![0, 1].into()),
2450            entries,
2451            None,
2452            false,
2453        ));
2454        let field = ArrowField::new("m", ArrowType::Map(entries_field, false), true);
2455
2456        let err = Dummy.from_array(&field, &file_map).unwrap_err();
2457        assert!(
2458            err.to_string().contains("invalid map key type"),
2459            "unexpected error: {err}"
2460        );
2461    }
2462
2463    #[test]
2464    fn test_list_schema_match() {
2465        // Arrow: list<double>
2466        let arrow_list =
2467            ArrowType::List(Box::new(ArrowField::new("item", ArrowType::Float64, true)).into());
2468        // RW: list<double>
2469        let rw_list = RwType::Float64.list();
2470        assert!(is_parquet_schema_match_source_schema(&arrow_list, &rw_list));
2471
2472        let rw_list2 = RwType::Int32.list();
2473        assert!(!is_parquet_schema_match_source_schema(
2474            &arrow_list,
2475            &rw_list2
2476        ));
2477    }
2478
2479    #[test]
2480    fn test_map_schema_match() {
2481        // Arrow: map<utf8, int32>
2482        let arrow_map = ArrowType::Map(
2483            Arc::new(ArrowField::new(
2484                "entries",
2485                ArrowType::Struct(
2486                    vec![
2487                        ArrowField::new("key", ArrowType::Utf8, false),
2488                        ArrowField::new("value", ArrowType::Int32, true),
2489                    ]
2490                    .into(),
2491                ),
2492                false,
2493            )),
2494            false,
2495        );
2496        // RW: map<varchar, int32>
2497        let rw_map = RwType::Map(MapType::from_kv(RwType::Varchar, RwType::Int32));
2498        assert!(is_parquet_schema_match_source_schema(&arrow_map, &rw_map));
2499
2500        // Key type does not match
2501        let rw_map2 = RwType::Map(MapType::from_kv(RwType::Int32, RwType::Int32));
2502        assert!(!is_parquet_schema_match_source_schema(&arrow_map, &rw_map2));
2503
2504        // Value type does not match
2505        let rw_map3 = RwType::Map(MapType::from_kv(RwType::Varchar, RwType::Float64));
2506        assert!(!is_parquet_schema_match_source_schema(&arrow_map, &rw_map3));
2507
2508        // Arrow inner struct field name does not match
2509        let arrow_map2 = ArrowType::Map(
2510            Arc::new(ArrowField::new(
2511                "entries",
2512                ArrowType::Struct(
2513                    vec![
2514                        ArrowField::new("k", ArrowType::Utf8, false),
2515                        ArrowField::new("value", ArrowType::Int32, true),
2516                    ]
2517                    .into(),
2518                ),
2519                false,
2520            )),
2521            false,
2522        );
2523        assert!(!is_parquet_schema_match_source_schema(&arrow_map2, &rw_map));
2524    }
2525
2526    #[test]
2527    fn bool() {
2528        let array = BoolArray::from_iter([None, Some(false), Some(true)]);
2529        let arrow = arrow_array::BooleanArray::from(&array);
2530        assert_eq!(BoolArray::from(&arrow), array);
2531    }
2532
2533    #[test]
2534    fn i16() {
2535        let array = I16Array::from_iter([None, Some(-7), Some(25)]);
2536        let arrow = arrow_array::Int16Array::from(&array);
2537        assert_eq!(I16Array::from(&arrow), array);
2538    }
2539
2540    #[test]
2541    fn i32() {
2542        let array = I32Array::from_iter([None, Some(-7), Some(25)]);
2543        let arrow = arrow_array::Int32Array::from(&array);
2544        assert_eq!(I32Array::from(&arrow), array);
2545    }
2546
2547    #[test]
2548    fn i64() {
2549        let array = I64Array::from_iter([None, Some(-7), Some(25)]);
2550        let arrow = arrow_array::Int64Array::from(&array);
2551        assert_eq!(I64Array::from(&arrow), array);
2552    }
2553
2554    #[test]
2555    fn f32() {
2556        let array = F32Array::from_iter([None, Some(-7.0), Some(25.0)]);
2557        let arrow = arrow_array::Float32Array::from(&array);
2558        assert_eq!(F32Array::from(&arrow), array);
2559    }
2560
2561    #[test]
2562    fn f64() {
2563        let array = F64Array::from_iter([None, Some(-7.0), Some(25.0)]);
2564        let arrow = arrow_array::Float64Array::from(&array);
2565        assert_eq!(F64Array::from(&arrow), array);
2566    }
2567
2568    #[test]
2569    fn int8() {
2570        let array: PrimitiveArray<i16> = I16Array::from_iter([None, Some(-128), Some(127)]);
2571        let arr = arrow_array::Int8Array::from(vec![None, Some(-128), Some(127)]);
2572        let converted: PrimitiveArray<i16> = (&arr).into();
2573        assert_eq!(converted, array);
2574    }
2575
2576    #[test]
2577    fn uint8() {
2578        let array: PrimitiveArray<i16> = I16Array::from_iter([None, Some(7), Some(25)]);
2579        let arr = arrow_array::UInt8Array::from(vec![None, Some(7), Some(25)]);
2580        let converted: PrimitiveArray<i16> = (&arr).into();
2581        assert_eq!(converted, array);
2582    }
2583
2584    #[test]
2585    fn uint16() {
2586        let array: PrimitiveArray<i32> = I32Array::from_iter([None, Some(7), Some(65535)]);
2587        let arr = arrow_array::UInt16Array::from(vec![None, Some(7), Some(65535)]);
2588        let converted: PrimitiveArray<i32> = (&arr).into();
2589        assert_eq!(converted, array);
2590    }
2591
2592    #[test]
2593    fn uint32() {
2594        let array: PrimitiveArray<i64> = I64Array::from_iter([None, Some(7), Some(4294967295)]);
2595        let arr = arrow_array::UInt32Array::from(vec![None, Some(7), Some(4294967295)]);
2596        let converted: PrimitiveArray<i64> = (&arr).into();
2597        assert_eq!(converted, array);
2598    }
2599
2600    #[test]
2601    fn uint64() {
2602        let array: PrimitiveArray<Decimal> = DecimalArray::from_iter([
2603            None,
2604            Some(Decimal::Normalized("7".parse().unwrap())),
2605            Some(Decimal::Normalized("18446744073709551615".parse().unwrap())),
2606        ]);
2607        let arr = arrow_array::UInt64Array::from(vec![None, Some(7), Some(18446744073709551615)]);
2608        let converted: PrimitiveArray<Decimal> = (&arr).try_into().unwrap();
2609        assert_eq!(converted, array);
2610    }
2611
2612    #[test]
2613    fn date() {
2614        let array = DateArray::from_iter([
2615            None,
2616            Date::with_days_since_ce(12345).ok(),
2617            Date::with_days_since_ce(-12345).ok(),
2618        ]);
2619        let arrow = arrow_array::Date32Array::try_from(&array).unwrap();
2620        assert_eq!(DateArray::try_from(&arrow).unwrap(), array);
2621    }
2622
2623    #[test]
2624    fn time() {
2625        let array = TimeArray::from_iter([None, Time::with_micro(24 * 3600 * 1_000_000 - 1).ok()]);
2626        let arrow = arrow_array::Time64MicrosecondArray::try_from(&array).unwrap();
2627        assert_eq!(TimeArray::try_from(&arrow).unwrap(), array);
2628    }
2629
2630    #[test]
2631    fn time_arrow_units_round_trip() {
2632        let second_array = TimeArray::from_iter([
2633            None,
2634            Time::with_secs_nano(1, 0).ok(),
2635            Time::with_secs_nano(2, 0).ok(),
2636        ]);
2637        let arrow = arrow_array::Time32SecondArray::try_from(&second_array).unwrap();
2638        assert_eq!(
2639            arrow,
2640            arrow_array::Time32SecondArray::from(vec![None, Some(1), Some(2)])
2641        );
2642        assert_eq!(TimeArray::try_from(&arrow).unwrap(), second_array);
2643
2644        let millisecond_array = TimeArray::from_iter([
2645            None,
2646            Time::with_secs_nano(1, 0).ok(),
2647            Time::with_secs_nano(2, 123_000_000).ok(),
2648        ]);
2649        let arrow = arrow_array::Time32MillisecondArray::try_from(&millisecond_array).unwrap();
2650        assert_eq!(
2651            arrow,
2652            arrow_array::Time32MillisecondArray::from(vec![None, Some(1_000), Some(2_123)])
2653        );
2654        assert_eq!(TimeArray::try_from(&arrow).unwrap(), millisecond_array);
2655
2656        let microsecond_array = TimeArray::from_iter([
2657            None,
2658            Time::with_secs_nano(1, 0).ok(),
2659            Time::with_secs_nano(2, 123_456_000).ok(),
2660        ]);
2661        let arrow = arrow_array::Time64MicrosecondArray::try_from(&microsecond_array).unwrap();
2662        assert_eq!(
2663            arrow,
2664            arrow_array::Time64MicrosecondArray::from(vec![None, Some(1_000_000), Some(2_123_456)])
2665        );
2666        assert_eq!(TimeArray::try_from(&arrow).unwrap(), microsecond_array);
2667
2668        let nanosecond_array = TimeArray::from_iter([
2669            None,
2670            Time::with_secs_nano(1, 0).ok(),
2671            Time::with_secs_nano(2, 123_456_000).ok(),
2672        ]);
2673        let arrow = arrow_array::Time64NanosecondArray::try_from(&nanosecond_array).unwrap();
2674        assert_eq!(
2675            arrow,
2676            arrow_array::Time64NanosecondArray::from(vec![
2677                None,
2678                Some(1_000_000_000),
2679                Some(2_123_456_000)
2680            ])
2681        );
2682        assert_eq!(TimeArray::try_from(&arrow).unwrap(), nanosecond_array);
2683    }
2684
2685    #[test]
2686    fn time_arrow_units_truncate_sub_unit_precision() {
2687        let array = TimeArray::from_iter([Time::with_secs_nano(2, 123_456_789).ok()]);
2688
2689        assert_eq!(
2690            arrow_array::Time32SecondArray::try_from(&array).unwrap(),
2691            arrow_array::Time32SecondArray::from(vec![Some(2)])
2692        );
2693        assert_eq!(
2694            arrow_array::Time32MillisecondArray::try_from(&array).unwrap(),
2695            arrow_array::Time32MillisecondArray::from(vec![Some(2_123)])
2696        );
2697        assert_eq!(
2698            arrow_array::Time64MicrosecondArray::try_from(&array).unwrap(),
2699            arrow_array::Time64MicrosecondArray::from(vec![Some(2_123_456)])
2700        );
2701
2702        // RisingWave's `time` is microsecond-precision.
2703        let arrow = arrow_array::Time64NanosecondArray::from(vec![Some(2_123_456_789)]);
2704        assert_eq!(
2705            TimeArray::try_from(&arrow).unwrap(),
2706            TimeArray::from_iter([Time::with_secs_nano(2, 123_456_000).ok()])
2707        );
2708    }
2709
2710    #[test]
2711    fn time_arrow_units_from_arrow() {
2712        use std::sync::Arc;
2713
2714        struct Dummy;
2715        impl FromArrow for Dummy {}
2716
2717        for arrow_type in [
2718            ArrowType::Time32(arrow_schema::TimeUnit::Second),
2719            ArrowType::Time32(arrow_schema::TimeUnit::Millisecond),
2720            ArrowType::Time64(arrow_schema::TimeUnit::Microsecond),
2721            ArrowType::Time64(arrow_schema::TimeUnit::Nanosecond),
2722        ] {
2723            let field = ArrowField::new("t", arrow_type, true);
2724            assert!(is_parquet_schema_match_source_schema(
2725                field.data_type(),
2726                &RwType::Time
2727            ));
2728            assert_eq!(Dummy.from_field(&field).unwrap(), RwType::Time);
2729        }
2730
2731        let cases: Vec<(arrow_array::ArrayRef, TimeArray)> = vec![
2732            (
2733                Arc::new(arrow_array::Time32SecondArray::from(vec![
2734                    None,
2735                    Some(1),
2736                    Some(2),
2737                ])),
2738                TimeArray::from_iter([
2739                    None,
2740                    Time::with_secs_nano(1, 0).ok(),
2741                    Time::with_secs_nano(2, 0).ok(),
2742                ]),
2743            ),
2744            (
2745                Arc::new(arrow_array::Time32MillisecondArray::from(vec![
2746                    None,
2747                    Some(1_000),
2748                    Some(2_123),
2749                ])),
2750                TimeArray::from_iter([
2751                    None,
2752                    Time::with_secs_nano(1, 0).ok(),
2753                    Time::with_secs_nano(2, 123_000_000).ok(),
2754                ]),
2755            ),
2756            (
2757                Arc::new(arrow_array::Time64MicrosecondArray::from(vec![
2758                    None,
2759                    Some(1_000_000),
2760                    Some(2_123_456),
2761                ])),
2762                TimeArray::from_iter([
2763                    None,
2764                    Time::with_secs_nano(1, 0).ok(),
2765                    Time::with_secs_nano(2, 123_456_000).ok(),
2766                ]),
2767            ),
2768            (
2769                Arc::new(arrow_array::Time64NanosecondArray::from(vec![
2770                    None,
2771                    Some(1_000_000_000),
2772                    Some(2_123_456_789),
2773                ])),
2774                TimeArray::from_iter([
2775                    None,
2776                    Time::with_secs_nano(1, 0).ok(),
2777                    Time::with_secs_nano(2, 123_456_000).ok(),
2778                ]),
2779            ),
2780        ];
2781
2782        for (array, expected) in cases {
2783            let field = ArrowField::new("t", array.data_type().clone(), true);
2784            let ArrayImpl::Time(actual) = Dummy.from_array(&field, &array).unwrap() else {
2785                panic!("expected RW TimeArray");
2786            };
2787            assert_eq!(actual, expected);
2788        }
2789    }
2790
2791    #[test]
2792    fn time_arrow_units_reject_invalid_values() {
2793        use std::sync::Arc;
2794
2795        struct Dummy;
2796        impl FromArrow for Dummy {}
2797
2798        let cases: Vec<arrow_array::ArrayRef> = vec![
2799            Arc::new(arrow_array::Time32SecondArray::from(vec![Some(-1)])),
2800            Arc::new(arrow_array::Time32SecondArray::from(vec![Some(86_400)])),
2801            Arc::new(arrow_array::Time32MillisecondArray::from(vec![Some(-1)])),
2802            Arc::new(arrow_array::Time32MillisecondArray::from(vec![Some(
2803                86_400_000,
2804            )])),
2805            Arc::new(arrow_array::Time64MicrosecondArray::from(vec![Some(-1)])),
2806            Arc::new(arrow_array::Time64MicrosecondArray::from(vec![Some(
2807                86_400_000_000,
2808            )])),
2809            Arc::new(arrow_array::Time64NanosecondArray::from(vec![Some(-1)])),
2810            Arc::new(arrow_array::Time64NanosecondArray::from(vec![Some(
2811                86_400_000_000_000,
2812            )])),
2813            // Seconds counts at a multiple of 2^32 used to wrap into the valid range.
2814            Arc::new(arrow_array::Time64MicrosecondArray::from(vec![Some(
2815                4_294_967_296_000_000,
2816            )])),
2817            Arc::new(arrow_array::Time64NanosecondArray::from(vec![Some(
2818                4_294_967_296_000_000_000,
2819            )])),
2820        ];
2821
2822        for array in cases {
2823            let field = ArrowField::new("t", array.data_type().clone(), true);
2824            assert_from_arrow_error(Dummy.from_array(&field, &array));
2825        }
2826    }
2827
2828    #[test]
2829    fn timestamp() {
2830        let array =
2831            TimestampArray::from_iter([None, Timestamp::with_micros(123456789012345678).ok()]);
2832        let arrow = arrow_array::TimestampMicrosecondArray::try_from(&array).unwrap();
2833        assert_eq!(TimestampArray::try_from(&arrow).unwrap(), array);
2834    }
2835
2836    #[test]
2837    fn timestamp_nanosecond_export_rejects_out_of_range_values() {
2838        // Beyond ±year 2262, the value does not fit in `i64` nanoseconds.
2839        let timestamp_array =
2840            TimestampArray::from_iter([Timestamp::with_micros(9_300_000_000_000_000).ok()]);
2841        let err = arrow_array::TimestampNanosecondArray::try_from(&timestamp_array).unwrap_err();
2842        assert!(matches!(err, ArrayError::ToArrow(_)), "got {err:?}");
2843
2844        let timestamptz_array =
2845            TimestamptzArray::from_iter([Timestamptz::from_micros(9_300_000_000_000_000).unwrap()]);
2846        let err = arrow_array::TimestampNanosecondArray::try_from(&timestamptz_array).unwrap_err();
2847        assert!(matches!(err, ArrayError::ToArrow(_)), "got {err:?}");
2848    }
2849
2850    #[test]
2851    fn timestamp_arrow_units_reject_invalid_values() {
2852        let invalid_second = arrow_array::TimestampSecondArray::from(vec![Some(i64::MAX)]);
2853        let invalid_millisecond =
2854            arrow_array::TimestampMillisecondArray::from(vec![Some(i64::MAX)]);
2855        let invalid_microsecond =
2856            arrow_array::TimestampMicrosecondArray::from(vec![Some(i64::MAX)]);
2857
2858        assert_from_arrow_error(TimestampArray::try_from(&invalid_second));
2859        assert_from_arrow_error(TimestampArray::try_from(&invalid_millisecond));
2860        assert_from_arrow_error(TimestampArray::try_from(&invalid_microsecond));
2861    }
2862
2863    #[test]
2864    fn timestamptz_arrow_units_reject_invalid_values() {
2865        let invalid_second = arrow_array::TimestampSecondArray::from(vec![Some(i64::MAX)]);
2866        let invalid_millisecond =
2867            arrow_array::TimestampMillisecondArray::from(vec![Some(i64::MAX)]);
2868        let invalid_microsecond =
2869            arrow_array::TimestampMicrosecondArray::from(vec![Some(i64::MAX)]);
2870        // Within `checked_mul` range, but past what chrono can represent.
2871        let unrepresentable_second =
2872            arrow_array::TimestampSecondArray::from(vec![Some(9_000_000_000_000)]);
2873
2874        assert_from_arrow_error(TimestamptzArray::try_from(&invalid_second));
2875        assert_from_arrow_error(TimestamptzArray::try_from(&invalid_millisecond));
2876        assert_from_arrow_error(TimestamptzArray::try_from(&invalid_microsecond));
2877        assert_from_arrow_error(TimestamptzArray::try_from(&unrepresentable_second));
2878    }
2879
2880    #[test]
2881    fn date_rejects_out_of_range_arrow_value() {
2882        let valid = arrow_array::Date32Array::from(vec![Some(0), None]);
2883        assert_eq!(
2884            DateArray::try_from(&valid).unwrap(),
2885            DateArray::from_iter([Date::with_days_since_unix_epoch(0).ok(), None])
2886        );
2887
2888        // chrono's `NaiveDate` tops out well below `i32::MAX` days from the epoch.
2889        let out_of_range = arrow_array::Date32Array::from(vec![Some(1_000_000_000)]);
2890        assert_from_arrow_error(DateArray::try_from(&out_of_range));
2891    }
2892
2893    #[test]
2894    fn interval_rejects_out_of_range_microseconds() {
2895        let array = IntervalArray::from_iter([Interval::from_month_day_usec(0, 0, i64::MAX)]);
2896        let err = arrow_array::IntervalMonthDayNanoArray::try_from(&array).unwrap_err();
2897        assert!(matches!(err, ArrayError::ToArrow(_)), "got {err:?}");
2898    }
2899
2900    #[test]
2901    fn interval_truncates_sub_microsecond_nanos() {
2902        let arrow = arrow_array::IntervalMonthDayNanoArray::from(vec![
2903            Some(ArrowIntervalType::new(0, 0, 1_999)),
2904            Some(ArrowIntervalType::new(0, 0, -1)),
2905            Some(ArrowIntervalType::new(0, 0, -1_999)),
2906        ]);
2907        assert_eq!(
2908            IntervalArray::try_from(&arrow).unwrap(),
2909            IntervalArray::from_iter([
2910                Interval::from_month_day_usec(0, 0, 1),
2911                Interval::from_month_day_usec(0, 0, 0),
2912                Interval::from_month_day_usec(0, 0, -1),
2913            ])
2914        );
2915    }
2916
2917    fn assert_from_arrow_error<T>(result: Result<T, ArrayError>) {
2918        match result {
2919            Err(ArrayError::FromArrow(_)) => {}
2920            Err(err) => panic!("expected FromArrow error, got {err:?}"),
2921            Ok(_) => panic!("expected FromArrow error, got Ok"),
2922        }
2923    }
2924
2925    #[test]
2926    fn interval() {
2927        let array = IntervalArray::from_iter([
2928            None,
2929            Some(Interval::from_month_day_usec(
2930                1_000_000,
2931                1_000,
2932                1_000_000_000,
2933            )),
2934            Some(Interval::from_month_day_usec(
2935                -1_000_000,
2936                -1_000,
2937                -1_000_000_000,
2938            )),
2939        ]);
2940        let arrow = arrow_array::IntervalMonthDayNanoArray::try_from(&array).unwrap();
2941        assert_eq!(IntervalArray::try_from(&arrow).unwrap(), array);
2942    }
2943
2944    #[test]
2945    fn string() {
2946        let array = Utf8Array::from_iter([None, Some("array"), Some("arrow")]);
2947        let arrow = arrow_array::StringArray::from(&array);
2948        assert_eq!(Utf8Array::from(&arrow), array);
2949    }
2950
2951    #[test]
2952    fn binary() {
2953        let array = BytesArray::from_iter([None, Some("array".as_bytes())]);
2954        let arrow = arrow_array::BinaryArray::from(&array);
2955        assert_eq!(BytesArray::from(&arrow), array);
2956    }
2957
2958    #[test]
2959    fn fixed_size_binary() {
2960        let uuid = [
2961            0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc,
2962            0xde, 0xf0,
2963        ];
2964        let arrow_array = arrow_array::FixedSizeBinaryArray::try_from_sparse_iter_with_size(
2965            [None, Some(uuid)].into_iter(),
2966            16,
2967        )
2968        .unwrap();
2969        let field =
2970            arrow_schema::Field::new("u", arrow_schema::DataType::FixedSizeBinary(16), true);
2971
2972        assert_eq!(Dummy.from_field(&field).unwrap(), DataType::Bytea);
2973
2974        let rw_array = Dummy
2975            .from_array(&field, &(Arc::new(arrow_array) as arrow_array::ArrayRef))
2976            .unwrap();
2977        let expected = BytesArray::from_iter([None, Some(uuid.as_slice())]);
2978        assert_eq!(rw_array.as_bytea(), &expected);
2979    }
2980
2981    #[test]
2982    fn decimal() {
2983        let array = DecimalArray::from_iter([
2984            None,
2985            Some(Decimal::NaN),
2986            Some(Decimal::PositiveInf),
2987            Some(Decimal::NegativeInf),
2988            Some(Decimal::Normalized("123.4".parse().unwrap())),
2989            Some(Decimal::Normalized("123.456".parse().unwrap())),
2990        ]);
2991        let arrow = arrow_array::LargeBinaryArray::from(&array);
2992        assert_eq!(DecimalArray::try_from(&arrow).unwrap(), array);
2993
2994        let arrow = arrow_array::StringArray::from(&array);
2995        assert_eq!(DecimalArray::try_from(&arrow).unwrap(), array);
2996    }
2997
2998    #[test]
2999    fn jsonb() {
3000        let array = JsonbArray::from_iter([
3001            None,
3002            Some("null".parse().unwrap()),
3003            Some("false".parse().unwrap()),
3004            Some("1".parse().unwrap()),
3005            Some("[1, 2, 3]".parse().unwrap()),
3006            Some(r#"{ "a": 1, "b": null }"#.parse().unwrap()),
3007        ]);
3008        let arrow = arrow_array::LargeStringArray::from(&array);
3009        assert_eq!(JsonbArray::try_from(&arrow).unwrap(), array);
3010
3011        let arrow = arrow_array::StringArray::from(&array);
3012        assert_eq!(JsonbArray::try_from(&arrow).unwrap(), array);
3013    }
3014
3015    #[test]
3016    fn int256() {
3017        let values = [
3018            None,
3019            Some(Int256::from(1)),
3020            Some(Int256::from(i64::MAX)),
3021            Some(Int256::from(i64::MAX) * Int256::from(i64::MAX)),
3022            Some(Int256::from(i64::MAX) * Int256::from(i64::MAX) * Int256::from(i64::MAX)),
3023            Some(
3024                Int256::from(i64::MAX)
3025                    * Int256::from(i64::MAX)
3026                    * Int256::from(i64::MAX)
3027                    * Int256::from(i64::MAX),
3028            ),
3029            Some(Int256::min_value()),
3030            Some(Int256::max_value()),
3031        ];
3032
3033        let array =
3034            Int256Array::from_iter(values.iter().map(|r| r.as_ref().map(|x| x.as_scalar_ref())));
3035        let arrow = arrow_array::Decimal256Array::from(&array);
3036        assert_eq!(Int256Array::from(&arrow), array);
3037    }
3038}