Skip to content

Commit 6078213

Browse files
authored
[58_maintenance] fix: account for offsets in runarrays when using extend for MutableArrayData (#11761)
- Backport #11546 - For inclusion in #11665 Cherry-pick of 2e26ab4
1 parent 561c176 commit 6078213

1 file changed

Lines changed: 54 additions & 9 deletions

File tree

  • arrow-data/src/transform

‎arrow-data/src/transform/run.rs‎

Lines changed: 54 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
// under the License.
1717

1818
use super::{_MutableArrayData, ArrayData, Extend};
19-
use arrow_buffer::{ArrowNativeType, Buffer, ToByteSlice};
19+
use arrow_buffer::{ArrowNativeType, ToByteSlice};
2020
use arrow_schema::DataType;
2121
use num_traits::CheckedAdd;
2222

@@ -58,8 +58,9 @@ pub fn extend_nulls(mutable: &mut _MutableArrayData, len: usize) {
5858
macro_rules! extend_nulls_impl {
5959
($run_end_type:ty) => {{
6060
let last_run_end = get_last_run_end::<$run_end_type>(&mutable.child_data[0]);
61-
let new_value = last_run_end
62-
.checked_add(<$run_end_type as ArrowNativeType>::usize_as(len))
61+
let len = <$run_end_type as ArrowNativeType>::from_usize(len);
62+
let new_value = len
63+
.and_then(|len| last_run_end.checked_add(len))
6364
.expect("run end overflow");
6465
mutable.child_data[0]
6566
.data
@@ -81,7 +82,7 @@ pub fn extend_nulls(mutable: &mut _MutableArrayData, len: usize) {
8182

8283
/// Build run ends bytes and values range directly for batch processing
8384
fn build_extend_arrays<T: ArrowNativeType + std::ops::Add<Output = T> + CheckedAdd>(
84-
buffer: &Buffer,
85+
typed_slice: &[T],
8586
length: usize,
8687
start: usize,
8788
len: usize,
@@ -93,9 +94,6 @@ fn build_extend_arrays<T: ArrowNativeType + std::ops::Add<Output = T> + CheckedA
9394
let mut prev_end = 0;
9495
let mut current_run_end = dest_last_run_end;
9596

96-
// Convert buffer to typed slice once
97-
let typed_slice: &[T] = buffer.typed_data();
98-
9997
for i in 0..length {
10098
if i < typed_slice.len() {
10199
let run_end = typed_slice[i].to_usize().unwrap();
@@ -188,6 +186,8 @@ pub fn build_extend(array: &ArrayData) -> Extend<'_> {
188186

189187
// We need to analyze the source array's run structure
190188
let source_run_ends = &array.child_data()[0];
189+
let source_buffer_offset = source_run_ends.offset();
190+
let source_buffer_len = source_run_ends.len();
191191
let source_buffer = &source_run_ends.buffers()[0];
192192

193193
// Get the run end type from the mutable array
@@ -201,6 +201,8 @@ pub fn build_extend(array: &ArrayData) -> Extend<'_> {
201201
// Build run ends and values indices directly for batch processing
202202
macro_rules! build_and_process_impl {
203203
($run_end_type:ty) => {{
204+
let source_buffer = &source_buffer.typed_data()
205+
[source_buffer_offset..source_buffer_offset + source_buffer_len];
204206
let dest_last_run_end =
205207
get_last_run_end::<$run_end_type>(&mutable.child_data[0]);
206208
let (run_ends_bytes, values_range) = build_extend_arrays::<$run_end_type>(
@@ -511,7 +513,8 @@ mod tests {
511513
#[test]
512514
fn test_build_extend_arrays_int16() {
513515
let buffer = Buffer::from_vec(vec![3i16, 5i16, 8i16]);
514-
let (run_ends_bytes, values_range) = build_extend_arrays::<i16>(&buffer, 3, 2, 4, 0i16);
516+
let (run_ends_bytes, values_range) =
517+
build_extend_arrays::<i16>(buffer.typed_data(), 3, 2, 4, 0i16);
515518

516519
// Logical array: [A, A, A, B, B, C, C, C]
517520
// Requesting indices 2-6 should give us:
@@ -533,7 +536,8 @@ mod tests {
533536
#[test]
534537
fn test_build_extend_arrays_int64() {
535538
let buffer = Buffer::from_vec(vec![3i64, 5i64, 8i64]);
536-
let (run_ends_bytes, values_range) = build_extend_arrays::<i64>(&buffer, 3, 2, 4, 0i64);
539+
let (run_ends_bytes, values_range) =
540+
build_extend_arrays::<i64>(buffer.typed_data(), 3, 2, 4, 0i64);
537541

538542
// Same logic as above but with i64
539543
assert_eq!(run_ends_bytes.len(), 3 * std::mem::size_of::<i64>());
@@ -644,4 +648,45 @@ mod tests {
644648
// This should cause overflow: (i32::MAX - 50) + 100 > i32::MAX
645649
mutable.extend(0, 0, 100);
646650
}
651+
652+
#[test]
653+
#[should_panic(expected = "run end overflow")]
654+
fn test_extend_nulls_overflow() {
655+
let values = create_int32_array_data(vec![10]);
656+
let array = create_run_array_data_int16(vec![100], values);
657+
658+
let mut mutable = MutableArrayData::new(vec![&array], true, 10);
659+
mutable.extend_nulls(i16::MAX as usize + 1);
660+
}
661+
662+
#[test]
663+
fn test_extend_accounts_for_offset() {
664+
let dt = DataType::RunEndEncoded(
665+
Arc::new(Field::new("run_ends", DataType::Int32, false)),
666+
Arc::new(Field::new("values", DataType::Float32, true)),
667+
);
668+
669+
let runs = ArrayData::builder(DataType::Int32)
670+
.len(2)
671+
.offset(2)
672+
.add_buffer(vec![-10_i32, -20, 1_i32, 4, 0, 100].into())
673+
.build()
674+
.unwrap();
675+
let values = ArrayData::builder(DataType::Float32)
676+
.len(2)
677+
.add_buffer(vec![1.5, 2.5].into())
678+
.build()
679+
.unwrap();
680+
681+
let source_data = ArrayDataBuilder::new(dt)
682+
.len(3)
683+
.child_data(vec![runs, values])
684+
.build()
685+
.unwrap();
686+
687+
let mut mutable = MutableArrayData::new(vec![&source_data], true, 10);
688+
mutable.extend(0, 0, 1);
689+
let data = mutable.freeze();
690+
assert_eq!(data, source_data.slice(0, 1));
691+
}
647692
}

0 commit comments

Comments
 (0)