This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch 59_maintenance
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
The following commit(s) were added to refs/heads/59_maintenance by this push:
new c8a8df5e72 [59_maintenance] fix(arrow-array): preserve type params in
`PrimitiveArray::into_builder` (#11448)
c8a8df5e72 is described below
commit c8a8df5e7236085753c7ed643900bdb0ec25e82f
Author: Jeffrey Vo <[email protected]>
AuthorDate: Fri Oct 9 03:26:13 2026 +0900
[59_maintenance] fix(arrow-array): preserve type params in
`PrimitiveArray::into_builder` (#11448)
- Backport #11310 and #11321
- For inclusion in https://github.com/apache/arrow-rs/issues/11352
Cherry-pick of
https://github.com/apache/arrow-rs/commit/2f3cd82bea9f5baabdcc5b76efb4624620eeeb15
and
https://github.com/apache/arrow-rs/commit/38054b7713eade3bd8092bbf0fc3eaad69d4ce65
These are combined into a single PR since the fixes work on the same
function
---------
Co-authored-by: Neil Conway <[email protected]>
---
arrow-array/src/array/dictionary_array.rs | 22 +++++++++++++++++++++-
arrow-array/src/array/primitive_array.rs | 24 ++++++++++++++++++++++--
arrow-array/src/builder/primitive_run_builder.rs | 11 +++++++++++
3 files changed, 54 insertions(+), 3 deletions(-)
diff --git a/arrow-array/src/array/dictionary_array.rs
b/arrow-array/src/array/dictionary_array.rs
index 0c465ec144..382af1a152 100644
--- a/arrow-array/src/array/dictionary_array.rs
+++ b/arrow-array/src/array/dictionary_array.rs
@@ -1061,7 +1061,7 @@ impl<K: ArrowDictionaryKeyType> AnyDictionaryArray for
DictionaryArray<K> {
mod tests {
use super::*;
use crate::cast::as_dictionary_array;
- use crate::{Int8Array, Int16Array, Int32Array, RunArray, UInt8Array};
+ use crate::{Decimal128Array, Int8Array, Int16Array, Int32Array, RunArray,
UInt8Array};
use arrow_buffer::{Buffer, ToByteSlice};
#[test]
@@ -1448,6 +1448,26 @@ mod tests {
assert_eq!(expected, returned);
}
+ #[test]
+ fn test_unary_mut_keeps_value_type() {
+ let values = || {
+ Decimal128Array::from(vec![123, 456])
+ .with_precision_and_scale(5, 2)
+ .unwrap()
+ };
+ let keys = Int8Array::from_iter_values([0, 1, 0]);
+ let dict = DictionaryArray::new(keys, Arc::new(values()));
+ let data_type = dict.data_type().clone();
+ let updated = dict.unary_mut::<_, Decimal128Type>(|x| x + 1).unwrap();
+ assert_eq!(updated.data_type(), &data_type);
+
+ // When the keys are shared, the original array is returned
+ let keys = Int8Array::from_iter_values([0, 1, 0]);
+ let dict = DictionaryArray::new(keys.clone(), Arc::new(values()));
+ let returned = dict.unary_mut::<_, Decimal128Type>(|x| x +
1).unwrap_err();
+ assert_eq!(returned, DictionaryArray::new(keys, Arc::new(values())));
+ }
+
#[test]
fn test_occupancy() {
let keys = Int32Array::new((100..200).collect(), None);
diff --git a/arrow-array/src/array/primitive_array.rs
b/arrow-array/src/array/primitive_array.rs
index 8946af2b74..de20aaa271 100644
--- a/arrow-array/src/array/primitive_array.rs
+++ b/arrow-array/src/array/primitive_array.rs
@@ -1138,6 +1138,7 @@ impl<T: ArrowPrimitiveType> PrimitiveArray<T> {
/// `Err(self)`
pub fn into_builder(self) -> Result<PrimitiveBuilder<T>, Self> {
let len = self.len();
+ let data_type = self.data_type.clone();
let data = self.into_data();
let null_bit_buffer = data.nulls().map(|b| b.inner().sliced());
@@ -1177,9 +1178,9 @@ impl<T: ArrowPrimitiveType> PrimitiveArray<T> {
};
match try_mutable_buffers {
- Ok(builder) => Ok(builder),
+ Ok(builder) => Ok(builder.with_data_type(data_type)),
Err((buffer, null_bit_buffer)) => {
- let builder = ArrayData::builder(T::DATA_TYPE)
+ let builder = ArrayData::builder(data_type)
.len(len)
.add_buffer(buffer)
.null_bit_buffer(null_bit_buffer);
@@ -2869,6 +2870,25 @@ mod tests {
}
}
+ #[test]
+ fn test_into_builder_keeps_data_type() {
+ let array = Decimal128Array::from(vec![1, 2])
+ .with_precision_and_scale(10, 2)
+ .unwrap();
+ let data_type = array.data_type().clone();
+
+ // Shared buffers: the array is returned
+ let shared = array.clone();
+ let array = array.into_builder().unwrap_err();
+ assert_eq!(array.data_type(), &data_type);
+ drop(shared);
+
+ // Unshared buffers: the buffers are reused by the builder
+ let mut builder = array.into_builder().unwrap();
+ builder.append_value(3);
+ assert_eq!(builder.finish().data_type(), &data_type);
+ }
+
#[test]
fn test_into_builder_on_sliced_array() {
let array: Int32Array = vec![1, 2, 3].into_iter().map(Some).collect();
diff --git a/arrow-array/src/builder/primitive_run_builder.rs
b/arrow-array/src/builder/primitive_run_builder.rs
index 17beffdffa..832c40bb9b 100644
--- a/arrow-array/src/builder/primitive_run_builder.rs
+++ b/arrow-array/src/builder/primitive_run_builder.rs
@@ -378,4 +378,15 @@ mod tests {
let values = array.values();
assert_eq!(values.timezone(), Some("Europe/Paris"));
}
+
+ #[test]
+ fn test_finish_cloned_keeps_data_type() {
+ let data_type = DataType::Decimal128(5, 2);
+ let mut builder = PrimitiveRunBuilder::<Int16Type,
Decimal128Type>::new()
+ .with_data_type(data_type.clone());
+ // Leave the run open, so `finish_cloned` has to add it to a copy of
the values
+ builder.append_value(123);
+ let array = builder.finish_cloned();
+ assert_eq!(array.values().data_type(), &data_type);
+ }
}