Skip to content

Commit

Permalink
fix: first none/empty list in ListArray panics in `cast_with_option…
Browse files Browse the repository at this point in the history
…s` (#7065)

* fix: first none in `ListArray` panics in `cast_with_options`

* simplify

* fix

* Update arrow-cast/src/cast/list.rs

Co-authored-by: Jeffrey Vo <jeffrey.vo.australia@gmail.com>

---------

Co-authored-by: Jeffrey Vo <jeffrey.vo.australia@gmail.com>
  • Loading branch information
irenjj and Jefffrey authored Feb 8, 2025
1 parent 5bf4a6c commit 0bbfc03
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 1 deletion.
13 changes: 12 additions & 1 deletion arrow-cast/src/cast/list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,17 @@ where
let mut mutable = MutableArrayData::new(vec![&values], nullable, cap);
// The end position in values of the last incorrectly-sized list slice
let mut last_pos = 0;

// Need to flag when previous vector(s) are empty/None to distinguish from 'All slices were correct length' cases.
let is_prev_empty = if array.offsets().len() < 2 {
false
} else {
let first_offset = array.offsets()[0].as_usize();
let second_offset = array.offsets()[1].as_usize();

first_offset == 0 && second_offset == 0
};

for (idx, w) in array.offsets().windows(2).enumerate() {
let start_pos = w[0].as_usize();
let end_pos = w[1].as_usize();
Expand All @@ -113,7 +124,7 @@ where
}

let values = match last_pos {
0 => array.values().slice(0, cap), // All slices were the correct length
0 if !is_prev_empty => array.values().slice(0, cap), // All slices were the correct length
_ => {
if mutable.len() != cap {
// Remaining slices were all correct length
Expand Down
37 changes: 37 additions & 0 deletions arrow-cast/src/cast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9952,4 +9952,41 @@ mod tests {
assert_eq!(result.unwrap_err().to_string(),
"Invalid argument error: 123456789 is too large to store in a Decimal256 of precision 6. Max is 999999");
}

#[test]
fn test_first_none() {
let array = Arc::new(ListArray::from_iter_primitive::<Int64Type, _, _>(vec![
None,
Some(vec![Some(1), Some(2)]),
])) as ArrayRef;
let data_type =
DataType::FixedSizeList(FieldRef::new(Field::new("item", DataType::Int64, true)), 2);
let opt = CastOptions::default();
let r = cast_with_options(&array, &data_type, &opt).unwrap();

let fixed_array = Arc::new(FixedSizeListArray::from_iter_primitive::<Int64Type, _, _>(
vec![None, Some(vec![Some(1), Some(2)])],
2,
)) as ArrayRef;
assert_eq!(*fixed_array, *r);
}

#[test]
fn test_first_last_none() {
let array = Arc::new(ListArray::from_iter_primitive::<Int64Type, _, _>(vec![
None,
Some(vec![Some(1), Some(2)]),
None,
])) as ArrayRef;
let data_type =
DataType::FixedSizeList(FieldRef::new(Field::new("item", DataType::Int64, true)), 2);
let opt = CastOptions::default();
let r = cast_with_options(&array, &data_type, &opt).unwrap();

let fixed_array = Arc::new(FixedSizeListArray::from_iter_primitive::<Int64Type, _, _>(
vec![None, Some(vec![Some(1), Some(2)]), None],
2,
)) as ArrayRef;
assert_eq!(*fixed_array, *r);
}
}

0 comments on commit 0bbfc03

Please sign in to comment.