1use crate::VariantArrayBuilder;
21use crate::type_conversion::{
22 generic_conversion_single_value, generic_conversion_single_value_with_result,
23 primitive_conversion_single_value,
24};
25use arrow::array::{Array, ArrayRef, AsArray, StructArray, new_null_array};
26use arrow::buffer::NullBuffer;
27use arrow::compute::cast;
28use arrow::datatypes::{
29 Date32Type, Decimal32Type, Decimal64Type, Decimal128Type, Float16Type, Float32Type,
30 Float64Type, Int8Type, Int16Type, Int32Type, Int64Type, Time64MicrosecondType,
31 TimestampMicrosecondType, TimestampNanosecondType,
32};
33use arrow::error::Result;
34use arrow_schema::extension::{ExtensionType, Uuid as UuidExtension};
35use arrow_schema::{ArrowError, DataType, Field, FieldRef, Fields, TimeUnit};
36use chrono::{DateTime, NaiveTime};
37use parquet_variant::{
38 Uuid, Variant, VariantDecimal4, VariantDecimal8, VariantDecimal16, VariantDecimalType as _,
39};
40
41use std::borrow::Cow;
42use std::sync::Arc;
43
44pub(crate) fn binary_array_value(array: &dyn Array, index: usize) -> Option<&[u8]> {
46 match array.data_type() {
47 DataType::Binary => Some(array.as_binary::<i32>().value(index)),
48 DataType::LargeBinary => Some(array.as_binary::<i64>().value(index)),
49 DataType::BinaryView => Some(array.as_binary_view().value(index)),
50 _ => None,
51 }
52}
53
54pub(crate) fn variant_from_arrays_at<'m, 'v>(
57 metadata: &'m dyn Array,
58 value: &'v dyn Array,
59 index: usize,
60) -> Option<Variant<'m, 'v>> {
61 let metadata = binary_array_value(metadata, index)?;
62 let value = binary_array_value(value, index)?;
63 Some(Variant::new(metadata, value))
64}
65
66pub(crate) fn all_null_value_column(len: usize) -> ArrayRef {
72 new_null_array(&DataType::BinaryView, len)
73}
74
75pub(crate) fn validate_binary_array(array: &dyn Array, field_name: &str) -> Result<()> {
77 match array.data_type() {
78 DataType::Binary | DataType::LargeBinary | DataType::BinaryView => Ok(()),
79 _ => Err(ArrowError::InvalidArgumentError(format!(
80 "VariantArray '{field_name}' field must be Binary, LargeBinary, or BinaryView, got {}",
81 array.data_type()
82 ))),
83 }
84}
85
86pub struct VariantType;
91
92impl ExtensionType for VariantType {
93 const NAME: &'static str = "arrow.parquet.variant";
94
95 type Metadata = &'static str;
98
99 fn metadata(&self) -> &Self::Metadata {
100 &""
101 }
102
103 fn serialize_metadata(&self) -> Option<String> {
104 Some(String::new())
105 }
106
107 fn deserialize_metadata(_metadata: Option<&str>) -> Result<Self::Metadata> {
108 Ok("")
109 }
110
111 fn supports_data_type(&self, data_type: &DataType) -> Result<()> {
112 if matches!(data_type, DataType::Struct(_)) {
113 Ok(())
114 } else {
115 Err(ArrowError::InvalidArgumentError(format!(
116 "VariantType only supports StructArray, got {data_type}"
117 )))
118 }
119 }
120
121 fn try_new(data_type: &DataType, _metadata: Self::Metadata) -> Result<Self> {
122 Self.supports_data_type(data_type)?;
123 Ok(Self)
124 }
125
126 fn validate(data_type: &DataType, _metadata: Self::Metadata) -> Result<()> {
127 Self.supports_data_type(data_type)
128 }
129}
130
131#[derive(Debug, Clone)]
262pub struct VariantArray {
263 inner: StructArray,
265
266 metadata: ArrayRef,
268
269 shredding_state: ShreddingState,
271}
272
273impl VariantArray {
274 pub fn try_new(inner: &dyn Array) -> Result<Self> {
301 let inner = canonicalize_shredded_types(inner)?;
303
304 let Some(inner) = inner.as_struct_opt() else {
305 return Err(ArrowError::InvalidArgumentError(
306 "Invalid VariantArray: requires StructArray as input".to_string(),
307 ));
308 };
309
310 let Some(metadata_col) = inner.column_by_name("metadata") else {
314 return Err(ArrowError::InvalidArgumentError(
315 "Invalid VariantArray: StructArray must contain a 'metadata' field".to_string(),
316 ));
317 };
318 validate_binary_array(metadata_col.as_ref(), "metadata")?;
319
320 let shredding_state = ShreddingState::try_from(inner)?;
321
322 if inner.column_by_name("value").is_none() {
325 return Ok(Self::from_parts(
326 metadata_col.clone(),
327 shredding_state.value_column().clone(),
328 shredding_state.typed_value_column().cloned(),
329 inner.nulls().cloned(),
330 ));
331 }
332
333 Ok(Self {
335 inner: inner.clone(),
336 metadata: metadata_col.clone(),
337 shredding_state,
338 })
339 }
340
341 pub(crate) fn from_parts(
346 metadata: ArrayRef,
347 value: ArrayRef,
348 typed_value: Option<ArrayRef>,
349 nulls: Option<NullBuffer>,
350 ) -> Self {
351 Self::from_parts_with_nullable_value(metadata, value, typed_value, nulls, true)
352 }
353
354 pub(crate) fn from_parts_unshredded(
360 metadata: ArrayRef,
361 value: ArrayRef,
362 nulls: Option<NullBuffer>,
363 ) -> Self {
364 Self::from_parts_with_nullable_value(metadata, value, None, nulls, false)
365 }
366
367 fn from_parts_with_nullable_value(
368 metadata: ArrayRef,
369 value: ArrayRef,
370 typed_value: Option<ArrayRef>,
371 nulls: Option<NullBuffer>,
372 value_nullable: bool,
373 ) -> Self {
374 let mut builder = StructArrayBuilder::new()
375 .with_field("metadata", metadata.clone(), false)
376 .with_field("value", value.clone(), value_nullable);
377 if let Some(typed_value) = typed_value.clone() {
378 builder = builder.with_field_ref(typed_value_field(&typed_value), typed_value);
379 }
380 if let Some(nulls) = nulls {
381 builder = builder.with_nulls(nulls);
382 }
383
384 Self {
385 inner: builder.build(),
386 metadata,
387 shredding_state: ShreddingState::new(value, typed_value),
388 }
389 }
390
391 pub fn inner(&self) -> &StructArray {
393 &self.inner
394 }
395
396 pub fn into_inner(self) -> StructArray {
398 self.inner
399 }
400
401 pub fn shredding_state(&self) -> &ShreddingState {
403 &self.shredding_state
404 }
405
406 pub fn value(&self, index: usize) -> Variant<'_, '_> {
416 self.try_value(index).unwrap()
417 }
418
419 pub fn try_value(&self, index: usize) -> Result<Variant<'_, '_>> {
447 let value = self.value_column();
448 match self.typed_value_column() {
449 Some(typed_value) if typed_value.is_valid(index) => {
451 if !matches!(typed_value.data_type(), DataType::Struct(_)) && value.is_valid(index) {
452 panic!("Invalid variant, conflicting value and typed_value");
454 }
455 typed_value_to_variant(typed_value, index)
456 }
457 _ if value.is_valid(index) => variant_from_arrays_at(&self.metadata, value, index)
459 .ok_or_else(|| {
460 ArrowError::InvalidArgumentError(format!(
461 "metadata and value fields must be binary-like arrays, instead got {} and {}",
462 self.metadata.data_type(),
463 value.data_type()
464 ))
465 }),
466 _ => Ok(Variant::Null),
469 }
470 }
471
472 pub fn metadata_column(&self) -> &ArrayRef {
474 &self.metadata
475 }
476
477 pub fn value_column(&self) -> &ArrayRef {
479 self.shredding_state.value_column()
480 }
481
482 pub fn typed_value_column(&self) -> Option<&ArrayRef> {
484 self.shredding_state.typed_value_column()
485 }
486
487 pub fn field(&self, name: impl Into<String>) -> Field {
490 Field::new(
491 name.into(),
492 self.data_type().clone(),
493 self.inner.is_nullable(),
494 )
495 .with_extension_type(VariantType)
496 }
497
498 pub fn data_type(&self) -> &DataType {
500 self.inner.data_type()
501 }
502
503 pub fn slice(&self, offset: usize, length: usize) -> Self {
504 let inner = self.inner.slice(offset, length);
505 let metadata = self.metadata.slice(offset, length);
506 let shredding_state = self.shredding_state.slice(offset, length);
507 Self {
508 inner,
509 metadata,
510 shredding_state,
511 }
512 }
513
514 pub fn len(&self) -> usize {
515 self.inner.len()
516 }
517
518 pub fn is_empty(&self) -> bool {
519 self.inner.is_empty()
520 }
521
522 pub fn nulls(&self) -> Option<&NullBuffer> {
523 self.inner.nulls()
524 }
525
526 pub fn is_null(&self, index: usize) -> bool {
528 self.nulls().is_some_and(|n| n.is_null(index))
529 }
530
531 pub fn is_valid(&self, index: usize) -> bool {
533 !self.is_null(index)
534 }
535
536 pub fn iter(&self) -> VariantArrayIter<'_> {
538 VariantArrayIter::new(self)
539 }
540}
541
542impl PartialEq for VariantArray {
543 fn eq(&self, other: &Self) -> bool {
544 self.inner == other.inner
545 }
546}
547
548impl From<VariantArray> for StructArray {
549 fn from(variant_array: VariantArray) -> Self {
550 variant_array.into_inner()
551 }
552}
553
554impl From<VariantArray> for ArrayRef {
555 fn from(variant_array: VariantArray) -> Self {
556 Arc::new(variant_array.into_inner())
557 }
558}
559
560impl<'m, 'v> FromIterator<Option<Variant<'m, 'v>>> for VariantArray {
561 fn from_iter<T: IntoIterator<Item = Option<Variant<'m, 'v>>>>(iter: T) -> Self {
562 let iter = iter.into_iter();
563
564 let mut b = VariantArrayBuilder::new(iter.size_hint().0);
565 b.extend(iter);
566 b.build()
567 }
568}
569
570impl<'m, 'v> FromIterator<Variant<'m, 'v>> for VariantArray {
571 fn from_iter<T: IntoIterator<Item = Variant<'m, 'v>>>(iter: T) -> Self {
572 Self::from_iter(iter.into_iter().map(Some))
573 }
574}
575
576#[derive(Debug)]
601pub struct VariantArrayIter<'a> {
602 array: &'a VariantArray,
603 head_i: usize,
604 tail_i: usize,
605}
606
607impl<'a> VariantArrayIter<'a> {
608 pub fn new(array: &'a VariantArray) -> Self {
610 Self {
611 array,
612 head_i: 0,
613 tail_i: array.len(),
614 }
615 }
616
617 fn value_opt(&self, i: usize) -> Option<Variant<'a, 'a>> {
618 self.array.is_valid(i).then(|| self.array.value(i))
619 }
620}
621
622impl<'a> Iterator for VariantArrayIter<'a> {
623 type Item = Option<Variant<'a, 'a>>;
624
625 #[inline]
626 fn next(&mut self) -> Option<Self::Item> {
627 if self.head_i == self.tail_i {
628 return None;
629 }
630
631 let out = self.value_opt(self.head_i);
632
633 self.head_i += 1;
634
635 Some(out)
636 }
637
638 fn size_hint(&self) -> (usize, Option<usize>) {
639 let remainder = self.tail_i - self.head_i;
640
641 (remainder, Some(remainder))
642 }
643}
644
645impl<'a> DoubleEndedIterator for VariantArrayIter<'a> {
646 fn next_back(&mut self) -> Option<Self::Item> {
647 if self.head_i == self.tail_i {
648 return None;
649 }
650
651 self.tail_i -= 1;
652
653 Some(self.value_opt(self.tail_i))
654 }
655}
656
657impl<'a> ExactSizeIterator for VariantArrayIter<'a> {}
658
659#[derive(Debug)]
694pub struct ShreddedVariantFieldArray {
695 inner: StructArray,
697 shredding_state: ShreddingState,
698}
699
700impl ShreddedVariantFieldArray {
701 pub fn try_new(inner: &dyn Array) -> Result<Self> {
721 let Some(inner_struct) = inner.as_struct_opt() else {
722 return Err(ArrowError::InvalidArgumentError(
723 "Invalid ShreddedVariantFieldArray: requires StructArray as input".to_string(),
724 ));
725 };
726
727 let shredding_state = ShreddingState::try_from(inner_struct)?;
728
729 if inner_struct.column_by_name("value").is_none() {
732 return Ok(Self::from_parts(
733 shredding_state.value_column().clone(),
734 shredding_state.typed_value_column().cloned(),
735 inner_struct.nulls().cloned(),
736 ));
737 }
738
739 Ok(Self {
741 inner: inner_struct.clone(),
742 shredding_state,
743 })
744 }
745
746 pub fn shredding_state(&self) -> &ShreddingState {
748 &self.shredding_state
749 }
750
751 pub fn value_column(&self) -> &ArrayRef {
753 self.shredding_state.value_column()
754 }
755
756 pub fn typed_value_column(&self) -> Option<&ArrayRef> {
758 self.shredding_state.typed_value_column()
759 }
760
761 pub fn inner(&self) -> &StructArray {
763 &self.inner
764 }
765
766 pub(crate) fn from_parts(
767 value: ArrayRef,
768 typed_value: Option<ArrayRef>,
769 nulls: Option<NullBuffer>,
770 ) -> Self {
771 let mut builder = StructArrayBuilder::new().with_field("value", value.clone(), true);
772 if let Some(typed_value) = typed_value.clone() {
773 builder = builder.with_field_ref(typed_value_field(&typed_value), typed_value);
774 }
775 if let Some(nulls) = nulls {
776 builder = builder.with_nulls(nulls);
777 }
778
779 Self {
780 inner: builder.build(),
781 shredding_state: ShreddingState::new(value, typed_value),
782 }
783 }
784
785 pub fn into_inner(self) -> StructArray {
787 self.inner
788 }
789
790 pub fn data_type(&self) -> &DataType {
791 self.inner.data_type()
792 }
793
794 pub fn len(&self) -> usize {
795 self.inner.len()
796 }
797
798 pub fn is_empty(&self) -> bool {
799 self.inner.is_empty()
800 }
801
802 pub fn offset(&self) -> usize {
803 self.inner.offset()
804 }
805
806 pub fn nulls(&self) -> Option<&NullBuffer> {
807 None
811 }
812 pub fn is_null(&self, index: usize) -> bool {
814 self.nulls().is_some_and(|n| n.is_null(index))
815 }
816
817 pub fn is_valid(&self, index: usize) -> bool {
819 !self.is_null(index)
820 }
821}
822
823impl From<ShreddedVariantFieldArray> for ArrayRef {
824 fn from(array: ShreddedVariantFieldArray) -> Self {
825 Arc::new(array.into_inner())
826 }
827}
828
829impl From<ShreddedVariantFieldArray> for StructArray {
830 fn from(array: ShreddedVariantFieldArray) -> Self {
831 array.into_inner()
832 }
833}
834
835#[derive(Debug, Clone)]
872pub struct ShreddingState {
873 value: ArrayRef,
874 typed_value: Option<ArrayRef>,
875}
876
877impl ShreddingState {
878 pub fn new(value: ArrayRef, typed_value: Option<ArrayRef>) -> Self {
893 Self { value, typed_value }
894 }
895
896 pub fn value_column(&self) -> &ArrayRef {
898 &self.value
899 }
900
901 pub fn typed_value_column(&self) -> Option<&ArrayRef> {
903 self.typed_value.as_ref()
904 }
905
906 pub fn slice(&self, offset: usize, length: usize) -> Self {
908 Self {
909 value: self.value.slice(offset, length),
910 typed_value: self.typed_value.as_ref().map(|tv| tv.slice(offset, length)),
911 }
912 }
913}
914
915impl TryFrom<&StructArray> for ShreddingState {
916 type Error = ArrowError;
917
918 fn try_from(inner_struct: &StructArray) -> Result<Self> {
919 let typed_value = inner_struct.column_by_name("typed_value").cloned();
920 let value = match inner_struct.column_by_name("value") {
921 Some(value) => {
922 validate_binary_array(value.as_ref(), "value")?;
923 value.clone()
924 }
925 None if typed_value.is_some() => all_null_value_column(inner_struct.len()),
928 None => {
929 return Err(ArrowError::InvalidArgumentError(
930 "Invalid VariantArray: StructArray must contain a 'value' field".to_string(),
931 ));
932 }
933 };
934 Ok(ShreddingState::new(value, typed_value))
935 }
936}
937
938fn typed_value_field(array: &ArrayRef) -> FieldRef {
944 let mut field = Field::new("typed_value", array.data_type().clone(), true);
945 if matches!(array.data_type(), DataType::FixedSizeBinary(16)) {
946 field = field.with_extension_type(UuidExtension);
947 }
948 Arc::new(field)
949}
950
951#[derive(Debug, Default, Clone)]
955pub(crate) struct StructArrayBuilder {
956 fields: Vec<FieldRef>,
957 arrays: Vec<ArrayRef>,
958 nulls: Option<NullBuffer>,
959}
960
961impl StructArrayBuilder {
962 pub fn new() -> Self {
963 Default::default()
964 }
965
966 pub fn with_field(mut self, field_name: &str, array: ArrayRef, nullable: bool) -> Self {
968 let field = Field::new(field_name, array.data_type().clone(), nullable);
969 self.fields.push(Arc::new(field));
970 self.arrays.push(array);
971 self
972 }
973
974 pub fn with_field_ref(mut self, field: FieldRef, array: ArrayRef) -> Self {
979 self.fields.push(field);
980 self.arrays.push(array);
981 self
982 }
983
984 pub fn with_nulls(mut self, nulls: NullBuffer) -> Self {
986 self.nulls = Some(nulls);
987 self
988 }
989
990 pub fn build(self) -> StructArray {
991 let Self {
992 fields,
993 arrays,
994 nulls,
995 } = self;
996 StructArray::new(Fields::from(fields), arrays, nulls)
997 }
998}
999
1000fn typed_value_to_variant(typed_value: &ArrayRef, index: usize) -> Result<Variant<'_, '_>> {
1002 let data_type = typed_value.data_type();
1003 match data_type {
1004 DataType::Null => Ok(Variant::Null),
1005 DataType::Boolean => {
1006 let boolean_array = typed_value.as_boolean();
1007 let value = boolean_array.value(index);
1008 Ok(Variant::from(value))
1009 }
1010 DataType::FixedSizeBinary(16) => {
1012 let array = typed_value.as_fixed_size_binary();
1013 let value = array.value(index);
1014 Ok(Uuid::from_slice(value).unwrap().into()) }
1016 DataType::Binary => {
1017 let array = typed_value.as_binary::<i32>();
1018 let value = array.value(index);
1019 Ok(Variant::from(value))
1020 }
1021 DataType::LargeBinary => {
1022 let array = typed_value.as_binary::<i64>();
1023 let value = array.value(index);
1024 Ok(Variant::from(value))
1025 }
1026 DataType::BinaryView => {
1027 let array = typed_value.as_binary_view();
1028 let value = array.value(index);
1029 Ok(Variant::from(value))
1030 }
1031 DataType::Utf8 => {
1032 let array = typed_value.as_string::<i32>();
1033 let value = array.value(index);
1034 Ok(Variant::from(value))
1035 }
1036 DataType::LargeUtf8 => {
1037 let array = typed_value.as_string::<i64>();
1038 let value = array.value(index);
1039 Ok(Variant::from(value))
1040 }
1041 DataType::Utf8View => {
1042 let array = typed_value.as_string_view();
1043 let value = array.value(index);
1044 Ok(Variant::from(value))
1045 }
1046 DataType::Int8 => {
1047 primitive_conversion_single_value!(Int8Type, typed_value, index)
1048 }
1049 DataType::Int16 => {
1050 primitive_conversion_single_value!(Int16Type, typed_value, index)
1051 }
1052 DataType::Int32 => {
1053 primitive_conversion_single_value!(Int32Type, typed_value, index)
1054 }
1055 DataType::Int64 => {
1056 primitive_conversion_single_value!(Int64Type, typed_value, index)
1057 }
1058 DataType::Float16 => {
1059 primitive_conversion_single_value!(Float16Type, typed_value, index)
1060 }
1061 DataType::Float32 => {
1062 primitive_conversion_single_value!(Float32Type, typed_value, index)
1063 }
1064 DataType::Float64 => {
1065 primitive_conversion_single_value!(Float64Type, typed_value, index)
1066 }
1067 DataType::Decimal32(_, s) => {
1068 generic_conversion_single_value_with_result!(
1069 Decimal32Type,
1070 as_primitive,
1071 |v| VariantDecimal4::try_new(v, *s as u8),
1072 typed_value,
1073 index
1074 )
1075 }
1076 DataType::Decimal64(_, s) => {
1077 generic_conversion_single_value_with_result!(
1078 Decimal64Type,
1079 as_primitive,
1080 |v| VariantDecimal8::try_new(v, *s as u8),
1081 typed_value,
1082 index
1083 )
1084 }
1085 DataType::Decimal128(_, s) => {
1086 generic_conversion_single_value_with_result!(
1087 Decimal128Type,
1088 as_primitive,
1089 |v| VariantDecimal16::try_new(v, *s as u8),
1090 typed_value,
1091 index
1092 )
1093 }
1094 DataType::Date32 => {
1095 generic_conversion_single_value!(
1096 Date32Type,
1097 as_primitive,
1098 |v| Date32Type::to_naive_date_opt(v).unwrap(),
1099 typed_value,
1100 index
1101 )
1102 }
1103 DataType::Time64(TimeUnit::Microsecond) => {
1104 generic_conversion_single_value_with_result!(
1105 Time64MicrosecondType,
1106 as_primitive,
1107 |v| NaiveTime::from_num_seconds_from_midnight_opt(
1108 (v / 1_000_000) as u32,
1109 (v % 1_000_000) as u32 * 1000
1110 )
1111 .ok_or_else(|| format!("Invalid microsecond from midnight: {}", v)),
1112 typed_value,
1113 index
1114 )
1115 }
1116 DataType::Timestamp(TimeUnit::Microsecond, Some(_)) => {
1117 generic_conversion_single_value!(
1118 TimestampMicrosecondType,
1119 as_primitive,
1120 |v| DateTime::from_timestamp_micros(v).unwrap(),
1121 typed_value,
1122 index
1123 )
1124 }
1125 DataType::Timestamp(TimeUnit::Microsecond, None) => {
1126 generic_conversion_single_value!(
1127 TimestampMicrosecondType,
1128 as_primitive,
1129 |v| DateTime::from_timestamp_micros(v).unwrap().naive_utc(),
1130 typed_value,
1131 index
1132 )
1133 }
1134 DataType::Timestamp(TimeUnit::Nanosecond, Some(_)) => {
1135 generic_conversion_single_value!(
1136 TimestampNanosecondType,
1137 as_primitive,
1138 DateTime::from_timestamp_nanos,
1139 typed_value,
1140 index
1141 )
1142 }
1143 DataType::Timestamp(TimeUnit::Nanosecond, None) => {
1144 generic_conversion_single_value!(
1145 TimestampNanosecondType,
1146 as_primitive,
1147 |v| DateTime::from_timestamp_nanos(v).naive_utc(),
1148 typed_value,
1149 index
1150 )
1151 }
1152 _ => Err(ArrowError::NotYetImplemented(format!(
1159 "VariantArray::try_value cannot materialize typed_value of type {} \
1160 as a borrowed Variant; call unshred_variant first",
1161 typed_value.data_type()
1162 ))),
1163 }
1164}
1165
1166fn canonicalize_shredded_types(array: &dyn Array) -> Result<ArrayRef> {
1169 let new_type = canonicalize_and_verify_data_type(array.data_type())?;
1170 if let Cow::Borrowed(_) = new_type
1171 && let Some(array) = array.as_struct_opt()
1172 {
1173 return Ok(Arc::new(array.clone())); }
1175 cast(array, new_type.as_ref())
1176}
1177
1178fn canonicalize_and_verify_data_type(data_type: &DataType) -> Result<Cow<'_, DataType>> {
1182 use DataType::*;
1183
1184 macro_rules! fail {
1186 () => {
1187 return Err(ArrowError::InvalidArgumentError(format!(
1188 "Illegal shredded value type: {data_type}"
1189 )))
1190 };
1191 }
1192 macro_rules! borrow {
1193 () => {
1194 Cow::Borrowed(data_type)
1195 };
1196 }
1197
1198 let new_data_type = match data_type {
1199 Null | Boolean => borrow!(),
1201 Int8 | Int16 | Int32 | Int64 | Float32 | Float64 => borrow!(),
1202
1203 UInt8 | UInt16 | UInt32 | UInt64 | Float16 => fail!(),
1205
1206 Decimal64(p, s) | Decimal128(p, s)
1211 if VariantDecimal4::is_valid_precision_and_scale(p, s) =>
1212 {
1213 Cow::Owned(Decimal32(*p, *s))
1214 }
1215 Decimal128(p, s) if VariantDecimal8::is_valid_precision_and_scale(p, s) => {
1216 Cow::Owned(Decimal64(*p, *s))
1217 }
1218 Decimal32(p, s) if VariantDecimal4::is_valid_precision_and_scale(p, s) => borrow!(),
1219 Decimal64(p, s) if VariantDecimal8::is_valid_precision_and_scale(p, s) => borrow!(),
1220 Decimal128(p, s) if VariantDecimal16::is_valid_precision_and_scale(p, s) => borrow!(),
1221 Decimal32(..) | Decimal64(..) | Decimal128(..) | Decimal256(..) => fail!(),
1222
1223 Timestamp(TimeUnit::Microsecond | TimeUnit::Nanosecond, _) => borrow!(),
1225 Timestamp(TimeUnit::Millisecond | TimeUnit::Second, _) => fail!(),
1226
1227 Date32 | Time64(TimeUnit::Microsecond) => borrow!(),
1229 Date64 | Time32(_) | Time64(_) | Duration(_) | Interval(_) => fail!(),
1230
1231 Binary | LargeBinary | BinaryView | Utf8 | LargeUtf8 | Utf8View => borrow!(),
1233
1234 FixedSizeBinary(16) => borrow!(),
1236 FixedSizeBinary(_) | FixedSizeList(..) => fail!(),
1237
1238 List(field) => match canonicalize_and_verify_field(field)? {
1240 Cow::Borrowed(_) => borrow!(),
1241 Cow::Owned(new_field) => Cow::Owned(DataType::List(new_field)),
1242 },
1243 LargeList(field) => match canonicalize_and_verify_field(field)? {
1244 Cow::Borrowed(_) => borrow!(),
1245 Cow::Owned(new_field) => Cow::Owned(DataType::LargeList(new_field)),
1246 },
1247 ListView(field) => match canonicalize_and_verify_field(field)? {
1248 Cow::Borrowed(_) => borrow!(),
1249 Cow::Owned(new_field) => Cow::Owned(DataType::ListView(new_field)),
1250 },
1251 LargeListView(field) => match canonicalize_and_verify_field(field)? {
1252 Cow::Borrowed(_) => borrow!(),
1253 Cow::Owned(new_field) => Cow::Owned(DataType::LargeListView(new_field)),
1254 },
1255 Struct(fields) => {
1257 let mut new_fields = std::collections::HashMap::new();
1260 for (i, field) in fields.iter().enumerate() {
1261 if let Cow::Owned(new_field) = canonicalize_and_verify_field(field)? {
1262 new_fields.insert(i, new_field);
1263 }
1264 }
1265
1266 if new_fields.is_empty() {
1267 borrow!()
1268 } else {
1269 let new_fields = fields
1270 .iter()
1271 .enumerate()
1272 .map(|(i, field)| new_fields.remove(&i).unwrap_or_else(|| field.clone()));
1273 Cow::Owned(DataType::Struct(new_fields.collect()))
1274 }
1275 }
1276 Map(..) | Union(..) => fail!(),
1277
1278 Dictionary(..) | RunEndEncoded(..) => fail!(),
1280 };
1281 Ok(new_data_type)
1282}
1283
1284fn canonicalize_and_verify_field(field: &Arc<Field>) -> Result<Cow<'_, Arc<Field>>> {
1285 let new_data_type = canonicalize_and_verify_data_type(field.data_type())?;
1286
1287 if matches!(new_data_type.as_ref(), DataType::FixedSizeBinary(16))
1291 && !field.has_valid_extension_type::<UuidExtension>()
1292 {
1293 let new_field = field.as_ref().clone().with_extension_type(UuidExtension);
1294 return Ok(Cow::Owned(Arc::new(new_field)));
1295 }
1296
1297 let Cow::Owned(new_data_type) = new_data_type else {
1298 return Ok(Cow::Borrowed(field));
1299 };
1300 let new_field = field.as_ref().clone().with_data_type(new_data_type);
1301 Ok(Cow::Owned(Arc::new(new_field)))
1302}
1303
1304#[cfg(test)]
1307impl VariantArray {
1308 pub(crate) fn perfectly_shredded(
1309 metadata: ArrayRef,
1310 typed_value: ArrayRef,
1311 nulls: Option<NullBuffer>,
1312 ) -> Self {
1313 let value = all_null_value_column(typed_value.len());
1314 Self::from_parts(metadata, value, Some(typed_value), nulls)
1315 }
1316}
1317
1318#[cfg(test)]
1319impl ShreddedVariantFieldArray {
1320 pub(crate) fn perfectly_shredded(typed_value: ArrayRef) -> Self {
1321 let value = all_null_value_column(typed_value.len());
1322 Self::from_parts(value, Some(typed_value), None)
1323 }
1324}
1325
1326#[cfg(test)]
1327mod test {
1328 use crate::VariantArrayBuilder;
1329 use std::str::FromStr;
1330
1331 use super::*;
1332 use arrow::array::{
1333 BinaryArray, BinaryViewArray, Decimal32Array, Decimal64Array, Decimal128Array,
1334 FixedSizeBinaryArray, Int32Array, Int64Array, LargeBinaryArray, LargeListArray,
1335 LargeListViewArray, ListArray, ListViewArray, Time64MicrosecondArray,
1336 };
1337 use arrow::buffer::{OffsetBuffer, ScalarBuffer};
1338 use arrow_schema::{Field, Fields};
1339 use parquet_variant::{EMPTY_VARIANT_METADATA_BYTES, ShortString};
1340
1341 #[test]
1342 fn invalid_not_a_struct_array() {
1343 let array = make_binary_view_array();
1344 let err = VariantArray::try_new(&array);
1346 assert_eq!(
1347 err.unwrap_err().to_string(),
1348 "Invalid argument error: Invalid VariantArray: requires StructArray as input"
1349 );
1350 }
1351
1352 #[test]
1353 fn invalid_missing_metadata() {
1354 let fields = Fields::from(vec![Field::new("value", DataType::BinaryView, true)]);
1355 let array = StructArray::new(fields, vec![make_binary_view_array()], None);
1356 let err = VariantArray::try_new(&array);
1358 assert_eq!(
1359 err.unwrap_err().to_string(),
1360 "Invalid argument error: Invalid VariantArray: StructArray must contain a 'metadata' field"
1361 );
1362 }
1363
1364 #[test]
1365 fn read_missing_value_column() {
1366 let typed_value = Arc::new(Int64Array::from(vec![Some(1), None, Some(3)])) as ArrayRef;
1370 let metadata =
1371 BinaryViewArray::from_iter_values(std::iter::repeat_n(EMPTY_VARIANT_METADATA_BYTES, 3));
1372 let struct_array = StructArrayBuilder::new()
1373 .with_field("metadata", Arc::new(metadata), false)
1374 .with_field("typed_value", typed_value, true)
1375 .build();
1376 assert!(struct_array.column_by_name("value").is_none());
1377
1378 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1379 assert_eq!(variant_array.value_column().len(), 3);
1380 assert_eq!(variant_array.value_column().null_count(), 3);
1381 assert!(variant_array.inner().column_by_name("value").is_some());
1382 assert!(variant_array.typed_value_column().is_some());
1383 assert_eq!(variant_array.value(0), Variant::from(1i64));
1384 assert_eq!(variant_array.value(1), Variant::Null);
1385 assert_eq!(variant_array.value(2), Variant::from(3i64));
1386
1387 let fields = Fields::from(vec![Field::new("metadata", DataType::BinaryView, false)]);
1389 let metadata_only = StructArray::new(fields, vec![make_binary_view_array()], None);
1390 let err = VariantArray::try_new(&metadata_only);
1391 assert_eq!(
1392 err.unwrap_err().to_string(),
1393 "Invalid argument error: Invalid VariantArray: StructArray must contain a 'value' field"
1394 );
1395 }
1396
1397 #[test]
1398 fn invalid_metadata_field_type() {
1399 let fields = Fields::from(vec![
1400 Field::new("metadata", DataType::Int32, true), Field::new("value", DataType::BinaryView, true),
1402 ]);
1403 let array = StructArray::new(
1404 fields,
1405 vec![make_int32_array(), make_binary_view_array()],
1406 None,
1407 );
1408 let err = VariantArray::try_new(&array);
1409 assert_eq!(
1410 err.unwrap_err().to_string(),
1411 "Invalid argument error: VariantArray 'metadata' field must be Binary, LargeBinary, or BinaryView, got Int32"
1412 );
1413 }
1414
1415 #[test]
1416 fn invalid_value_field_type() {
1417 let fields = Fields::from(vec![
1418 Field::new("metadata", DataType::BinaryView, true),
1419 Field::new("value", DataType::Int32, true),
1420 ]);
1421 let array = StructArray::new(
1422 fields,
1423 vec![make_binary_view_array(), make_int32_array()],
1424 None,
1425 );
1426 let err = VariantArray::try_new(&array);
1427 assert_eq!(
1428 err.unwrap_err().to_string(),
1429 "Invalid argument error: VariantArray 'value' field must be Binary, LargeBinary, or BinaryView, got Int32"
1430 );
1431 }
1432
1433 fn make_binary_view_array() -> ArrayRef {
1434 Arc::new(BinaryViewArray::from(vec![b"test" as &[u8]]))
1435 }
1436
1437 fn make_int32_array() -> ArrayRef {
1438 Arc::new(Int32Array::from(vec![1]))
1439 }
1440
1441 fn make_variant_struct_with_typed_value(typed_value: ArrayRef) -> StructArray {
1442 let metadata = BinaryViewArray::from_iter_values(std::iter::repeat_n(
1443 EMPTY_VARIANT_METADATA_BYTES,
1444 typed_value.len(),
1445 ));
1446 let value = new_null_array(&DataType::BinaryView, typed_value.len());
1447 StructArrayBuilder::new()
1448 .with_field("metadata", Arc::new(metadata), false)
1449 .with_field("value", value, true)
1450 .with_field("typed_value", typed_value, true)
1451 .build()
1452 }
1453
1454 #[test]
1455 fn try_new_tags_untagged_uuid_on_read() {
1456 let typed_value = FixedSizeBinaryArray::try_from_iter(std::iter::repeat_n([0u8; 16], 2));
1459 let input = make_variant_struct_with_typed_value(Arc::new(typed_value.unwrap()));
1460
1461 let variant_array = VariantArray::try_new(&input).unwrap();
1463 let typed_value = variant_array.inner().field_by_name("typed_value").unwrap();
1464 assert_eq!(typed_value.data_type(), &DataType::FixedSizeBinary(16));
1465 assert!(typed_value.has_valid_extension_type::<UuidExtension>());
1466 }
1467
1468 #[test]
1469 fn try_new_tags_untagged_nested_uuid_on_read() {
1470 let leaf = FixedSizeBinaryArray::try_from_iter(std::iter::repeat_n([0u8; 16], 1)).unwrap();
1473 let inner = StructArrayBuilder::new()
1474 .with_field("typed_value", Arc::new(leaf), true)
1475 .build();
1476 let object = StructArrayBuilder::new()
1477 .with_field("id", Arc::new(inner), false)
1478 .build();
1479 let input = make_variant_struct_with_typed_value(Arc::new(object));
1480
1481 let variant_array = VariantArray::try_new(&input).unwrap();
1483 let object = variant_array.typed_value_column().unwrap().as_struct();
1484 let id = object.column_by_name("id").unwrap().as_struct();
1485 let uuid_leaf = id.field_by_name("typed_value").unwrap();
1486 assert!(uuid_leaf.has_valid_extension_type::<UuidExtension>());
1487 }
1488
1489 #[test]
1490 fn all_null_value_column_is_valid_and_unshredded() {
1491 let metadata = BinaryViewArray::from(vec![b"test" as &[u8]; 3]);
1494 let value = new_null_array(&DataType::BinaryView, 3);
1495
1496 let fields = Fields::from(vec![
1497 Field::new("metadata", DataType::BinaryView, false),
1498 Field::new("value", DataType::BinaryView, true),
1499 ]);
1500 let struct_array = StructArray::new(fields, vec![Arc::new(metadata), value], None);
1501
1502 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1503 assert!(variant_array.typed_value_column().is_none());
1504
1505 for i in 0..variant_array.len() {
1508 assert!(variant_array.is_valid(i));
1509 assert_eq!(variant_array.value(i), Variant::Null);
1510 }
1511 }
1512
1513 #[test]
1514 fn canonicalize_and_verify_list_like_data_types() {
1515 let make_item_binary = || Arc::new(Field::new("item", DataType::Binary, true));
1519 let make_large_binary = || Arc::new(Field::new("item", DataType::LargeBinary, true));
1520 let make_item_binary_view = || Arc::new(Field::new("item", DataType::BinaryView, true));
1521
1522 let cases = vec![
1523 DataType::LargeList(make_item_binary()),
1525 DataType::ListView(make_item_binary()),
1526 DataType::LargeListView(make_item_binary()),
1527 DataType::LargeList(make_large_binary()),
1529 DataType::ListView(make_large_binary()),
1530 DataType::LargeListView(make_large_binary()),
1531 DataType::LargeList(make_item_binary_view()),
1533 DataType::ListView(make_item_binary_view()),
1534 DataType::LargeListView(make_item_binary_view()),
1535 ];
1536
1537 for input in cases {
1538 assert_eq!(
1539 canonicalize_and_verify_data_type(&input).unwrap().as_ref(),
1540 &input
1541 );
1542 }
1543 }
1544
1545 #[test]
1546 fn variant_array_try_new_supports_list_like_typed_value() {
1547 let item_field = Arc::new(Field::new("item", DataType::Int64, true));
1548 let values: ArrayRef = Arc::new(Int64Array::from(vec![Some(1), None, Some(3)]));
1549
1550 let typed_values = vec![
1551 Arc::new(ListArray::new(
1552 item_field.clone(),
1553 OffsetBuffer::new(ScalarBuffer::from(vec![0, 2, 3])),
1554 values.clone(),
1555 None,
1556 )) as ArrayRef,
1557 Arc::new(LargeListArray::new(
1558 item_field.clone(),
1559 OffsetBuffer::new(ScalarBuffer::from(vec![0_i64, 2, 3])),
1560 values.clone(),
1561 None,
1562 )) as ArrayRef,
1563 Arc::new(ListViewArray::new(
1564 item_field.clone(),
1565 ScalarBuffer::from(vec![0, 2]),
1566 ScalarBuffer::from(vec![2, 1]),
1567 values.clone(),
1568 None,
1569 )) as ArrayRef,
1570 Arc::new(LargeListViewArray::new(
1571 item_field,
1572 ScalarBuffer::from(vec![0_i64, 2]),
1573 ScalarBuffer::from(vec![2_i64, 1]),
1574 values,
1575 None,
1576 )) as ArrayRef,
1577 ];
1578
1579 for typed_value in typed_values {
1580 let input = make_variant_struct_with_typed_value(typed_value.clone());
1581 let variant_array = VariantArray::try_new(&input).unwrap();
1582 assert_eq!(
1583 variant_array.typed_value_column().unwrap().data_type(),
1584 typed_value.data_type(),
1585 );
1586 }
1587 }
1588
1589 #[test]
1590 fn test_variant_array_iterable() {
1591 let mut b = VariantArrayBuilder::new(6);
1592
1593 b.append_null();
1594 b.append_variant(Variant::from(1_i8));
1595 b.append_variant(Variant::Null);
1596 b.append_variant(Variant::from(2_i32));
1597 b.append_variant(Variant::from(3_i64));
1598 b.append_null();
1599
1600 let v = b.build();
1601
1602 let variants = v.iter().collect::<Vec<_>>();
1603
1604 assert_eq!(
1605 variants,
1606 vec![
1607 None,
1608 Some(Variant::Int8(1)),
1609 Some(Variant::Null),
1610 Some(Variant::Int32(2)),
1611 Some(Variant::Int64(3)),
1612 None,
1613 ]
1614 );
1615 }
1616
1617 #[test]
1618 fn test_variant_array_iter_double_ended() {
1619 let mut b = VariantArrayBuilder::new(5);
1620
1621 b.append_variant(Variant::from(0_i32));
1622 b.append_null();
1623 b.append_variant(Variant::from(2_i32));
1624 b.append_null();
1625 b.append_variant(Variant::from(4_i32));
1626
1627 let array = b.build();
1628 let mut iter = array.iter();
1629
1630 assert_eq!(iter.next(), Some(Some(Variant::from(0_i32))));
1631 assert_eq!(iter.next(), Some(None));
1632
1633 assert_eq!(iter.next_back(), Some(Some(Variant::from(4_i32))));
1634 assert_eq!(iter.next_back(), Some(None));
1635 assert_eq!(iter.next_back(), Some(Some(Variant::from(2_i32))));
1636
1637 assert_eq!(iter.next_back(), None);
1638 assert_eq!(iter.next(), None);
1639 }
1640
1641 #[test]
1642 fn test_variant_array_iter_reverse() {
1643 let mut b = VariantArrayBuilder::new(5);
1644
1645 b.append_variant(Variant::from("a"));
1646 b.append_null();
1647 b.append_variant(Variant::from("aaa"));
1648 b.append_null();
1649 b.append_variant(Variant::from("aaaaa"));
1650
1651 let array = b.build();
1652
1653 let result: Vec<_> = array.iter().rev().collect();
1654 assert_eq!(
1655 result,
1656 vec![
1657 Some(Variant::from("aaaaa")),
1658 None,
1659 Some(Variant::from("aaa")),
1660 None,
1661 Some(Variant::from("a")),
1662 ]
1663 );
1664 }
1665
1666 #[test]
1667 fn test_variant_array_iter_empty() {
1668 let v = VariantArrayBuilder::new(0).build();
1669 let mut i = v.iter();
1670 assert!(i.next().is_none());
1671 assert!(i.next_back().is_none());
1672 }
1673
1674 #[test]
1675 fn test_from_variant_opts_into_variant_array() {
1676 let v = vec![None, Some(Variant::Null), Some(Variant::BooleanFalse), None];
1677
1678 let variant_array = VariantArray::from_iter(v);
1679
1680 assert_eq!(variant_array.len(), 4);
1681
1682 assert!(variant_array.is_null(0));
1683
1684 assert!(!variant_array.is_null(1));
1685 assert_eq!(variant_array.value(1), Variant::Null);
1686
1687 assert!(!variant_array.is_null(2));
1688 assert_eq!(variant_array.value(2), Variant::BooleanFalse);
1689
1690 assert!(variant_array.is_null(3));
1691 }
1692
1693 #[test]
1694 fn test_from_variants_into_variant_array() {
1695 let v = vec![
1696 Variant::Null,
1697 Variant::BooleanFalse,
1698 Variant::ShortString(ShortString::try_new("norm").unwrap()),
1699 ];
1700
1701 let variant_array = VariantArray::from_iter(v);
1702
1703 assert_eq!(variant_array.len(), 3);
1704
1705 assert!(!variant_array.is_null(0));
1706 assert_eq!(variant_array.value(0), Variant::Null);
1707
1708 assert!(!variant_array.is_null(1));
1709 assert_eq!(variant_array.value(1), Variant::BooleanFalse);
1710
1711 assert!(!variant_array.is_null(2));
1712 assert_eq!(
1713 variant_array.value(2),
1714 Variant::ShortString(ShortString::try_new("norm").unwrap())
1715 );
1716 }
1717
1718 #[test]
1719 fn test_variant_equality() {
1720 let v_iter = [None, Some(Variant::BooleanFalse), Some(Variant::Null), None];
1721 let v = VariantArray::from_iter(v_iter.clone());
1722
1723 {
1724 let v_copy = v.clone();
1725 assert_eq!(v, v_copy);
1726 }
1727
1728 {
1729 let v_iter_reversed = v_iter.iter().cloned().rev();
1730 let v_reversed = VariantArray::from_iter(v_iter_reversed);
1731
1732 assert_ne!(v, v_reversed);
1733 }
1734
1735 {
1736 let v_sliced = v.slice(0, 1);
1737 assert_ne!(v, v_sliced);
1738 }
1739 }
1740
1741 #[test]
1742 fn binary_typed_value_roundtrips() {
1743 let typed_value: ArrayRef = Arc::new(BinaryArray::from(vec![b"hello" as &[u8]]));
1745 let struct_array = make_variant_struct_with_typed_value(typed_value);
1746
1747 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1748 assert_eq!(variant_array.value(0), Variant::from(b"hello" as &[u8]));
1749 }
1750
1751 #[test]
1752 fn large_binary_typed_value_roundtrips() {
1753 let typed_value: ArrayRef = Arc::new(LargeBinaryArray::from(vec![b"world" as &[u8]]));
1755 let struct_array = make_variant_struct_with_typed_value(typed_value);
1756
1757 let variant_array = VariantArray::try_new(&struct_array).unwrap();
1758 assert_eq!(variant_array.value(0), Variant::from(b"world" as &[u8]));
1759 }
1760
1761 macro_rules! invalid_variant_array_test {
1762 ($fn_name: ident, $invalid_typed_value: expr, $error_msg: literal) => {
1763 #[test]
1764 fn $fn_name() {
1765 let invalid_typed_value = $invalid_typed_value;
1766
1767 let struct_array =
1768 make_variant_struct_with_typed_value(Arc::new(invalid_typed_value));
1769
1770 let array: VariantArray = VariantArray::try_new(&struct_array)
1771 .expect("should create variant array")
1772 .into();
1773
1774 let result = array.try_value(0);
1775 assert!(result.is_err());
1776 let error = result.unwrap_err();
1777 assert!(matches!(error, ArrowError::CastError(_)));
1778
1779 let expected: &str = $error_msg;
1780 assert!(
1781 error.to_string().contains($error_msg),
1782 "error `{}` did not contain `{}`",
1783 error,
1784 expected
1785 )
1786 }
1787 };
1788 }
1789
1790 invalid_variant_array_test!(
1791 test_variant_array_invalide_time,
1792 Time64MicrosecondArray::from(vec![Some(86401000000)]),
1793 "Cast error: Cast failed at index 0 (array type: Time64(µs)): Invalid microsecond from midnight: 86401000000"
1794 );
1795
1796 invalid_variant_array_test!(
1797 test_variant_array_invalid_decimal32,
1798 Decimal32Array::from(vec![Some(1234567890)]),
1799 "Cast error: Cast failed at index 0 (array type: Decimal32(9, 2)): Invalid argument error: 1234567890 is wider than max precision 9"
1800 );
1801
1802 invalid_variant_array_test!(
1803 test_variant_array_invalid_decimal64,
1804 Decimal64Array::from(vec![Some(1234567890123456789)]),
1805 "Cast error: Cast failed at index 0 (array type: Decimal64(18, 6)): Invalid argument error: 1234567890123456789 is wider than max precision 18"
1806 );
1807
1808 invalid_variant_array_test!(
1809 test_variant_array_invalid_decimal128,
1810 Decimal128Array::from(vec![Some(
1811 i128::from_str("123456789012345678901234567890123456789").unwrap()
1812 ),]),
1813 "Cast error: Cast failed at index 0 (array type: Decimal128(38, 10)): Invalid argument error: 123456789012345678901234567890123456789 is wider than max precision 38"
1814 );
1815 #[test]
1816 fn try_value_errors_on_unimplemented_typed_value_type() {
1817 use crate::{json_to_variant, shred_variant};
1818 use arrow::array::StringArray;
1819
1820 let json: ArrayRef = Arc::new(StringArray::from(vec![r#"{"qty": 3}"#]));
1821 let variant = json_to_variant(&json).unwrap();
1822 let shred_type = DataType::Struct(vec![Field::new("qty", DataType::Int64, true)].into());
1823 let shredded = shred_variant(&variant, &shred_type).unwrap();
1824 let err = shredded.try_value(0).unwrap_err();
1828 assert!(
1829 err.to_string().starts_with(
1830 "Not yet implemented: VariantArray::try_value cannot materialize typed_value"
1831 ),
1832 "unexpected error: {err}"
1833 );
1834 }
1835}