This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-11636-cdab920c847e62433e24162c897057c74c93d6a9 in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
commit 9827aaad30258bf348a0d4f2b792505d6d24a88f Author: Chang Yong Lik <[email protected]> AuthorDate: Sat Oct 17 07:45:08 2026 +0000 fix(arrow-data): account for FixedSizeList parent offset in MutableArrayData (#11636) # Which issue does this PR close? - Closes #11588. # Rationale for this change `MutableArrayData::extend` on a `FixedSizeList` with a nonzero parent offset copied the child values from the start of the child instead of from the offset. # What changes are included in this PR? `build_extend` in `transform/fixed_size_list.rs` adds `array.offset()` to `start` before computing the child range, the same way #10934 did for structs. # Are these changes tested? Yes, `test_extend_fixed_size_list_accounts_for_parent_offset` in `arrow-data/src/data.rs` (next to the struct test from #10934). It fails without the fix. # Are there any significant user-facing changes? No. AI use: I used Claude Code to find the cause and write the fix and test. I reviewed the change and checked that the test fails without the fix. --- arrow-data/src/data.rs | 23 +++++++++++++++++++++++ arrow-data/src/transform/fixed_size_list.rs | 21 ++++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/arrow-data/src/data.rs b/arrow-data/src/data.rs index d58bdcf963..6d34884808 100644 --- a/arrow-data/src/data.rs +++ b/arrow-data/src/data.rs @@ -2760,6 +2760,29 @@ mod tests { assert_eq!(output.child_data()[0].buffer::<i32>(0), &[1, 2, 3, 4]); } + #[test] + fn test_extend_fixed_size_list_accounts_for_parent_offset() { + let field = Arc::new(Field::new("item", DataType::Int32, false)); + let child = ArrayData::builder(DataType::Int32) + .len(6) + .add_buffer(Buffer::from_slice_ref([0, 1, 2, 3, 4, 5])) + .build() + .unwrap(); + + let data = ArrayData::builder(DataType::FixedSizeList(field, 2)) + .len(2) + .offset(1) + .add_child_data(child) + .build() + .unwrap(); + + let mut mutable = MutableArrayData::new(vec![&data], false, data.len()); + mutable.try_extend(0, 0, data.len()).unwrap(); + let output = mutable.freeze(); + + assert_eq!(output.child_data()[0].buffer::<i32>(0), &[2, 3, 4, 5]); + } + #[test] fn test_null_count() { let mut bit_v: [u8; 2] = [0; 2]; diff --git a/arrow-data/src/transform/fixed_size_list.rs b/arrow-data/src/transform/fixed_size_list.rs index de791884b9..f5234ec712 100644 --- a/arrow-data/src/transform/fixed_size_list.rs +++ b/arrow-data/src/transform/fixed_size_list.rs @@ -25,11 +25,30 @@ pub(super) fn build_extend(array: &ArrayData) -> Extend<'_> { DataType::FixedSizeList(_, i) => *i as usize, _ => unreachable!(), }; + let offset = array.offset(); Box::new( move |mutable: &mut _MutableArrayData, index: usize, start: usize, len: usize| { + let start = start.checked_add(offset).ok_or_else(|| { + ArrowError::InvalidArgumentError(format!( + "fixed size list offset {offset} with start {start} overflows usize" + )) + })?; + let end = start.checked_add(len).ok_or_else(|| { + ArrowError::InvalidArgumentError(format!( + "fixed size list start {start} with length {len} overflows usize" + )) + })?; + let (child_start, child_end) = start + .checked_mul(size) + .zip(end.checked_mul(size)) + .ok_or_else(|| { + ArrowError::InvalidArgumentError(format!( + "fixed size list range {start}..{end} with size {size} overflows usize" + )) + })?; for child in &mut mutable.child_data { - child.try_extend(index, start * size, (start + len) * size)?; + child.try_extend(index, child_start, child_end)?; } Ok(()) },
