From 98c2469acd7f2f371b15abdca31b842a30d7f9df Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Wed, 5 Nov 2025 18:43:53 -0500 Subject: [PATCH 1/4] [Variant] Enforce shredded-type validation in `shred_variant` --- parquet-variant-compute/src/shred_variant.rs | 86 ++++++++++++++++++- .../src/variant_to_arrow.rs | 5 -- 2 files changed, 83 insertions(+), 8 deletions(-) diff --git a/parquet-variant-compute/src/shred_variant.rs b/parquet-variant-compute/src/shred_variant.rs index 4e6a72e87aac..51306ebd1697 100644 --- a/parquet-variant-compute/src/shred_variant.rs +++ b/parquet-variant-compute/src/shred_variant.rs @@ -25,7 +25,7 @@ use crate::{VariantArray, VariantValueArrayBuilder}; use arrow::array::{ArrayRef, BinaryViewArray, NullBufferBuilder}; use arrow::buffer::NullBuffer; use arrow::compute::CastOptions; -use arrow::datatypes::{DataType, Fields}; +use arrow::datatypes::{DataType, Fields, TimeUnit}; use arrow::error::{ArrowError, Result}; use parquet_variant::{Variant, VariantBuilderExt}; @@ -123,13 +123,39 @@ pub(crate) fn make_variant_to_shredded_variant_arrow_row_builder<'a>( "Shredding variant array values as arrow lists".to_string(), )); } - _ => { + // Supported shredded primitive types, see Variant shredding spec: + // https://github.com/apache/parquet-format/blob/master/VariantShredding.md#shredded-value-types + DataType::Boolean + | DataType::Int8 + | DataType::Int16 + | DataType::Int32 + | DataType::Int64 + | DataType::Float32 + | DataType::Float64 + | DataType::Decimal32(..) + | DataType::Decimal64(..) + | DataType::Decimal128(..) + | DataType::Date32 + | DataType::Time64(TimeUnit::Microsecond) + | DataType::Timestamp(TimeUnit::Microsecond | TimeUnit::Nanosecond, _) + | DataType::Binary + | DataType::BinaryView + | DataType::Utf8 + | DataType::Utf8View + | DataType::FixedSizeBinary(16) // UUID + => { let builder = make_primitive_variant_to_arrow_row_builder(data_type, cast_options, capacity)?; let typed_value_builder = VariantToShreddedPrimitiveVariantRowBuilder::new(builder, capacity, top_level); VariantToShreddedVariantRowBuilder::Primitive(typed_value_builder) } + DataType::FixedSizeBinary(_) => { + return Err(ArrowError::InvalidArgumentError(format!("{data_type} is not a valid variant shredding type. Only FixedSizeBinary(16) for UUID is supported."))) + } + _ => { + return Err(ArrowError::InvalidArgumentError(format!("{data_type} is not a valid variant shredding type"))) + } }; Ok(builder) } @@ -327,7 +353,7 @@ mod tests { use super::*; use crate::VariantArrayBuilder; use arrow::array::{Array, FixedSizeBinaryArray, Float64Array, Int64Array}; - use arrow::datatypes::{DataType, Field, Fields}; + use arrow::datatypes::{DataType, Field, Fields, TimeUnit, UnionFields, UnionMode}; use parquet_variant::{ObjectBuilder, ReadOnlyMetadataBuilder, Variant, VariantBuilder}; use std::sync::Arc; use uuid::Uuid; @@ -536,6 +562,60 @@ mod tests { assert!(typed_value_float64.is_null(2)); // string doesn't convert } + #[test] + fn test_invalid_shredded_types_rejected() { + let input = VariantArray::from_iter([Variant::from(42)]); + + let invalid_types = vec![ + DataType::UInt8, + DataType::Float16, + DataType::Decimal256(38, 10), + DataType::Date64, + DataType::Time32(TimeUnit::Second), + DataType::Time64(TimeUnit::Nanosecond), + DataType::Timestamp(TimeUnit::Millisecond, None), + DataType::LargeBinary, + DataType::LargeUtf8, + DataType::FixedSizeBinary(17), + DataType::Union( + UnionFields::new( + vec![0_i8, 1_i8], + vec![ + Field::new("int_field", DataType::Int32, false), + Field::new("str_field", DataType::Utf8, true), + ], + ), + UnionMode::Dense, + ), + DataType::Map( + Arc::new(Field::new( + "entries", + DataType::Struct(Fields::from(vec![ + Field::new("key", DataType::Utf8, false), + Field::new("value", DataType::Int32, true), + ])), + false, + )), + false, + ), + DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)), + DataType::RunEndEncoded( + Arc::new(Field::new("run_ends", DataType::Int32, false)), + Arc::new(Field::new("values", DataType::Utf8, true)), + ), + ]; + + for data_type in invalid_types { + let err = shred_variant(&input, &data_type).unwrap_err(); + assert!( + matches!(err, ArrowError::InvalidArgumentError(_)), + "expected InvalidArgumentError for {:?}, got {:?}", + data_type, + err + ); + } + } + #[test] fn test_object_shredding_comprehensive() { let mut builder = VariantArrayBuilder::new(7); diff --git a/parquet-variant-compute/src/variant_to_arrow.rs b/parquet-variant-compute/src/variant_to_arrow.rs index b8030bc71575..f051abe93c85 100644 --- a/parquet-variant-compute/src/variant_to_arrow.rs +++ b/parquet-variant-compute/src/variant_to_arrow.rs @@ -312,11 +312,6 @@ pub(crate) fn make_primitive_variant_to_arrow_row_builder<'a>( DataType::FixedSizeBinary(16) => { Uuid(VariantToUuidArrowRowBuilder::new(cast_options, capacity)) } - DataType::FixedSizeBinary(size) => { - return Err(ArrowError::InvalidArgumentError(format!( - "FixedSizeBinary({size}) is not a valid variant shredding type. Only FixedSizeBinary(16) for UUID is supported." - ))); - } DataType::Utf8 => String(VariantToStringArrowBuilder::new(cast_options, capacity)), DataType::LargeUtf8 => { LargeString(VariantToStringArrowBuilder::new(cast_options, capacity)) From 9ecdfca6a6bf9381f5901ecc875f665c837736e3 Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Wed, 5 Nov 2025 19:58:22 -0500 Subject: [PATCH 2/4] fmt and doc --- .../src/variant_to_arrow.rs | 211 ++++++++---------- 1 file changed, 99 insertions(+), 112 deletions(-) diff --git a/parquet-variant-compute/src/variant_to_arrow.rs b/parquet-variant-compute/src/variant_to_arrow.rs index f051abe93c85..049691f9b621 100644 --- a/parquet-variant-compute/src/variant_to_arrow.rs +++ b/parquet-variant-compute/src/variant_to_arrow.rs @@ -33,7 +33,7 @@ use crate::{VariantArray, VariantValueArrayBuilder}; use arrow_schema::TimeUnit; use std::sync::Arc; -/// Builder for converting variant values to primitive Arrow arrays. It is used by both +/// Builder for converting primitive variant values to Arrow arrays. It is used by both /// `VariantToArrowRowBuilder` (below) and `VariantToShreddedPrimitiveVariantRowBuilder` (in /// `shred_variant.rs`). pub(crate) enum PrimitiveVariantToArrowRowBuilder<'a> { @@ -210,7 +210,7 @@ impl<'a> VariantToArrowRowBuilder<'a> { } } -/// Creates a primitive row builder, returning Err if the requested data type is not primitive. +/// Creates a row builder that converts primitive `Variant` values into the requested Arrow data type. pub(crate) fn make_primitive_variant_to_arrow_row_builder<'a>( data_type: &'a DataType, cast_options: &'a CastOptions, @@ -218,116 +218,103 @@ pub(crate) fn make_primitive_variant_to_arrow_row_builder<'a>( ) -> Result> { use PrimitiveVariantToArrowRowBuilder::*; - let builder = match data_type { - DataType::Null => Null(VariantToNullArrowRowBuilder::new(cast_options, capacity)), - DataType::Boolean => Boolean(VariantToBooleanArrowRowBuilder::new(cast_options, capacity)), - DataType::Int8 => Int8(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::Int16 => Int16(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::Int32 => Int32(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::Int64 => Int64(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::UInt8 => UInt8(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::UInt16 => UInt16(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::UInt32 => UInt32(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::UInt64 => UInt64(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::Float16 => Float16(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::Float32 => Float32(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::Float64 => Float64(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::Decimal32(precision, scale) => Decimal32(VariantToDecimalArrowRowBuilder::new( - cast_options, - capacity, - *precision, - *scale, - )?), - DataType::Decimal64(precision, scale) => Decimal64(VariantToDecimalArrowRowBuilder::new( - cast_options, - capacity, - *precision, - *scale, - )?), - DataType::Decimal128(precision, scale) => Decimal128(VariantToDecimalArrowRowBuilder::new( - cast_options, - capacity, - *precision, - *scale, - )?), - DataType::Decimal256(precision, scale) => Decimal256(VariantToDecimalArrowRowBuilder::new( - cast_options, - capacity, - *precision, - *scale, - )?), - DataType::Timestamp(TimeUnit::Microsecond, None) => TimestampMicroNtz( - VariantToTimestampNtzArrowRowBuilder::new(cast_options, capacity), - ), - DataType::Timestamp(TimeUnit::Microsecond, tz) => TimestampMicro( - VariantToTimestampArrowRowBuilder::new(cast_options, capacity, tz.clone()), - ), - DataType::Timestamp(TimeUnit::Nanosecond, None) => TimestampNanoNtz( - VariantToTimestampNtzArrowRowBuilder::new(cast_options, capacity), - ), - DataType::Timestamp(TimeUnit::Nanosecond, tz) => TimestampNano( - VariantToTimestampArrowRowBuilder::new(cast_options, capacity, tz.clone()), - ), - DataType::Date32 => Date(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::Time64(TimeUnit::Microsecond) => Time(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::FixedSizeBinary(16) => { - Uuid(VariantToUuidArrowRowBuilder::new(cast_options, capacity)) - } - DataType::Utf8 => String(VariantToStringArrowBuilder::new(cast_options, capacity)), - DataType::LargeUtf8 => { - LargeString(VariantToStringArrowBuilder::new(cast_options, capacity)) - } - DataType::Utf8View => StringView(VariantToStringArrowBuilder::new(cast_options, capacity)), - _ if data_type.is_primitive() => { - return Err(ArrowError::NotYetImplemented(format!( - "Primitive data_type {data_type:?} not yet implemented" - ))); - } - _ => { - return Err(ArrowError::InvalidArgumentError(format!( - "Not a primitive type: {data_type:?}" - ))); - } - }; + let builder = + match data_type { + DataType::Null => Null(VariantToNullArrowRowBuilder::new(cast_options, capacity)), + DataType::Boolean => { + Boolean(VariantToBooleanArrowRowBuilder::new(cast_options, capacity)) + } + DataType::Int8 => Int8(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::Int16 => Int16(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::Int32 => Int32(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::Int64 => Int64(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::UInt8 => UInt8(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::UInt16 => UInt16(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::UInt32 => UInt32(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::UInt64 => UInt64(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::Float16 => Float16(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::Float32 => Float32(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::Float64 => Float64(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::Decimal32(precision, scale) => Decimal32( + VariantToDecimalArrowRowBuilder::new(cast_options, capacity, *precision, *scale)?, + ), + DataType::Decimal64(precision, scale) => Decimal64( + VariantToDecimalArrowRowBuilder::new(cast_options, capacity, *precision, *scale)?, + ), + DataType::Decimal128(precision, scale) => Decimal128( + VariantToDecimalArrowRowBuilder::new(cast_options, capacity, *precision, *scale)?, + ), + DataType::Decimal256(precision, scale) => Decimal256( + VariantToDecimalArrowRowBuilder::new(cast_options, capacity, *precision, *scale)?, + ), + DataType::Timestamp(TimeUnit::Microsecond, None) => TimestampMicroNtz( + VariantToTimestampNtzArrowRowBuilder::new(cast_options, capacity), + ), + DataType::Timestamp(TimeUnit::Microsecond, tz) => TimestampMicro( + VariantToTimestampArrowRowBuilder::new(cast_options, capacity, tz.clone()), + ), + DataType::Timestamp(TimeUnit::Nanosecond, None) => TimestampNanoNtz( + VariantToTimestampNtzArrowRowBuilder::new(cast_options, capacity), + ), + DataType::Timestamp(TimeUnit::Nanosecond, tz) => TimestampNano( + VariantToTimestampArrowRowBuilder::new(cast_options, capacity, tz.clone()), + ), + DataType::Date32 => Date(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::Time64(TimeUnit::Microsecond) => Time( + VariantToPrimitiveArrowRowBuilder::new(cast_options, capacity), + ), + DataType::FixedSizeBinary(16) => { + Uuid(VariantToUuidArrowRowBuilder::new(cast_options, capacity)) + } + DataType::Utf8 => String(VariantToStringArrowBuilder::new(cast_options, capacity)), + DataType::LargeUtf8 => { + LargeString(VariantToStringArrowBuilder::new(cast_options, capacity)) + } + DataType::Utf8View => { + StringView(VariantToStringArrowBuilder::new(cast_options, capacity)) + } + _ => { + return Err(ArrowError::NotYetImplemented(format!( + "Data_type {data_type:?} not yet implemented" + ))); + } + }; Ok(builder) } From aca092c2347bed3a443d2eb8f8242d1e3d730106 Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Mon, 10 Nov 2025 19:01:31 -0500 Subject: [PATCH 3/4] Explicitly list all datatypes --- .../src/variant_to_arrow.rs | 70 ++++++++++++++----- 1 file changed, 53 insertions(+), 17 deletions(-) diff --git a/parquet-variant-compute/src/variant_to_arrow.rs b/parquet-variant-compute/src/variant_to_arrow.rs index afd4b77d5fcd..905f95523cbb 100644 --- a/parquet-variant-compute/src/variant_to_arrow.rs +++ b/parquet-variant-compute/src/variant_to_arrow.rs @@ -292,6 +292,23 @@ pub(crate) fn make_primitive_variant_to_arrow_row_builder<'a>( DataType::Decimal256(precision, scale) => Decimal256( VariantToDecimalArrowRowBuilder::new(cast_options, capacity, *precision, *scale)?, ), + DataType::Date32 => Date(VariantToPrimitiveArrowRowBuilder::new( + cast_options, + capacity, + )), + DataType::Date64 | DataType::Time32(_) => { + return Err(ArrowError::NotYetImplemented(format!( + "DataType {data_type:?} not yet implemented" + ))); + } + DataType::Time64(TimeUnit::Microsecond) => Time( + VariantToPrimitiveArrowRowBuilder::new(cast_options, capacity), + ), + DataType::Time64(_) => { + return Err(ArrowError::NotYetImplemented(format!( + "DataType {data_type:?} not yet implemented" + ))); + } DataType::Timestamp(TimeUnit::Microsecond, None) => TimestampMicroNtz( VariantToTimestampNtzArrowRowBuilder::new(cast_options, capacity), ), @@ -304,22 +321,17 @@ pub(crate) fn make_primitive_variant_to_arrow_row_builder<'a>( DataType::Timestamp(TimeUnit::Nanosecond, tz) => TimestampNano( VariantToTimestampArrowRowBuilder::new(cast_options, capacity, tz.clone()), ), - DataType::Date32 => Date(VariantToPrimitiveArrowRowBuilder::new( - cast_options, - capacity, - )), - DataType::Time64(TimeUnit::Microsecond) => Time( - VariantToPrimitiveArrowRowBuilder::new(cast_options, capacity), - ), - DataType::FixedSizeBinary(16) => { - Uuid(VariantToUuidArrowRowBuilder::new(cast_options, capacity)) - } - DataType::Utf8 => String(VariantToStringArrowBuilder::new(cast_options, capacity)), - DataType::LargeUtf8 => { - LargeString(VariantToStringArrowBuilder::new(cast_options, capacity)) + DataType::Timestamp(..) => { + return Err(ArrowError::NotYetImplemented(format!( + "DataType {data_type:?} not yet implemented" + ))); } - DataType::Utf8View => { - StringView(VariantToStringArrowBuilder::new(cast_options, capacity)) + DataType::Duration(_) | DataType::Interval(_) => { + return Err(ArrowError::InvalidArgumentError( + "Casting Variant to duration/interval types is not supported. \ + The Variant format does not define duration/interval types." + .to_string(), + )); } DataType::Binary => Binary(VariantToBinaryArrowRowBuilder::new(cast_options, capacity)), DataType::LargeBinary => { @@ -328,9 +340,33 @@ pub(crate) fn make_primitive_variant_to_arrow_row_builder<'a>( DataType::BinaryView => { BinaryView(VariantToBinaryArrowRowBuilder::new(cast_options, capacity)) } - _ => { + DataType::FixedSizeBinary(16) => { + Uuid(VariantToUuidArrowRowBuilder::new(cast_options, capacity)) + } + DataType::FixedSizeBinary(_) => { return Err(ArrowError::NotYetImplemented(format!( - "Data_type {data_type:?} not yet implemented" + "DataType {data_type:?} not yet implemented" + ))); + } + DataType::Utf8 => String(VariantToStringArrowBuilder::new(cast_options, capacity)), + DataType::LargeUtf8 => { + LargeString(VariantToStringArrowBuilder::new(cast_options, capacity)) + } + DataType::Utf8View => { + StringView(VariantToStringArrowBuilder::new(cast_options, capacity)) + } + DataType::List(_) + | DataType::LargeList(_) + | DataType::ListView(_) + | DataType::LargeListView(_) + | DataType::FixedSizeList(..) + | DataType::Struct(_) + | DataType::Map(..) + | DataType::Union(..) + | DataType::Dictionary(..) + | DataType::RunEndEncoded(..) => { + return Err(ArrowError::InvalidArgumentError(format!( + "Casting to {data_type:?} is not applicable for primitive Variant types" ))); } }; From a6e38ce3da9c97104f8de06017b33887993dc8d8 Mon Sep 17 00:00:00 2001 From: Liam Bao Date: Mon, 10 Nov 2025 20:47:02 -0500 Subject: [PATCH 4/4] Add tests --- parquet-variant-compute/src/variant_get.rs | 30 +++++++++- .../src/variant_to_arrow.rs | 56 +++++++++++++++++++ 2 files changed, 85 insertions(+), 1 deletion(-) diff --git a/parquet-variant-compute/src/variant_get.rs b/parquet-variant-compute/src/variant_get.rs index 5edcb74a2993..b082035ac08a 100644 --- a/parquet-variant-compute/src/variant_get.rs +++ b/parquet-variant-compute/src/variant_get.rs @@ -320,7 +320,7 @@ mod test { use arrow::datatypes::DataType::{Int16, Int32, Int64}; use arrow::datatypes::i256; use arrow_schema::DataType::{Boolean, Float32, Float64, Int8}; - use arrow_schema::{DataType, Field, FieldRef, Fields, TimeUnit}; + use arrow_schema::{DataType, Field, FieldRef, Fields, IntervalUnit, TimeUnit}; use chrono::DateTime; use parquet_variant::{ EMPTY_VARIANT_METADATA_BYTES, Variant, VariantDecimal4, VariantDecimal8, VariantDecimal16, @@ -3685,6 +3685,34 @@ mod test { )); } + #[test] + fn get_non_supported_temporal_types_error() { + let values = vec![None, Some(Variant::Null), Some(Variant::BooleanFalse)]; + let variant_array: ArrayRef = ArrayRef::from(VariantArray::from_iter(values)); + + let test_cases = vec![ + FieldRef::from(Field::new( + "result", + DataType::Duration(TimeUnit::Microsecond), + true, + )), + FieldRef::from(Field::new( + "result", + DataType::Interval(IntervalUnit::YearMonth), + true, + )), + ]; + + for field in test_cases { + let options = GetOptions::new().with_as_type(Some(field)); + let err = variant_get(&variant_array, options).unwrap_err(); + assert!( + err.to_string() + .contains("Casting Variant to duration/interval types is not supported") + ); + } + } + perfectly_shredded_variant_array_fn!(perfectly_shredded_invalid_time_variant_array, || { // 86401000000 is invalid for Time64Microsecond (max is 86400000000) Time64MicrosecondArray::from(vec![ diff --git a/parquet-variant-compute/src/variant_to_arrow.rs b/parquet-variant-compute/src/variant_to_arrow.rs index 905f95523cbb..6b0e05dd26c6 100644 --- a/parquet-variant-compute/src/variant_to_arrow.rs +++ b/parquet-variant-compute/src/variant_to_arrow.rs @@ -716,3 +716,59 @@ define_variant_to_primitive_builder!( |_value| Some(Variant::Null), type_name: "Null" ); + +#[cfg(test)] +mod tests { + use super::make_primitive_variant_to_arrow_row_builder; + use arrow::compute::CastOptions; + use arrow::datatypes::{DataType, Field, Fields, UnionFields, UnionMode}; + use arrow::error::ArrowError; + use std::sync::Arc; + + #[test] + fn make_primitive_builder_rejects_non_primitive_types() { + let cast_options = CastOptions::default(); + let item_field = Arc::new(Field::new("item", DataType::Int32, true)); + let struct_fields = Fields::from(vec![Field::new("child", DataType::Int32, true)]); + let map_entries_field = Arc::new(Field::new( + "entries", + DataType::Struct(Fields::from(vec![ + Field::new("key", DataType::Utf8, false), + Field::new("value", DataType::Float64, true), + ])), + true, + )); + let union_fields = + UnionFields::new(vec![1], vec![Field::new("child", DataType::Int32, true)]); + let run_ends_field = Arc::new(Field::new("run_ends", DataType::Int32, false)); + let ree_values_field = Arc::new(Field::new("values", DataType::Utf8, true)); + + let non_primitive_types = vec![ + DataType::List(item_field.clone()), + DataType::LargeList(item_field.clone()), + DataType::ListView(item_field.clone()), + DataType::LargeListView(item_field.clone()), + DataType::FixedSizeList(item_field.clone(), 2), + DataType::Struct(struct_fields.clone()), + DataType::Map(map_entries_field.clone(), false), + DataType::Union(union_fields.clone(), UnionMode::Dense), + DataType::Dictionary(Box::new(DataType::Int32), Box::new(DataType::Utf8)), + DataType::RunEndEncoded(run_ends_field.clone(), ree_values_field.clone()), + ]; + + for data_type in non_primitive_types { + let err = + match make_primitive_variant_to_arrow_row_builder(&data_type, &cast_options, 1) { + Ok(_) => panic!("non-primitive type {data_type:?} should be rejected"), + Err(err) => err, + }; + + match err { + ArrowError::InvalidArgumentError(msg) => { + assert!(msg.contains(&format!("{data_type:?}"))); + } + other => panic!("expected InvalidArgumentError, got {other:?}"), + } + } + } +}