This is an automated email from the ASF dual-hosted git repository.
alamb pushed a commit to branch 57_maintenance
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
The following commit(s) were added to refs/heads/57_maintenance by this push:
new 8fd4fdbccd [57_maintenance] Fix sliced sparse union ArrayData
conversion (#11812)
8fd4fdbccd is described below
commit 8fd4fdbccdc02b75bfe7acc6a8f69c6b4fb73923
Author: Jeffrey Vo <[email protected]>
AuthorDate: Fri Oct 23 00:22:46 2026 +0900
[57_maintenance] Fix sliced sparse union ArrayData conversion (#11812)
- Backport https://github.com/apache/arrow-rs/pull/11649
- For inclusion in https://github.com/apache/arrow-rs/issues/11666
Cherry-pick of
https://github.com/apache/arrow-rs/commit/a9341121687aea7881063ff07b88c14967ee9a9d
Co-authored-by: Kyon <[email protected]>
---
arrow-array/src/array/union_array.rs | 55 +++++++++++++++++++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/arrow-array/src/array/union_array.rs
b/arrow-array/src/array/union_array.rs
index 73e3045faa..cc2d0a17eb 100644
--- a/arrow-array/src/array/union_array.rs
+++ b/arrow-array/src/array/union_array.rs
@@ -702,7 +702,11 @@ impl From<ArrayData> for UnionArray {
let max_id = fields.iter().map(|(i, _)| i).max().unwrap_or_default()
as usize;
let mut boxed_fields = vec![None; max_id + 1];
for (cd, (field_id, _)) in data.child_data().iter().zip(fields.iter())
{
- boxed_fields[field_id as usize] = Some(make_array(cd.clone()));
+ let cd = match mode {
+ UnionMode::Sparse => cd.slice(data.offset(), data.len()),
+ UnionMode::Dense => cd.clone(),
+ };
+ boxed_fields[field_id as usize] = Some(make_array(cd));
}
Self {
data_type: data.data_type().clone(),
@@ -1685,6 +1689,55 @@ mod tests {
test_slice_union(record_batch_slice);
}
+ #[test]
+ fn test_union_from_sliced_array_data() {
+ for mode in [UnionMode::Sparse, UnionMode::Dense] {
+ let fields = UnionFields::try_new(
+ [3, 7],
+ [
+ Field::new("ints", DataType::Int32, false),
+ Field::new("floats", DataType::Float64, false),
+ ],
+ )
+ .unwrap();
+ let offsets = (mode == UnionMode::Dense).then(|| vec![0, 1, 2,
3].into());
+ let array = UnionArray::try_new(
+ fields,
+ vec![3, 7, 3, 7].into(),
+ offsets,
+ vec![
+ Arc::new(Int32Array::from(vec![10, 20, 30, 40])),
+ Arc::new(Float64Array::from(vec![1.0, 2.0, 3.0, 4.0])),
+ ],
+ )
+ .unwrap();
+ for (offset, len) in [(1, 2), (0, 2), (4, 0), (0, 4)] {
+ let expected = array.slice(offset, len);
+ let actual = make_array(array.to_data().slice(offset, len));
+ let actual =
actual.as_any().downcast_ref::<UnionArray>().unwrap();
+ for i in 0..len {
+ assert_eq!(actual.value(i).to_data(),
expected.value(i).to_data());
+ }
+ assert_eq!(actual.to_data(), expected.to_data());
+ }
+ }
+ }
+
+ #[test]
+ fn test_sparse_union_from_sliced_array_data_logical_nulls() {
+ let child = Int32Array::from(vec![Some(10), None, Some(30)]);
+ let fields =
+ UnionFields::try_new([0], [Field::new("ints", DataType::Int32,
true)]).unwrap();
+ let array =
+ UnionArray::try_new(fields, vec![0, 0, 0].into(), None,
vec![Arc::new(child)]).unwrap();
+ for (offset, len) in [(0, 1), (1, 1), (2, 1), (3, 0)] {
+ let expected = array.slice(offset, len);
+ let actual = make_array(array.to_data().slice(offset, len));
+ assert_eq!(actual.logical_nulls(), expected.logical_nulls());
+ assert_eq!(actual.to_data(), expected.to_data());
+ }
+ }
+
#[test]
fn test_custom_type_ids() {
let data_type = DataType::Union(