Repository: jorgecarleitao/arrow2
Pull request #1088 (2022-06-19 21:27:11)

Simplified code
Also added `MutableUtf8Array::try_new` 

codecov[bot]: # [Codecov](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao) Report
> Merging [#1088](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao) (0da360a) into [main](https://codecov.io/gh/jorgecarleitao/arrow2/commit/d1ab4efa5c895513681bacd5e20660be882433ac?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao) (d1ab4ef) will **decrease** coverage by `0.01%`.
> The diff coverage is `72.88%`.

```diff
@@            Coverage Diff             @@
##             main    #1088      +/-   ##
==========================================
- Coverage   81.07%   81.06%   -0.02%     
==========================================
  Files         367      367              
  Lines       35309    35305       -4     
==========================================
- Hits        28628    28620       -8     
- Misses       6681     6685       +4     
```


| [Impacted Files](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao) | Coverage Δ | |
|---|---|---|
| [src/array/specification.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2FycmF5L3NwZWNpZmljYXRpb24ucnM=) | `91.46% <ø> (-0.31%)` | :arrow_down: |
| [src/io/parquet/write/binary/basic.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2lvL3BhcnF1ZXQvd3JpdGUvYmluYXJ5L2Jhc2ljLnJz) | `68.14% <0.00%> (ø)` | |
| [src/bitmap/mutable.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2JpdG1hcC9tdXRhYmxlLnJz) | `96.86% <40.00%> (-0.66%)` | :arrow_down: |
| [src/array/utf8/mutable.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2FycmF5L3V0ZjgvbXV0YWJsZS5ycw==) | `81.38% <54.16%> (-2.62%)` | :arrow_down: |
| [src/array/primitive/mod.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2FycmF5L3ByaW1pdGl2ZS9tb2QucnM=) | `79.53% <54.54%> (ø)` | |
| [src/array/utf8/mod.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2FycmF5L3V0ZjgvbW9kLnJz) | `81.78% <59.25%> (+2.39%)` | :arrow_up: |
| [src/bitmap/immutable.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2JpdG1hcC9pbW11dGFibGUucnM=) | `81.48% <90.00%> (-1.54%)` | :arrow_down: |
| [src/array/binary/mutable.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2FycmF5L2JpbmFyeS9tdXRhYmxlLnJz) | `87.97% <100.00%> (ø)` | |
| [src/array/boolean/mutable.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2FycmF5L2Jvb2xlYW4vbXV0YWJsZS5ycw==) | `89.32% <100.00%> (ø)` | |
| [src/array/mod.rs](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao#diff-c3JjL2FycmF5L21vZC5ycw==) | `68.54% <100.00%> (ø)` | |
| ... and [17 more](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao). Last update [d1ab4ef...0da360a](https://codecov.io/gh/jorgecarleitao/arrow2/pull/1088?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=Jorge+Leitao).


Patch:
diff --git a/src/array/primitive/mod.rs b/src/array/primitive/mod.rs
index f358b12dba..0a4aacf2a9 100644
--- a/src/array/primitive/mod.rs
+++ b/src/array/primitive/mod.rs
@@ -309,7 +309,7 @@ impl<T: NativeType> PrimitiveArray<T> {
     ///
     /// This function is primarily used to re-use memory regions.
     #[must_use]
-    pub fn into_mut(self) -> Either<Self, MutablePrimitiveArray<T>> {
+    pub fn into_mut(mut self) -> Either<Self, MutablePrimitiveArray<T>> {
         use Either::*;
 
         if let Some(bitmap) = self.validity {
@@ -319,27 +319,27 @@ impl<T: NativeType> PrimitiveArray<T> {
                     self.values,
                     Some(bitmap),
                 )),
-                Right(mutable_bitmap) => match self.values.into_mut() {
-                    Left(buffer) => Left(PrimitiveArray::new(
-                        self.data_type,
-                        buffer,
-                        Some(mutable_bitmap.into()),
-                    )),
-                    Right(values) => Right(MutablePrimitiveArray::from_data(
+                Right(mutable_bitmap) => match self.values.get_mut().map(std::mem::take) {
+                    Some(values) => Right(MutablePrimitiveArray::from_data(
                         self.data_type,
                         values,
                         Some(mutable_bitmap),
                     )),
+                    None => Left(PrimitiveArray::new(
+                        self.data_type,
+                        self.values,
+                        Some(mutable_bitmap.into()),
+                    )),
                 },
             }
         } else {
-            match self.values.into_mut() {
-                Left(values) => Left(PrimitiveArray::new(self.data_type, values, None)),
-                Right(values) => Right(MutablePrimitiveArray::from_data(
+            match self.values.get_mut().map(std::mem::take) {
+                Some(values) => Right(MutablePrimitiveArray::from_data(
                     self.data_type,
                     values,
                     None,
                 )),
+                None => Left(PrimitiveArray::new(self.data_type, self.values, None)),
             }
         }
     }
diff --git a/src/array/specification.rs b/src/array/specification.rs
index f025cc3c8f..0ede258232 100644
--- a/src/array/specification.rs
+++ b/src/array/specification.rs
@@ -30,14 +30,6 @@ pub fn check_offsets_minimal<O: Offset>(offsets: &[O], values_len: usize) -> usi
     len
 }
 
-/// # Panics iff:
-/// * the `offsets` is not monotonically increasing, or
-/// * any slice of `values` between two consecutive pairs from `offsets` is invalid `utf8`, or
-/// * any offset is larger or equal to `values_len`.
-pub fn check_offsets_and_utf8<O: Offset>(offsets: &[O], values: &[u8]) {
-    try_check_offsets_and_utf8(offsets, values).unwrap()
-}
-
 /// # Panics iff:
 /// * the `offsets` is not monotonically increasing, or
 /// * any slice of `values` between two consecutive pairs from `offsets` is invalid `utf8`, or
diff --git a/src/array/utf8/mod.rs b/src/array/utf8/mod.rs
index 047e8778c0..8c9b9046f9 100644
--- a/src/array/utf8/mod.rs
+++ b/src/array/utf8/mod.rs
@@ -243,7 +243,7 @@ impl<O: Offset> Utf8Array<O> {
     }
 
     /// Try to convert this `Utf8Array` to a `MutableUtf8Array`
-    pub fn into_mut(self) -> Either<Self, MutableUtf8Array<O>> {
+    pub fn into_mut(mut self) -> Either<Self, MutableUtf8Array<O>> {
         use Either::*;
         if let Some(bitmap) = self.validity {
             match bitmap.into_mut() {
@@ -256,84 +256,70 @@ impl<O: Offset> Utf8Array<O> {
                         Some(bitmap),
                     )
                 }),
-                Right(mutable_bitmap) => match (self.values.into_mut(), self.offsets.into_mut()) {
-                    (Left(immutable_values), Left(immutable_offsets)) => {
+                Right(mutable_bitmap) => match (
+                    self.values.get_mut().map(std::mem::take),
+                    self.offsets.get_mut().map(std::mem::take),
+                ) {
+                    (None, None) => {
                         // Safety: invariants are preserved
                         Left(unsafe {
                             Utf8Array::new_unchecked(
                                 self.data_type,
-                                immutable_offsets,
-                                immutable_values,
+                                self.offsets,
+                                self.values,
                                 Some(mutable_bitmap.into()),
                             )
                         })
                     }
-                    (Left(immutable_values), Right(mutable_offsets)) => {
+                    (None, Some(offsets)) => {
                         // Safety: invariants are preserved
                         Left(unsafe {
                             Utf8Array::new_unchecked(
                                 self.data_type,
-                                mutable_offsets.into(),
-                                immutable_values,
+                                offsets.into(),
+                                self.values,
                                 Some(mutable_bitmap.into()),
                             )
                         })
                     }
-                    (Right(mutable_values), Left(immutable_offsets)) => {
+                    (Some(mutable_values), None) => {
                         // Safety: invariants are preserved
                         Left(unsafe {
                             Utf8Array::new_unchecked(
                                 self.data_type,
-                                immutable_offsets,
+                                self.offsets,
                                 mutable_values.into(),
                                 Some(mutable_bitmap.into()),
                             )
                         })
                     }
-                    (Right(mutable_values), Right(mutable_offsets)) => {
-                        Right(MutableUtf8Array::from_data(
+                    (Some(values), Some(offsets)) => Right(unsafe {
+                        MutableUtf8Array::from_data_unchecked(
                             self.data_type,
-                            mutable_offsets,
-                            mutable_values,
+                            offsets,
+                            values,
                             Some(mutable_bitmap),
-                        ))
-                    }
+                        )
+                    }),
                 },
             }
         } else {
-            match (self.values.into_mut(), self.offsets.into_mut()) {
-                (Left(immutable_values), Left(immutable_offsets)) => Left(unsafe {
-                    Utf8Array::new_unchecked(
-                        self.data_type,
-                        immutable_offsets,
-                        immutable_values,
-                        None,
-                    )
+            match (
+                self.values.get_mut().map(std::mem::take),
+                self.offsets.get_mut().map(std::mem::take),
+            ) {
+                (None, None) => Left(unsafe {
+                    Utf8Array::new_unchecked(self.data_type, self.offsets, self.values, None)
                 }),
-                (Left(immutable_values), Right(mutable_offsets)) => Left(unsafe {
-                    Utf8Array::new_unchecked(
-                        self.data_type,
-                        mutable_offsets.into(),
-                        immutable_values,
-                        None,
-                    )
+                (None, Some(offsets)) => Left(unsafe {
+                    Utf8Array::new_unchecked(self.data_type, offsets.into(), self.values, None)
                 }),
-                (Right(mutable_values), Left(immutable_offsets)) => Left(unsafe {
-                    Utf8Array::from_data(
-                        self.data_type,
-                        immutable_offsets,
-                        mutable_values.into(),
-                        None,
-                    )
+                (Some(values), None) => Left(unsafe {
+                    Utf8Array::new_unchecked(self.data_type, self.offsets, values.into(), None)
+                }),
+                (Some(values), Some(offsets)) => Right(unsafe {
+                    MutableUtf8Array::from_data_unchecked(self.data_type, offsets, values, None)
                 }),
-                (Right(mutable_values), Right(mutable_offsets)) => {
-                    Right(MutableUtf8Array::from_data(
-                        self.data_type,
-                        mutable_offsets,
-                        mutable_values,
-                        None,
-                    ))
-                }
             }
         }
     }
diff --git a/src/array/utf8/mutable.rs b/src/array/utf8/mutable.rs
index 3d53e69bbb..b80c73e212 100644
--- a/src/array/utf8/mutable.rs
+++ b/src/array/utf8/mutable.rs
@@ -2,7 +2,7 @@ use std::{iter::FromIterator, sync::Arc};
 
 use crate::{
     array::{
-        specification::{check_offsets_and_utf8, check_offsets_minimal},
+        specification::{check_offsets_minimal, try_check_offsets_and_utf8},
         Array, MutableArray, Offset, TryExtend, TryPush,
     },
     bitmap::MutableBitmap,
@@ -75,6 +75,47 @@ impl<O: Offset> MutableUtf8Array<O> {
         }
     }
 
+    /// Returns a [`MutableUtf8Array`] created from its internal representation.
+    ///
+    /// # Errors
+    /// This function returns an error iff:
+    /// * the offsets are not monotonically increasing
+    /// * The last offset is not equal to the values' length.
+    /// * the validity's length is not equal to `offsets.len() - 1`.
+    /// * The `data_type`'s [`crate::datatypes::PhysicalType`] is not equal to either `Utf8` or `LargeUtf8`.
+    /// * The `values` between two consecutive `offsets` are not valid utf8
+    /// # Implementation
+    /// This function is `O(N)` - checking monotinicity and utf8 is `O(N)`
+    pub fn try_new(
+        data_type: DataType,
+        offsets: Vec<O>,
+        values: Vec<u8>,
+        validity: Option<MutableBitmap>,
+    ) -> Result<Self> {
+        try_check_offsets_and_utf8(&offsets, &values)?;
+        if validity
+            .as_ref()
+            .map_or(false, |validity| validity.len() != offsets.len() - 1)
+        {
+            return Err(Error::oos(
+                "validity's length must be equal to the number of values",
+            ));
+        }
+
+        if data_type.to_physical_type() != Self::default_data_type().to_physical_type() {
+            return Err(Error::oos(
+                "MutableUtf8Array can only be initialized with DataType::Utf8 or DataType::LargeUtf8",
+            ));
+        }
+
+        Ok(Self {
+            data_type,
+            offsets,
+            values,
+            validity,
+        })
+    }
+
     /// The canonical method to create a [`MutableUtf8Array`] out of low-end APIs.
     /// # Panics
     /// This function panics iff:
@@ -87,19 +128,7 @@ impl<O: Offset> MutableUtf8Array<O> {
         values: Vec<u8>,
         validity: Option<MutableBitmap>,
     ) -> Self {
-        check_offsets_and_utf8(&offsets, &values);
-        if let Some(ref validity) = validity {
-            assert_eq!(offsets.len() - 1, validity.len());
-        }
-        if data_type.to_physical_type() != Self::default_data_type().to_physical_type() {
-            panic!("MutableUtf8Array can only be initialized with DataType::Utf8 or DataType::LargeUtf8")
-        }
-        Self {
-            data_type,
-            offsets,
-            values,
-            validity,
-        }
+        Self::try_new(data_type, offsets, values, validity).unwrap()
     }
 
     /// Create a [`MutableUtf8Array`] out of low-end APIs.
diff --git a/src/io/flight/mod.rs b/src/io/flight/mod.rs
index 4b848e3adf..b439ced2d9 100644
--- a/src/io/flight/mod.rs
+++ b/src/io/flight/mod.rs
@@ -14,16 +14,22 @@ use crate::{
     io::ipc::write::common::{encode_chunk, DictionaryTracker, EncodedData, WriteOptions},
 };
 
-use super::ipc::write::default_ipc_fields;
+pub use super::ipc::write::default_ipc_fields;
 use super::ipc::{IpcField, IpcSchema};
 
 /// Serializes [`Chunk`] to a vector of [`FlightData`] representing the serialized dictionaries
 /// and a [`FlightData`] representing the batch.
+/// # Errors
+/// This function errors iff `fields` is not consistent with `columns`
 pub fn serialize_batch(
     columns: &Chunk<Box<dyn Array>>,
     fields: &[IpcField],
     options: &WriteOptions,
-) -> (Vec<FlightData>, FlightData) {
+) -> Result<(Vec<FlightData>, FlightData)> {
+    if fields.len() != columns.arrays().len() {
+        return Err(Error::InvalidArgumentError("The argument `fields` must be consistent with the columns' schema. Use e.g. &arrow2::io::flight::default_ipc_fields(&schema.fields)".to_string()));
+    }
+
     let mut dictionary_tracker = DictionaryTracker {
         dictionaries: Default::default(),
         cannot_replace: false,
@@ -36,7 +42,7 @@ pub fn serialize_batch(
     let flight_dictionaries = encoded_dictionaries.into_iter().map(Into::into).collect();
     let flight_batch = encoded_batch.into();
 
-    (flight_dictionaries, flight_batch)
+    Ok((flight_dictionaries, flight_batch))
 }
 
 impl From<EncodedData> for FlightData {
diff --git a/src/io/parquet/read/deserialize/mod.rs b/src/io/parquet/read/deserialize/mod.rs
index 433d807baf..d4a7de6ee8 100644
--- a/src/io/parquet/read/deserialize/mod.rs
+++ b/src/io/parquet/read/deserialize/mod.rs
@@ -188,14 +188,29 @@ where
         }
         UInt32 => {
             init.push(InitNested::Primitive(field.is_nullable));
-            types.pop();
-            primitive::iter_to_arrays_nested(
-                columns.pop().unwrap(),
-                init,
-                field.data_type().clone(),
-                chunk_size,
-                |x: i32| x as u32,
-            )
+            let type_ = types.pop().unwrap();
+            match type_.physical_type {
+                PhysicalType::Int32 => primitive::iter_to_arrays_nested(
+                    columns.pop().unwrap(),
+                    init,
+                    field.data_type().clone(),
+                    chunk_size,
+                    |x: i32| x as u32,
+                ),
+                // some implementations of parquet write arrow's u32 into i64.
+                PhysicalType::Int64 => primitive::iter_to_arrays_nested(
+                    columns.pop().unwrap(),
+                    init,
+                    field.data_type().clone(),
+                    chunk_size,
+                    |x: i64| x as u32,
+                ),
+                other => {
+                    return Err(Error::nyi(format!(
+                        "Deserializing UInt32 from {other:?}'s parquet"
+                    )))
+                }
+            }
         }
         UInt64 => {
             init.push(InitNested::Primitive(field.is_nullable));
diff --git a/src/io/parquet/read/deserialize/simple.rs b/src/io/parquet/read/deserialize/simple.rs
index 6d3026c18b..8a8ef653da 100644
--- a/src/io/parquet/read/deserialize/simple.rs
+++ b/src/io/parquet/read/deserialize/simple.rs
@@ -82,12 +82,27 @@ pub fn page_iter_to_arrays<'a, I: 'a + DataPages>(
             chunk_size,
             |x: i32| x as u16,
         ))),
-        UInt32 => dyn_iter(iden(primitive::Iter::new(
-            pages,
-            data_type,
-            chunk_size,
-            |x: i32| x as u32,
-        ))),
+        UInt32 => match physical_type {
+            PhysicalType::Int32 => dyn_iter(iden(primitive::Iter::new(
+                pages,
+                data_type,
+                chunk_size,
+                |x: i32| x as u32,
+            ))),
+            // some implementations of parquet write arrow's u32 into i64.
+            PhysicalType::Int64 => dyn_iter(iden(primitive::Iter::new(
+                pages,
+                data_type,
+                chunk_size,
+                |x: i64| x as u32,
+            ))),
+            other => {
+                return Err(Error::NotYetImplemented(format!(
+                    "Reading uin32 from {:?}-encoded parquet still not implemented",
+                    other
+                )))
+            }
+        },
         Int8 => dyn_iter(iden(primitive::Iter::new(
             pages,
             data_type,
diff --git a/src/io/parquet/read/statistics/mod.rs b/src/io/parquet/read/statistics/mod.rs
index 4f3eaeff7b..540dac4df9 100644
--- a/src/io/parquet/read/statistics/mod.rs
+++ b/src/io/parquet/read/statistics/mod.rs
@@ -410,7 +410,17 @@ fn push(
         }
         UInt8 => primitive::push(from, min, max, |x: i32| Ok(x as u8)),
         UInt16 => primitive::push(from, min, max, |x: i32| Ok(x as u16)),
-        UInt32 => primitive::push(from, min, max, |x: i32| Ok(x as u32)),
+        UInt32 => match physical_type {
+            // some implementations of parquet write arrow's u32 into i64.
+            ParquetPhysicalType::Int64 => primitive::push(from, min, max, |x: i64| Ok(x as u32)),
+            ParquetPhysicalType::Int32 => primitive::push(from, min, max, |x: i32| Ok(x as u32)),
+            other => {
+                return Err(Error::NotYetImplemented(format!(
+                    "Can't decode UInt32 type from parquet type {:?}",
+                    other
+                )))
+            }
+        },
         Int32 => primitive::push(from, min, max, |x: i32| Ok(x as i32)),
         Int64 | Date64 | Time64(_) | Duration(_) => {
             primitive::push(from, min, max, |x: i64| Ok(x as i64))


Test patch:
diff --git a/integration-testing/src/flight_client_scenarios/integration_test.rs b/integration-testing/src/flight_client_scenarios/integration_test.rs
index 4d028292f4..19a4b1a4ef 100644
--- a/integration-testing/src/flight_client_scenarios/integration_test.rs
+++ b/integration-testing/src/flight_client_scenarios/integration_test.rs
@@ -147,7 +147,7 @@ async fn send_batch(
     fields: &[IpcField],
     options: &write::WriteOptions,
 ) -> Result {
-    let (dictionary_flight_data, mut batch_flight_data) = serialize_batch(batch, fields, options);
+    let (dictionary_flight_data, mut batch_flight_data) = serialize_batch(batch, fields, options)?;
 
     upload_tx
         .send_all(&mut stream::iter(dictionary_flight_data).map(Ok))
diff --git a/integration-testing/src/flight_server_scenarios/integration_test.rs b/integration-testing/src/flight_server_scenarios/integration_test.rs
index 73b4cd9dbe..07453f5c72 100644
--- a/integration-testing/src/flight_server_scenarios/integration_test.rs
+++ b/integration-testing/src/flight_server_scenarios/integration_test.rs
@@ -122,7 +122,7 @@ impl FlightService for FlightServiceImpl {
             .enumerate()
             .flat_map(|(counter, batch)| {
                 let (dictionary_flight_data, mut batch_flight_data) =
-                    serialize_batch(batch, &flight.ipc_schema.fields, &options);
+                    serialize_batch(batch, &flight.ipc_schema.fields, &options).unwrap();
 
                 // Only the record batch's FlightData gets app_metadata
                 let metadata = counter.to_string().into_bytes();
diff --git a/tests/it/io/parquet/read.rs b/tests/it/io/parquet/read.rs
index 4e426ef5ba..8ab783dbab 100644
--- a/tests/it/io/parquet/read.rs
+++ b/tests/it/io/parquet/read.rs
@@ -130,11 +130,15 @@ fn v1_timestamp_ms_nullable() -> Result<()> {
 }
 
 #[test]
-#[ignore] // pyarrow issue; see https://issues.apache.org/jira/browse/ARROW-12201
 fn v1_u32_nullable() -> Result<()> {
     test_pyarrow_integration("uint32", 1, "basic", false, false, None)
 }
 
+#[test]
+fn v2_u32_nullable() -> Result<()> {
+    test_pyarrow_integration("uint32", 2, "basic", false, false, None)
+}
+
 #[test]
 fn v2_int64_nullable() -> Result<()> {
     test_pyarrow_integration("int64", 2, "basic", false, false, None)