Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 73 additions & 1 deletion arrow-array/src/array/struct_array.rs
Original file line number Diff line number Diff line change
Expand Up @@ -294,10 +294,19 @@ impl StructArray {

impl From<ArrayData> for StructArray {
fn from(data: ArrayData) -> Self {
let parent_offset = data.offset();
let parent_len = data.len();

let fields = data
.child_data()
.iter()
.map(|cd| make_array(cd.clone()))
.map(|cd| {
if parent_offset != 0 || cd.len() != parent_len {
Comment thread
alamb marked this conversation as resolved.
Outdated
make_array(cd.slice(parent_offset, parent_len))
} else {
make_array(cd.clone())
}
})
.collect();

Self {
Expand Down Expand Up @@ -523,6 +532,69 @@ mod tests {
assert_eq!(0, struct_array.offset());
}

#[test]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did verify that these tests fail without the code change in this PR



thread 'array::struct_array::tests::test_struct_array_from_data_with_offset_and_length' panicked at arrow-array/src/array/struct_array.rs:551:9:
assertion `left == right` failed
  left: StructArray
-- validity:

fn test_struct_array_from_data_with_offset_and_length() {
// Case 1: Null buffer has no offset
let int_arr = Int32Array::from(vec![1, 2, 3, 4, 5]);
let int_field = Field::new("x", DataType::Int32, false);
let struct_nulls = NullBuffer::new(BooleanBuffer::from(vec![true, true, false]));
Comment thread
alamb marked this conversation as resolved.
Outdated
let int_data = int_arr.to_data();
let struct_data =
ArrayData::builder(DataType::Struct(Fields::from(vec![int_field.clone()])))
.len(3)
.offset(1)
.nulls(Some(struct_nulls))
.add_child_data(int_data.clone())
.build()
.unwrap();
let struct_arr_from_data = StructArray::from(struct_data);

let struct_arr = StructArray::new(
Fields::from(vec![int_field.clone()]),
vec![Arc::new(int_arr)],
Some(NullBuffer::new(BooleanBuffer::from(vec![
true, true, true, false, true,
]))),
)
.slice(1, 3);

assert_eq!(struct_arr_from_data, struct_arr);

// Case 2: Null buffer has offset
let struct_nulls =
NullBuffer::new(BooleanBuffer::from(vec![true, true, true, false, true]).slice(1, 3));
let struct_data =
ArrayData::builder(DataType::Struct(Fields::from(vec![int_field.clone()])))
.len(3)
.offset(1)
.nulls(Some(struct_nulls))
.add_child_data(int_data)
.build()
.unwrap();
let struct_arr_from_data = StructArray::from(struct_data);

assert_eq!(struct_arr_from_data, struct_arr);
}

#[test]
#[should_panic(expected = "assertion failed: (offset + length) <= self.len()")]
fn test_struct_array_from_data_with_offset_and_length_error() {
let int_arr = Int32Array::from(vec![1, 2, 3, 4, 5]);
let int_field = Field::new("x", DataType::Int32, false);
let struct_nulls = NullBuffer::new(BooleanBuffer::from(vec![true, true, false]));
let int_data = int_arr.to_data();
// If parent offset is 3 and len is 3 then child must have 6 items
let struct_data =
ArrayData::builder(DataType::Struct(Fields::from(vec![int_field.clone()])))
.len(3)
.offset(3)
.nulls(Some(struct_nulls))
.add_child_data(int_data)
.build()
.unwrap();
let _ = StructArray::from(struct_data);
}

/// validates that struct can be accessed using `column_name` as index i.e. `struct_array["column_name"]`.
#[test]
fn test_struct_array_index_access() {
Expand Down
20 changes: 6 additions & 14 deletions arrow-ipc/src/reader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2548,12 +2548,7 @@ mod tests {
fn test_invalid_struct_array_ipc_read_errors() {
let a_field = Field::new("a", DataType::Int32, false);
let b_field = Field::new("b", DataType::Int32, false);

let schema = Arc::new(Schema::new(vec![Field::new_struct(
"s",
vec![a_field.clone(), b_field.clone()],
false,
)]));
let struct_fields = Fields::from(vec![a_field.clone(), b_field.clone()]);

let a_array_data = ArrayData::builder(a_field.data_type().clone())
.len(4)
Expand All @@ -2566,17 +2561,14 @@ mod tests {
.build()
.unwrap();

let struct_data_type = schema.field(0).data_type();

let invalid_struct_arr = unsafe {
make_array(
ArrayData::builder(struct_data_type.clone())
.len(4)
.add_child_data(a_array_data)
.add_child_data(b_array_data)
.build_unchecked(),
StructArray::new_unchecked(
struct_fields,
vec![make_array(a_array_data), make_array(b_array_data)],
None,
)
};

expect_ipc_validation_error(
Arc::new(invalid_struct_arr),
"Invalid argument error: Incorrect array length for StructArray field \"b\", expected 4 got 3",
Expand Down
Loading