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