1420 lines
41 KiB
Rust
1420 lines
41 KiB
Rust
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
use arrow::array::{
|
|
Array, ArrayRef, BooleanArray, Decimal128Array, FixedSizeBinaryArray, FixedSizeBinaryBuilder,
|
|
FixedSizeListBuilder, GenericBinaryArray, GenericStringArray, Int32Array, Int32Builder,
|
|
Int64Builder, ListArray, ListBuilder, NullArray, OffsetSizeTrait, StringArray,
|
|
StringDictionaryBuilder, StructArray, UnionBuilder, make_array,
|
|
};
|
|
use arrow::datatypes::{Int16Type, Int32Type};
|
|
use arrow_array::builder::{
|
|
GenericListViewBuilder, StringBuilder, StringViewBuilder, StructBuilder,
|
|
};
|
|
use arrow_array::cast::AsArray;
|
|
use arrow_array::{
|
|
DictionaryArray, FixedSizeListArray, GenericListViewArray, PrimitiveArray, StringViewArray,
|
|
};
|
|
use arrow_buffer::{Buffer, ToByteSlice};
|
|
use arrow_data::{ArrayData, ArrayDataBuilder};
|
|
use arrow_schema::{DataType, Field, Fields};
|
|
use arrow_select::take::take;
|
|
use std::sync::Arc;
|
|
|
|
#[test]
|
|
fn test_null_equal() {
|
|
let a = NullArray::new(12);
|
|
let b = NullArray::new(12);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = NullArray::new(10);
|
|
test_equal(&a, &b, false);
|
|
|
|
// Test the case where offset != 0
|
|
|
|
let a_slice = a.slice(2, 3);
|
|
let b_slice = b.slice(1, 3);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
|
|
let a_slice = a.slice(5, 4);
|
|
let b_slice = b.slice(3, 3);
|
|
test_equal(&a_slice, &b_slice, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_boolean_equal() {
|
|
let a = BooleanArray::from(vec![false, false, true]);
|
|
let b = BooleanArray::from(vec![false, false, true]);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = BooleanArray::from(vec![false, false, false]);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_boolean_equal_nulls() {
|
|
let a = BooleanArray::from(vec![Some(false), None, None, Some(true)]);
|
|
let b = BooleanArray::from(vec![Some(false), None, None, Some(true)]);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = BooleanArray::from(vec![None, None, None, Some(true)]);
|
|
test_equal(&a, &b, false);
|
|
|
|
let b = BooleanArray::from(vec![Some(true), None, None, Some(true)]);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_boolean_equal_offset() {
|
|
let a = BooleanArray::from(vec![false, true, false, true, false, false, true]);
|
|
let b = BooleanArray::from(vec![true, false, false, false, true, false, true, true]);
|
|
test_equal(&a, &b, false);
|
|
|
|
let a_slice = a.slice(2, 3);
|
|
let b_slice = b.slice(3, 3);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
|
|
let a_slice = a.slice(3, 4);
|
|
let b_slice = b.slice(4, 4);
|
|
test_equal(&a_slice, &b_slice, false);
|
|
|
|
// Test the optimization cases where null_count == 0 and starts at 0 and len >= size_of(u8)
|
|
|
|
// Elements fill in `u8`'s exactly.
|
|
let mut vector = vec![false, false, true, true, true, true, true, true];
|
|
let a = BooleanArray::from(vector.clone());
|
|
let b = BooleanArray::from(vector.clone());
|
|
test_equal(&a, &b, true);
|
|
|
|
// Elements fill in `u8`s + suffix bits.
|
|
vector.push(true);
|
|
let a = BooleanArray::from(vector.clone());
|
|
let b = BooleanArray::from(vector);
|
|
test_equal(&a, &b, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_primitive() {
|
|
let cases = vec![
|
|
(
|
|
vec![Some(1), Some(2), Some(3)],
|
|
vec![Some(1), Some(2), Some(3)],
|
|
true,
|
|
),
|
|
(
|
|
vec![Some(1), Some(2), Some(3)],
|
|
vec![Some(1), Some(2), Some(4)],
|
|
false,
|
|
),
|
|
(
|
|
vec![Some(1), Some(2), None],
|
|
vec![Some(1), Some(2), None],
|
|
true,
|
|
),
|
|
(
|
|
vec![Some(1), None, Some(3)],
|
|
vec![Some(1), Some(2), None],
|
|
false,
|
|
),
|
|
(
|
|
vec![Some(1), None, None],
|
|
vec![Some(1), Some(2), None],
|
|
false,
|
|
),
|
|
];
|
|
|
|
for (lhs, rhs, expected) in cases {
|
|
let lhs = Int32Array::from(lhs);
|
|
let rhs = Int32Array::from(rhs);
|
|
test_equal(&lhs, &rhs, expected);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_primitive_slice() {
|
|
let cases = vec![
|
|
(
|
|
vec![Some(1), Some(2), Some(3)],
|
|
(0, 1),
|
|
vec![Some(1), Some(2), Some(3)],
|
|
(0, 1),
|
|
true,
|
|
),
|
|
(
|
|
vec![Some(1), Some(2), Some(3)],
|
|
(1, 1),
|
|
vec![Some(1), Some(2), Some(3)],
|
|
(2, 1),
|
|
false,
|
|
),
|
|
(
|
|
vec![Some(1), Some(2), None],
|
|
(1, 1),
|
|
vec![Some(1), None, Some(2)],
|
|
(2, 1),
|
|
true,
|
|
),
|
|
(
|
|
vec![None, Some(2), None],
|
|
(1, 1),
|
|
vec![None, None, Some(2)],
|
|
(2, 1),
|
|
true,
|
|
),
|
|
(
|
|
vec![Some(1), None, Some(2), None, Some(3)],
|
|
(2, 2),
|
|
vec![None, Some(2), None, Some(3)],
|
|
(1, 2),
|
|
true,
|
|
),
|
|
(
|
|
vec![Some(1), Some(2), None, Some(0)],
|
|
(2, 2),
|
|
vec![Some(4), Some(5), Some(0), None],
|
|
(2, 2),
|
|
false,
|
|
),
|
|
];
|
|
|
|
for (lhs, slice_lhs, rhs, slice_rhs, expected) in cases {
|
|
let lhs = Int32Array::from(lhs);
|
|
let lhs = lhs.slice(slice_lhs.0, slice_lhs.1);
|
|
let rhs = Int32Array::from(rhs);
|
|
let rhs = rhs.slice(slice_rhs.0, slice_rhs.1);
|
|
|
|
test_equal(&lhs, &rhs, expected);
|
|
}
|
|
}
|
|
|
|
#[allow(clippy::eq_op)]
|
|
fn test_equal(lhs: &dyn Array, rhs: &dyn Array, expected: bool) {
|
|
// equality is symmetric
|
|
assert_eq!(lhs, lhs);
|
|
assert_eq!(rhs, rhs);
|
|
|
|
match expected {
|
|
true => {
|
|
assert_eq!(lhs, rhs);
|
|
assert_eq!(rhs, lhs);
|
|
}
|
|
false => {
|
|
assert_ne!(lhs, rhs);
|
|
assert_ne!(rhs, lhs);
|
|
}
|
|
}
|
|
}
|
|
|
|
type OptionString = Option<String>;
|
|
|
|
fn binary_cases() -> Vec<(Vec<OptionString>, Vec<OptionString>, bool)> {
|
|
let base = vec![
|
|
Some("hello".to_owned()),
|
|
None,
|
|
None,
|
|
Some("world".to_owned()),
|
|
None,
|
|
None,
|
|
];
|
|
let not_base = vec![
|
|
Some("hello".to_owned()),
|
|
Some("foo".to_owned()),
|
|
None,
|
|
Some("world".to_owned()),
|
|
None,
|
|
None,
|
|
];
|
|
vec![
|
|
(
|
|
vec![Some("hello".to_owned()), Some("world".to_owned())],
|
|
vec![Some("hello".to_owned()), Some("world".to_owned())],
|
|
true,
|
|
),
|
|
(
|
|
vec![Some("hello".to_owned()), Some("world".to_owned())],
|
|
vec![Some("hello".to_owned()), Some("arrow".to_owned())],
|
|
false,
|
|
),
|
|
(base.clone(), base.clone(), true),
|
|
(base, not_base, false),
|
|
]
|
|
}
|
|
|
|
fn test_generic_string_equal<OffsetSize: OffsetSizeTrait>() {
|
|
let cases = binary_cases();
|
|
|
|
for (lhs, rhs, expected) in cases {
|
|
let lhs: GenericStringArray<OffsetSize> = lhs.into_iter().collect();
|
|
let rhs: GenericStringArray<OffsetSize> = rhs.into_iter().collect();
|
|
test_equal(&lhs, &rhs, expected);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_string_equal() {
|
|
test_generic_string_equal::<i32>()
|
|
}
|
|
|
|
#[test]
|
|
fn test_large_string_equal() {
|
|
test_generic_string_equal::<i64>()
|
|
}
|
|
|
|
fn test_generic_binary_equal<OffsetSize: OffsetSizeTrait>() {
|
|
let cases = binary_cases();
|
|
|
|
for (lhs, rhs, expected) in cases {
|
|
let lhs = lhs
|
|
.iter()
|
|
.map(|x| x.as_deref().map(|x| x.as_bytes()))
|
|
.collect();
|
|
let rhs = rhs
|
|
.iter()
|
|
.map(|x| x.as_deref().map(|x| x.as_bytes()))
|
|
.collect();
|
|
let lhs = GenericBinaryArray::<OffsetSize>::from_opt_vec(lhs);
|
|
let rhs = GenericBinaryArray::<OffsetSize>::from_opt_vec(rhs);
|
|
test_equal(&lhs, &rhs, expected);
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn test_binary_equal() {
|
|
test_generic_binary_equal::<i32>()
|
|
}
|
|
|
|
#[test]
|
|
fn test_large_binary_equal() {
|
|
test_generic_binary_equal::<i64>()
|
|
}
|
|
|
|
#[test]
|
|
fn test_fixed_size_binary_array() {
|
|
let a_input_arg = vec![vec![1, 2], vec![3, 4], vec![5, 6]];
|
|
let a = FixedSizeBinaryArray::try_from_iter(a_input_arg.into_iter()).unwrap();
|
|
|
|
let b_input_arg = vec![vec![1, 2], vec![3, 4], vec![5, 6]];
|
|
let b = FixedSizeBinaryArray::try_from_iter(b_input_arg.into_iter()).unwrap();
|
|
|
|
test_equal(&a, &b, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_string_view_equal() {
|
|
let a1 = StringViewArray::from(vec!["foo", "very long string over 12 bytes", "bar"]);
|
|
let a2 = StringViewArray::from(vec![
|
|
"a very long string over 12 bytes",
|
|
"foo",
|
|
"very long string over 12 bytes",
|
|
"bar",
|
|
]);
|
|
test_equal(&a1, &a2.slice(1, 3), true);
|
|
|
|
let a1 = StringViewArray::from(vec!["foo", "very long string over 12 bytes", "bar"]);
|
|
let a2 = StringViewArray::from(vec!["foo", "very long string over 12 bytes", "bar"]);
|
|
test_equal(&a1, &a2, true);
|
|
|
|
let a1_s = a1.slice(1, 1);
|
|
let a2_s = a2.slice(1, 1);
|
|
test_equal(&a1_s, &a2_s, true);
|
|
|
|
let a1_s = a1.slice(2, 1);
|
|
let a2_s = a2.slice(0, 1);
|
|
test_equal(&a1_s, &a2_s, false);
|
|
|
|
// test will null value.
|
|
let a1 = StringViewArray::from(vec!["foo", "very long string over 12 bytes", "bar"]);
|
|
let a2 = {
|
|
let mut builder = StringViewBuilder::new();
|
|
builder.append_value("foo");
|
|
builder.append_null();
|
|
builder.append_option(Some("very long string over 12 bytes"));
|
|
builder.append_value("bar");
|
|
builder.finish()
|
|
};
|
|
test_equal(&a1, &a2, false);
|
|
|
|
let a1_s = a1.slice(1, 2);
|
|
let a2_s = a2.slice(1, 3);
|
|
test_equal(&a1_s, &a2_s, false);
|
|
|
|
let a1_s = a1.slice(1, 2);
|
|
let a2_s = a2.slice(2, 2);
|
|
test_equal(&a1_s, &a2_s, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_string_offset() {
|
|
let a = StringArray::from(vec![Some("a"), None, Some("b")]);
|
|
let a = a.slice(2, 1);
|
|
let b = StringArray::from(vec![Some("b")]);
|
|
|
|
test_equal(&a, &b, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_string_offset_larger() {
|
|
let a = StringArray::from(vec![Some("a"), None, Some("b"), None, Some("c")]);
|
|
let b = StringArray::from(vec![None, Some("b"), None, Some("c")]);
|
|
|
|
test_equal(&a.slice(2, 2), &b.slice(0, 2), false);
|
|
test_equal(&a.slice(2, 2), &b.slice(1, 2), true);
|
|
test_equal(&a.slice(2, 2), &b.slice(2, 2), false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_null() {
|
|
let a = NullArray::new(2);
|
|
let b = NullArray::new(2);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = NullArray::new(1);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
fn create_list_array<U: AsRef<[i32]>, T: AsRef<[Option<U>]>>(data: T) -> ListArray {
|
|
let mut builder = ListBuilder::new(Int32Builder::with_capacity(10));
|
|
for d in data.as_ref() {
|
|
if let Some(v) = d {
|
|
builder.values().append_slice(v.as_ref());
|
|
builder.append(true);
|
|
} else {
|
|
builder.append(false);
|
|
}
|
|
}
|
|
builder.finish()
|
|
}
|
|
|
|
#[test]
|
|
fn test_list_equal() {
|
|
let a = create_list_array([Some(&[1, 2, 3]), Some(&[4, 5, 6])]);
|
|
let b = create_list_array([Some(&[1, 2, 3]), Some(&[4, 5, 6])]);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = create_list_array([Some(&[1, 2, 3]), Some(&[4, 5, 7])]);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_empty_offsets_list_equal() {
|
|
let empty: Vec<i32> = vec![];
|
|
let values = Int32Array::from(empty);
|
|
let empty_offsets: [u8; 0] = [];
|
|
|
|
let a: ListArray = ArrayDataBuilder::new(DataType::List(Arc::new(Field::new_list_field(
|
|
DataType::Int32,
|
|
true,
|
|
))))
|
|
.len(0)
|
|
.add_buffer(Buffer::from(&empty_offsets))
|
|
.add_child_data(values.to_data())
|
|
.null_bit_buffer(Some(Buffer::from(&empty_offsets)))
|
|
.build()
|
|
.unwrap()
|
|
.into();
|
|
|
|
let b: ListArray = ArrayDataBuilder::new(DataType::List(Arc::new(Field::new_list_field(
|
|
DataType::Int32,
|
|
true,
|
|
))))
|
|
.len(0)
|
|
.add_buffer(Buffer::from(&empty_offsets))
|
|
.add_child_data(values.to_data())
|
|
.null_bit_buffer(Some(Buffer::from(&empty_offsets)))
|
|
.build()
|
|
.unwrap()
|
|
.into();
|
|
|
|
test_equal(&a, &b, true);
|
|
|
|
let c: ListArray = ArrayDataBuilder::new(DataType::List(Arc::new(Field::new_list_field(
|
|
DataType::Int32,
|
|
true,
|
|
))))
|
|
.len(0)
|
|
.add_buffer(Buffer::from([0i32, 2, 3, 4, 6, 7, 8].to_byte_slice()))
|
|
.add_child_data(Int32Array::from(vec![1, 2, -1, -2, 3, 4, -3, -4]).into_data())
|
|
.null_bit_buffer(Some(Buffer::from([0b00001001])))
|
|
.build()
|
|
.unwrap()
|
|
.into();
|
|
|
|
test_equal(&a, &c, true);
|
|
}
|
|
|
|
// Test the case where null_count > 0
|
|
#[test]
|
|
fn test_list_null() {
|
|
let a = create_list_array([Some(&[1, 2]), None, None, Some(&[3, 4]), None, None]);
|
|
let b = create_list_array([Some(&[1, 2]), None, None, Some(&[3, 4]), None, None]);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = create_list_array([
|
|
Some(&[1, 2]),
|
|
None,
|
|
Some(&[5, 6]),
|
|
Some(&[3, 4]),
|
|
None,
|
|
None,
|
|
]);
|
|
test_equal(&a, &b, false);
|
|
|
|
let b = create_list_array([Some(&[1, 2]), None, None, Some(&[3, 5]), None, None]);
|
|
test_equal(&a, &b, false);
|
|
|
|
// a list where the nullness of values is determined by the list's bitmap
|
|
let c_values = Int32Array::from(vec![1, 2, -1, -2, 3, 4, -3, -4]);
|
|
let c: ListArray = ArrayDataBuilder::new(DataType::List(Arc::new(Field::new_list_field(
|
|
DataType::Int32,
|
|
true,
|
|
))))
|
|
.len(6)
|
|
.add_buffer(Buffer::from([0i32, 2, 3, 4, 6, 7, 8].to_byte_slice()))
|
|
.add_child_data(c_values.into_data())
|
|
.null_bit_buffer(Some(Buffer::from([0b00001001])))
|
|
.build()
|
|
.unwrap()
|
|
.into();
|
|
|
|
let d_values = Int32Array::from(vec![
|
|
Some(1),
|
|
Some(2),
|
|
None,
|
|
None,
|
|
Some(3),
|
|
Some(4),
|
|
None,
|
|
None,
|
|
]);
|
|
let d: ListArray = ArrayDataBuilder::new(DataType::List(Arc::new(Field::new_list_field(
|
|
DataType::Int32,
|
|
true,
|
|
))))
|
|
.len(6)
|
|
.add_buffer(Buffer::from([0i32, 2, 3, 4, 6, 7, 8].to_byte_slice()))
|
|
.add_child_data(d_values.into_data())
|
|
.null_bit_buffer(Some(Buffer::from([0b00001001])))
|
|
.build()
|
|
.unwrap()
|
|
.into();
|
|
test_equal(&c, &d, true);
|
|
}
|
|
|
|
// Test the case where offset != 0
|
|
#[test]
|
|
fn test_list_offsets() {
|
|
let a = create_list_array([Some(&[1, 2]), None, None, Some(&[3, 4]), None, None]);
|
|
let b = create_list_array([Some(&[1, 2]), None, None, Some(&[3, 5]), None, None]);
|
|
|
|
let a_slice = a.slice(0, 3);
|
|
let b_slice = b.slice(0, 3);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
|
|
let a_slice = a.slice(0, 5);
|
|
let b_slice = b.slice(0, 5);
|
|
test_equal(&a_slice, &b_slice, false);
|
|
|
|
let a_slice = a.slice(4, 1);
|
|
let b_slice = b.slice(4, 1);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
}
|
|
|
|
fn create_fixed_size_binary_array<U: AsRef<[u8]>, T: AsRef<[Option<U>]>>(
|
|
data: T,
|
|
) -> FixedSizeBinaryArray {
|
|
let mut builder = FixedSizeBinaryBuilder::with_capacity(data.as_ref().len(), 5);
|
|
|
|
for d in data.as_ref() {
|
|
if let Some(v) = d {
|
|
builder.append_value(v.as_ref()).unwrap();
|
|
} else {
|
|
builder.append_null();
|
|
}
|
|
}
|
|
builder.finish()
|
|
}
|
|
|
|
#[test]
|
|
fn test_fixed_size_binary_equal() {
|
|
let a = create_fixed_size_binary_array([Some(b"hello"), Some(b"world")]);
|
|
let b = create_fixed_size_binary_array([Some(b"hello"), Some(b"world")]);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = create_fixed_size_binary_array([Some(b"hello"), Some(b"arrow")]);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
// Test the case where null_count > 0
|
|
#[test]
|
|
fn test_fixed_size_binary_null() {
|
|
let a = create_fixed_size_binary_array([Some(b"hello"), None, Some(b"world")]);
|
|
let b = create_fixed_size_binary_array([Some(b"hello"), None, Some(b"world")]);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = create_fixed_size_binary_array([Some(b"hello"), Some(b"world"), None]);
|
|
test_equal(&a, &b, false);
|
|
|
|
let b = create_fixed_size_binary_array([Some(b"hello"), None, Some(b"arrow")]);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_fixed_size_binary_offsets() {
|
|
// Test the case where offset != 0
|
|
let a =
|
|
create_fixed_size_binary_array([Some(b"hello"), None, None, Some(b"world"), None, None]);
|
|
let b =
|
|
create_fixed_size_binary_array([Some(b"hello"), None, None, Some(b"arrow"), None, None]);
|
|
|
|
let a_slice = a.slice(0, 3);
|
|
let b_slice = b.slice(0, 3);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
|
|
let a_slice = a.slice(0, 5);
|
|
let b_slice = b.slice(0, 5);
|
|
test_equal(&a_slice, &b_slice, false);
|
|
|
|
let a_slice = a.slice(4, 1);
|
|
let b_slice = b.slice(4, 1);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
|
|
let a_slice = a.slice(3, 1);
|
|
let b_slice = b.slice(3, 1);
|
|
test_equal(&a_slice, &b_slice, false);
|
|
}
|
|
|
|
fn create_decimal_array(data: Vec<Option<i128>>) -> Decimal128Array {
|
|
data.into_iter()
|
|
.collect::<Decimal128Array>()
|
|
.with_precision_and_scale(23, 6)
|
|
.unwrap()
|
|
}
|
|
|
|
#[test]
|
|
fn test_decimal_equal() {
|
|
let a = create_decimal_array(vec![Some(8_887_000_000), Some(-8_887_000_000)]);
|
|
let b = create_decimal_array(vec![Some(8_887_000_000), Some(-8_887_000_000)]);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = create_decimal_array(vec![Some(15_887_000_000), Some(-8_887_000_000)]);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
// Test the case where null_count > 0
|
|
#[test]
|
|
fn test_decimal_null() {
|
|
let a = create_decimal_array(vec![Some(8_887_000_000), None, Some(-8_887_000_000)]);
|
|
let b = create_decimal_array(vec![Some(8_887_000_000), None, Some(-8_887_000_000)]);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = create_decimal_array(vec![Some(8_887_000_000), Some(-8_887_000_000), None]);
|
|
test_equal(&a, &b, false);
|
|
|
|
let b = create_decimal_array(vec![Some(15_887_000_000), None, Some(-8_887_000_000)]);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_decimal_offsets() {
|
|
// Test the case where offset != 0
|
|
let a = create_decimal_array(vec![
|
|
Some(8_887_000_000),
|
|
None,
|
|
None,
|
|
Some(-8_887_000_000),
|
|
None,
|
|
None,
|
|
]);
|
|
let b = create_decimal_array(vec![
|
|
None,
|
|
Some(8_887_000_000),
|
|
None,
|
|
None,
|
|
Some(15_887_000_000),
|
|
None,
|
|
None,
|
|
]);
|
|
|
|
let a_slice = a.slice(0, 3);
|
|
let b_slice = b.slice(1, 3);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
|
|
let a_slice = a.slice(0, 5);
|
|
let b_slice = b.slice(1, 5);
|
|
test_equal(&a_slice, &b_slice, false);
|
|
|
|
let a_slice = a.slice(4, 1);
|
|
let b_slice = b.slice(5, 1);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
|
|
let a_slice = a.slice(3, 3);
|
|
let b_slice = b.slice(4, 3);
|
|
test_equal(&a_slice, &b_slice, false);
|
|
|
|
let a_slice = a.slice(1, 3);
|
|
let b_slice = b.slice(2, 3);
|
|
test_equal(&a_slice, &b_slice, false);
|
|
|
|
let b = create_decimal_array(vec![
|
|
None,
|
|
None,
|
|
None,
|
|
Some(-8_887_000_000),
|
|
Some(-3_000),
|
|
None,
|
|
]);
|
|
let a_slice = a.slice(1, 3);
|
|
let b_slice = b.slice(1, 3);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
}
|
|
|
|
/// Create a fixed size list of 2 value lengths
|
|
fn create_fixed_size_list_array<U: AsRef<[i32]>, T: AsRef<[Option<U>]>>(
|
|
data: T,
|
|
) -> FixedSizeListArray {
|
|
let mut builder = FixedSizeListBuilder::new(Int32Builder::with_capacity(10), 3);
|
|
|
|
for d in data.as_ref() {
|
|
if let Some(v) = d {
|
|
builder.values().append_slice(v.as_ref());
|
|
builder.append(true);
|
|
} else {
|
|
for _ in 0..builder.value_length() {
|
|
builder.values().append_null();
|
|
}
|
|
builder.append(false);
|
|
}
|
|
}
|
|
builder.finish()
|
|
}
|
|
|
|
#[test]
|
|
fn test_fixed_size_list_equal() {
|
|
let a = create_fixed_size_list_array([Some(&[1, 2, 3]), Some(&[4, 5, 6])]);
|
|
let b = create_fixed_size_list_array([Some(&[1, 2, 3]), Some(&[4, 5, 6])]);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = create_fixed_size_list_array([Some(&[1, 2, 3]), Some(&[4, 5, 7])]);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
// Test the case where null_count > 0
|
|
#[test]
|
|
fn test_fixed_list_null() {
|
|
let a =
|
|
create_fixed_size_list_array([Some(&[1, 2, 3]), None, None, Some(&[4, 5, 6]), None, None]);
|
|
let b =
|
|
create_fixed_size_list_array([Some(&[1, 2, 3]), None, None, Some(&[4, 5, 6]), None, None]);
|
|
test_equal(&a, &b, true);
|
|
|
|
let b = create_fixed_size_list_array([
|
|
Some(&[1, 2, 3]),
|
|
None,
|
|
Some(&[7, 8, 9]),
|
|
Some(&[4, 5, 6]),
|
|
None,
|
|
None,
|
|
]);
|
|
test_equal(&a, &b, false);
|
|
|
|
let b =
|
|
create_fixed_size_list_array([Some(&[1, 2, 3]), None, None, Some(&[3, 6, 9]), None, None]);
|
|
test_equal(&a, &b, false);
|
|
|
|
let b = create_fixed_size_list_array([None, Some(&[4, 5, 6]), None, None]);
|
|
|
|
test_equal(&a.slice(2, 4), &b, true);
|
|
test_equal(&a.slice(3, 3), &b.slice(1, 3), true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_fixed_list_offsets() {
|
|
// Test the case where offset != 0
|
|
let a =
|
|
create_fixed_size_list_array([Some(&[1, 2, 3]), None, None, Some(&[4, 5, 6]), None, None]);
|
|
let b =
|
|
create_fixed_size_list_array([Some(&[1, 2, 3]), None, None, Some(&[3, 6, 9]), None, None]);
|
|
|
|
let a_slice = a.slice(0, 3);
|
|
let b_slice = b.slice(0, 3);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
|
|
let a_slice = a.slice(0, 5);
|
|
let b_slice = b.slice(0, 5);
|
|
test_equal(&a_slice, &b_slice, false);
|
|
|
|
let a_slice = a.slice(4, 1);
|
|
let b_slice = b.slice(4, 1);
|
|
test_equal(&a_slice, &b_slice, true);
|
|
}
|
|
|
|
fn create_list_view_array<
|
|
O: OffsetSizeTrait,
|
|
U: IntoIterator<Item = Option<i32>>,
|
|
T: IntoIterator<Item = Option<U>>,
|
|
>(
|
|
data: T,
|
|
) -> GenericListViewArray<O> {
|
|
let mut builder = GenericListViewBuilder::<O, _>::new(Int32Builder::new());
|
|
for d in data {
|
|
if let Some(v) = d {
|
|
builder.append_value(v);
|
|
} else {
|
|
builder.append_null();
|
|
}
|
|
}
|
|
|
|
builder.finish()
|
|
}
|
|
|
|
fn test_test_list_view_array<T: OffsetSizeTrait>() {
|
|
let a = create_list_view_array::<T, _, _>([
|
|
None,
|
|
Some(vec![Some(1), None, Some(2)]),
|
|
Some(vec![Some(3), Some(4), Some(5), None]),
|
|
]);
|
|
let b = create_list_view_array::<T, _, _>([
|
|
None,
|
|
Some(vec![Some(1), None, Some(2)]),
|
|
Some(vec![Some(3), Some(4), Some(5), None]),
|
|
]);
|
|
|
|
test_equal(&a, &b, true);
|
|
|
|
// Simple non-matching arrays by reordering
|
|
let b = create_list_view_array::<T, _, _>([
|
|
Some(vec![Some(3), Some(4), Some(5), None]),
|
|
Some(vec![Some(1), None, Some(2)]),
|
|
]);
|
|
test_equal(&a, &b, false);
|
|
|
|
// reorder using take yields equal values
|
|
let indices: PrimitiveArray<Int32Type> = vec![None, Some(1), Some(0)].into();
|
|
let b = take(&b, &indices, None)
|
|
.unwrap()
|
|
.as_list_view::<T>()
|
|
.clone();
|
|
|
|
test_equal(&a, &b, true);
|
|
|
|
// Slicing one side yields unequal again
|
|
let a = a.slice(1, 2);
|
|
|
|
test_equal(&a, &b, false);
|
|
|
|
// Slicing the other to match makes them equal again
|
|
let b = b.slice(1, 2);
|
|
|
|
test_equal(&a, &b, true);
|
|
}
|
|
|
|
// Special test for List<ListView<i32>>.
|
|
// This tests the equal_ranges kernel
|
|
fn test_sliced_list_of_list_view<T: OffsetSizeTrait>() {
|
|
// First list view is created using the builder, with elements not deduplicated.
|
|
let mut a = ListBuilder::new(GenericListViewBuilder::<T, _>::new(Int32Builder::new()));
|
|
|
|
a.append_value([Some(vec![Some(1), Some(2), Some(3)]), Some(vec![])]);
|
|
a.append_null();
|
|
a.append_value([
|
|
Some(vec![Some(1), Some(2), Some(3)]),
|
|
None,
|
|
Some(vec![Some(6)]),
|
|
]);
|
|
|
|
let a = a.finish();
|
|
// a = [[[1,2,3], []], null, [[4, null], [5], null, [6]]]
|
|
|
|
// First list view is created using the builder, with elements not deduplicated.
|
|
let mut b = ListBuilder::new(GenericListViewBuilder::<T, _>::new(Int32Builder::new()));
|
|
|
|
// Add an extra row that we will slice off, adjust the List offsets
|
|
b.append_value([Some(vec![Some(0), Some(0), Some(0)])]);
|
|
b.append_value([Some(vec![Some(1), Some(2), Some(3)]), Some(vec![])]);
|
|
b.append_null();
|
|
b.append_value([
|
|
Some(vec![Some(1), Some(2), Some(3)]),
|
|
None,
|
|
Some(vec![Some(6)]),
|
|
]);
|
|
|
|
let b = b.finish();
|
|
// b = [[[0, 0, 0]], [[1,2,3], []], null, [[4, null], [5], null, [6]]]
|
|
let b = b.slice(1, 3);
|
|
// b = [[[1,2,3], []], null, [[4, null], [5], null, [6]]] but the outer ListArray
|
|
// has an offset
|
|
|
|
test_equal(&a, &b, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_list_view_array() {
|
|
test_test_list_view_array::<i32>();
|
|
}
|
|
|
|
#[test]
|
|
fn test_large_list_view_array() {
|
|
test_test_list_view_array::<i64>();
|
|
}
|
|
|
|
#[test]
|
|
fn test_nested_list_view_array() {
|
|
test_sliced_list_of_list_view::<i32>();
|
|
}
|
|
|
|
#[test]
|
|
fn test_nested_large_list_view_array() {
|
|
test_sliced_list_of_list_view::<i64>();
|
|
}
|
|
|
|
#[test]
|
|
fn test_struct_equal() {
|
|
let strings: ArrayRef = Arc::new(StringArray::from(vec![
|
|
Some("joe"),
|
|
None,
|
|
None,
|
|
Some("mark"),
|
|
Some("doe"),
|
|
]));
|
|
let ints: ArrayRef = Arc::new(Int32Array::from(vec![
|
|
Some(1),
|
|
Some(2),
|
|
None,
|
|
Some(4),
|
|
Some(5),
|
|
]));
|
|
|
|
let a = StructArray::try_from(vec![("f1", strings.clone()), ("f2", ints.clone())]).unwrap();
|
|
|
|
let b = StructArray::try_from(vec![("f1", strings), ("f2", ints)]).unwrap();
|
|
|
|
test_equal(&a, &b, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_struct_equal_null() {
|
|
let strings: ArrayRef = Arc::new(StringArray::from(vec![
|
|
Some("joe"),
|
|
None,
|
|
None,
|
|
Some("mark"),
|
|
Some("doe"),
|
|
]));
|
|
let ints: ArrayRef = Arc::new(Int32Array::from(vec![
|
|
Some(1),
|
|
Some(2),
|
|
None,
|
|
Some(4),
|
|
Some(5),
|
|
]));
|
|
let ints_non_null: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3, 4, 0]));
|
|
|
|
let a = ArrayData::builder(DataType::Struct(Fields::from(vec![
|
|
Field::new("f1", DataType::Utf8, true),
|
|
Field::new("f2", DataType::Int32, true),
|
|
])))
|
|
.null_bit_buffer(Some(Buffer::from([0b00001011])))
|
|
.len(5)
|
|
.add_child_data(strings.to_data())
|
|
.add_child_data(ints.to_data())
|
|
.build()
|
|
.unwrap();
|
|
let a = make_array(a);
|
|
|
|
let b = ArrayData::builder(DataType::Struct(Fields::from(vec![
|
|
Field::new("f1", DataType::Utf8, true),
|
|
Field::new("f2", DataType::Int32, true),
|
|
])))
|
|
.null_bit_buffer(Some(Buffer::from([0b00001011])))
|
|
.len(5)
|
|
.add_child_data(strings.to_data())
|
|
.add_child_data(ints_non_null.to_data())
|
|
.build()
|
|
.unwrap();
|
|
let b = make_array(b);
|
|
|
|
test_equal(&a, &b, true);
|
|
|
|
// test with arrays that are not equal
|
|
let c_ints_non_null: ArrayRef = Arc::new(Int32Array::from(vec![1, 2, 3, 0, 4]));
|
|
let c = ArrayData::builder(DataType::Struct(Fields::from(vec![
|
|
Field::new("f1", DataType::Utf8, true),
|
|
Field::new("f2", DataType::Int32, true),
|
|
])))
|
|
.null_bit_buffer(Some(Buffer::from([0b00001011])))
|
|
.len(5)
|
|
.add_child_data(strings.to_data())
|
|
.add_child_data(c_ints_non_null.to_data())
|
|
.build()
|
|
.unwrap();
|
|
let c = make_array(c);
|
|
|
|
test_equal(&a, &c, false);
|
|
|
|
// test a nested struct
|
|
let a = ArrayData::builder(DataType::Struct(
|
|
vec![Field::new("f3", a.data_type().clone(), true)].into(),
|
|
))
|
|
.null_bit_buffer(Some(Buffer::from([0b00011110])))
|
|
.len(5)
|
|
.add_child_data(a.to_data())
|
|
.build()
|
|
.unwrap();
|
|
let a = make_array(a);
|
|
|
|
// reconstruct b, but with different data where the first struct is null
|
|
let strings: ArrayRef = Arc::new(StringArray::from(vec![
|
|
Some("joanne"), // difference
|
|
None,
|
|
None,
|
|
Some("mark"),
|
|
Some("doe"),
|
|
]));
|
|
let b = ArrayData::builder(DataType::Struct(Fields::from(vec![
|
|
Field::new("f1", DataType::Utf8, true),
|
|
Field::new("f2", DataType::Int32, true),
|
|
])))
|
|
.null_bit_buffer(Some(Buffer::from([0b00001011])))
|
|
.len(5)
|
|
.add_child_data(strings.to_data())
|
|
.add_child_data(ints_non_null.to_data())
|
|
.build()
|
|
.unwrap();
|
|
|
|
let b = ArrayData::builder(DataType::Struct(
|
|
vec![Field::new("f3", b.data_type().clone(), true)].into(),
|
|
))
|
|
.null_bit_buffer(Some(Buffer::from([0b00011110])))
|
|
.len(5)
|
|
.add_child_data(b)
|
|
.build()
|
|
.unwrap();
|
|
let b = make_array(b);
|
|
|
|
test_equal(&a, &b, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_struct_equal_null_variable_size() {
|
|
// the string arrays differ, but where the struct array is null
|
|
let strings1: ArrayRef = Arc::new(StringArray::from(vec![
|
|
Some("joe"),
|
|
None,
|
|
None,
|
|
Some("mark"),
|
|
Some("doel"),
|
|
]));
|
|
let strings2: ArrayRef = Arc::new(StringArray::from(vec![
|
|
Some("joel"),
|
|
None,
|
|
None,
|
|
Some("mark"),
|
|
Some("doe"),
|
|
]));
|
|
|
|
let a = ArrayData::builder(DataType::Struct(
|
|
vec![Field::new("f1", DataType::Utf8, true)].into(),
|
|
))
|
|
.null_bit_buffer(Some(Buffer::from([0b00001010])))
|
|
.len(5)
|
|
.add_child_data(strings1.to_data())
|
|
.build()
|
|
.unwrap();
|
|
let a = make_array(a);
|
|
|
|
let b = ArrayData::builder(DataType::Struct(
|
|
vec![Field::new("f1", DataType::Utf8, true)].into(),
|
|
))
|
|
.null_bit_buffer(Some(Buffer::from([0b00001010])))
|
|
.len(5)
|
|
.add_child_data(strings2.to_data())
|
|
.build()
|
|
.unwrap();
|
|
let b = make_array(b);
|
|
|
|
test_equal(&a, &b, true);
|
|
|
|
// test with arrays that are not equal
|
|
let strings3: ArrayRef = Arc::new(StringArray::from(vec![
|
|
Some("mark"),
|
|
None,
|
|
None,
|
|
Some("doe"),
|
|
Some("joe"),
|
|
]));
|
|
let c = ArrayData::builder(DataType::Struct(
|
|
vec![Field::new("f1", DataType::Utf8, true)].into(),
|
|
))
|
|
.null_bit_buffer(Some(Buffer::from([0b00001011])))
|
|
.len(5)
|
|
.add_child_data(strings3.to_data())
|
|
.build()
|
|
.unwrap();
|
|
let c = make_array(c);
|
|
|
|
test_equal(&a, &c, false);
|
|
}
|
|
|
|
fn create_dictionary_array(values: &[&str], keys: &[Option<&str>]) -> DictionaryArray<Int16Type> {
|
|
let values = StringArray::from(values.to_vec());
|
|
let mut builder =
|
|
StringDictionaryBuilder::<Int16Type>::new_with_dictionary(keys.len(), &values).unwrap();
|
|
for key in keys {
|
|
if let Some(v) = key {
|
|
builder.append(v).unwrap();
|
|
} else {
|
|
builder.append_null()
|
|
}
|
|
}
|
|
builder.finish()
|
|
}
|
|
|
|
#[test]
|
|
fn test_dictionary_equal() {
|
|
// (a, b, c), (1, 2, 1, 3) => (a, b, a, c)
|
|
let a = create_dictionary_array(
|
|
&["a", "b", "c"],
|
|
&[Some("a"), Some("b"), Some("a"), Some("c")],
|
|
);
|
|
// different representation (values and keys are swapped), same result
|
|
let b = create_dictionary_array(
|
|
&["a", "c", "b"],
|
|
&[Some("a"), Some("b"), Some("a"), Some("c")],
|
|
);
|
|
test_equal(&a, &b, true);
|
|
|
|
// different len
|
|
let b = create_dictionary_array(&["a", "c", "b"], &[Some("a"), Some("b"), Some("a")]);
|
|
test_equal(&a, &b, false);
|
|
|
|
// different key
|
|
let b = create_dictionary_array(
|
|
&["a", "c", "b"],
|
|
&[Some("a"), Some("b"), Some("a"), Some("a")],
|
|
);
|
|
test_equal(&a, &b, false);
|
|
|
|
// different values, same keys
|
|
let b = create_dictionary_array(
|
|
&["a", "b", "d"],
|
|
&[Some("a"), Some("b"), Some("a"), Some("d")],
|
|
);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_dictionary_equal_null() {
|
|
// (a, b, c), (1, 2, 1, 3) => (a, b, a, c)
|
|
let a = create_dictionary_array(&["a", "b", "c"], &[Some("a"), None, Some("a"), Some("c")]);
|
|
|
|
// equal to self
|
|
test_equal(&a, &a, true);
|
|
|
|
// different representation (values and keys are swapped), same result
|
|
let b = create_dictionary_array(&["a", "c", "b"], &[Some("a"), None, Some("a"), Some("c")]);
|
|
test_equal(&a, &b, true);
|
|
|
|
// different null position
|
|
let b = create_dictionary_array(&["a", "c", "b"], &[Some("a"), Some("b"), Some("a"), None]);
|
|
test_equal(&a, &b, false);
|
|
|
|
// different key
|
|
let b = create_dictionary_array(&["a", "c", "b"], &[Some("a"), None, Some("a"), Some("a")]);
|
|
test_equal(&a, &b, false);
|
|
|
|
// different values, same keys
|
|
let b = create_dictionary_array(&["a", "b", "d"], &[Some("a"), None, Some("a"), Some("d")]);
|
|
test_equal(&a, &b, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_non_null_empty_strings() {
|
|
let s1 = StringArray::from(vec![Some(""), Some(""), Some("")]);
|
|
let data = s1.to_data().into_builder().nulls(None).build().unwrap();
|
|
let s2 = StringArray::from(data);
|
|
|
|
// s2 is identical to s1 except that it has no validity buffer but since there
|
|
// are no nulls, s1 and s2 are equal
|
|
test_equal(&s1, &s2, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_null_empty_strings() {
|
|
let s1 = StringArray::from(vec![Some(""), None, Some("")]);
|
|
let data = s1.to_data().into_builder().nulls(None).build().unwrap();
|
|
let s2 = StringArray::from(data);
|
|
|
|
// s2 is identical to s1 except that it has no validity buffer since string1 has
|
|
// nulls in it, s1 and s2 are not equal
|
|
test_equal(&s1, &s2, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_union_equal_dense() {
|
|
let mut builder = UnionBuilder::new_dense();
|
|
builder.append::<Int32Type>("a", 1).unwrap();
|
|
builder.append::<Int32Type>("b", 2).unwrap();
|
|
builder.append::<Int32Type>("c", 3).unwrap();
|
|
builder.append::<Int32Type>("a", 4).unwrap();
|
|
builder.append_null::<Int32Type>("a").unwrap();
|
|
builder.append::<Int32Type>("a", 6).unwrap();
|
|
builder.append::<Int32Type>("b", 7).unwrap();
|
|
let union1 = builder.build().unwrap();
|
|
|
|
builder = UnionBuilder::new_dense();
|
|
builder.append::<Int32Type>("a", 1).unwrap();
|
|
builder.append::<Int32Type>("b", 2).unwrap();
|
|
builder.append::<Int32Type>("c", 3).unwrap();
|
|
builder.append::<Int32Type>("a", 4).unwrap();
|
|
builder.append_null::<Int32Type>("a").unwrap();
|
|
builder.append::<Int32Type>("a", 6).unwrap();
|
|
builder.append::<Int32Type>("b", 7).unwrap();
|
|
let union2 = builder.build().unwrap();
|
|
|
|
builder = UnionBuilder::new_dense();
|
|
builder.append::<Int32Type>("a", 1).unwrap();
|
|
builder.append::<Int32Type>("b", 2).unwrap();
|
|
builder.append::<Int32Type>("c", 3).unwrap();
|
|
builder.append::<Int32Type>("a", 5).unwrap();
|
|
builder.append::<Int32Type>("c", 4).unwrap();
|
|
builder.append::<Int32Type>("a", 6).unwrap();
|
|
builder.append::<Int32Type>("b", 7).unwrap();
|
|
let union3 = builder.build().unwrap();
|
|
|
|
builder = UnionBuilder::new_dense();
|
|
builder.append::<Int32Type>("a", 1).unwrap();
|
|
builder.append::<Int32Type>("b", 2).unwrap();
|
|
builder.append::<Int32Type>("c", 3).unwrap();
|
|
builder.append::<Int32Type>("a", 4).unwrap();
|
|
builder.append_null::<Int32Type>("c").unwrap();
|
|
builder.append_null::<Int32Type>("b").unwrap();
|
|
builder.append::<Int32Type>("b", 7).unwrap();
|
|
let union4 = builder.build().unwrap();
|
|
|
|
test_equal(&union1, &union2, true);
|
|
test_equal(&union1, &union3, false);
|
|
test_equal(&union1, &union4, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_union_equal_sparse() {
|
|
let mut builder = UnionBuilder::new_sparse();
|
|
builder.append::<Int32Type>("a", 1).unwrap();
|
|
builder.append::<Int32Type>("b", 2).unwrap();
|
|
builder.append::<Int32Type>("c", 3).unwrap();
|
|
builder.append::<Int32Type>("a", 4).unwrap();
|
|
builder.append_null::<Int32Type>("a").unwrap();
|
|
builder.append::<Int32Type>("a", 6).unwrap();
|
|
builder.append::<Int32Type>("b", 7).unwrap();
|
|
let union1 = builder.build().unwrap();
|
|
|
|
builder = UnionBuilder::new_sparse();
|
|
builder.append::<Int32Type>("a", 1).unwrap();
|
|
builder.append::<Int32Type>("b", 2).unwrap();
|
|
builder.append::<Int32Type>("c", 3).unwrap();
|
|
builder.append::<Int32Type>("a", 4).unwrap();
|
|
builder.append_null::<Int32Type>("a").unwrap();
|
|
builder.append::<Int32Type>("a", 6).unwrap();
|
|
builder.append::<Int32Type>("b", 7).unwrap();
|
|
let union2 = builder.build().unwrap();
|
|
|
|
builder = UnionBuilder::new_sparse();
|
|
builder.append::<Int32Type>("a", 1).unwrap();
|
|
builder.append::<Int32Type>("b", 2).unwrap();
|
|
builder.append::<Int32Type>("c", 3).unwrap();
|
|
builder.append::<Int32Type>("a", 5).unwrap();
|
|
builder.append::<Int32Type>("c", 4).unwrap();
|
|
builder.append::<Int32Type>("a", 6).unwrap();
|
|
builder.append::<Int32Type>("b", 7).unwrap();
|
|
let union3 = builder.build().unwrap();
|
|
|
|
builder = UnionBuilder::new_sparse();
|
|
builder.append::<Int32Type>("a", 1).unwrap();
|
|
builder.append::<Int32Type>("b", 2).unwrap();
|
|
builder.append::<Int32Type>("c", 3).unwrap();
|
|
builder.append::<Int32Type>("a", 4).unwrap();
|
|
builder.append_null::<Int32Type>("a").unwrap();
|
|
builder.append_null::<Int32Type>("a").unwrap();
|
|
builder.append::<Int32Type>("b", 7).unwrap();
|
|
let union4 = builder.build().unwrap();
|
|
|
|
test_equal(&union1, &union2, true);
|
|
test_equal(&union1, &union3, false);
|
|
test_equal(&union1, &union4, false);
|
|
}
|
|
|
|
#[test]
|
|
fn test_union_equal_sparse_slice() {
|
|
let mut builder = UnionBuilder::new_sparse();
|
|
builder.append::<Int32Type>("a", 1).unwrap();
|
|
builder.append::<Int32Type>("a", 2).unwrap();
|
|
builder.append::<Int32Type>("b", 3).unwrap();
|
|
let a1 = builder.build().unwrap();
|
|
|
|
let mut builder = UnionBuilder::new_sparse();
|
|
builder.append::<Int32Type>("a", 2).unwrap();
|
|
builder.append::<Int32Type>("b", 3).unwrap();
|
|
let a2 = builder.build().unwrap();
|
|
|
|
test_equal(&a1.slice(1, 2), &a2, true)
|
|
}
|
|
|
|
#[test]
|
|
fn test_boolean_slice() {
|
|
let array = BooleanArray::from(vec![true; 32]);
|
|
let slice = array.slice(4, 12);
|
|
assert_eq!(&slice, &slice);
|
|
|
|
let slice = array.slice(8, 12);
|
|
assert_eq!(&slice, &slice);
|
|
|
|
let slice = array.slice(8, 24);
|
|
assert_eq!(&slice, &slice);
|
|
}
|
|
|
|
#[test]
|
|
fn test_sliced_nullable_boolean_array() {
|
|
let a = BooleanArray::from(vec![None; 32]);
|
|
let b = BooleanArray::from(vec![true; 32]);
|
|
let slice_a = a.slice(1, 12);
|
|
let slice_b = b.slice(1, 12);
|
|
assert_ne!(&slice_a, &slice_b);
|
|
}
|
|
|
|
#[test]
|
|
fn list_array_non_zero_nulls() {
|
|
// Tests handling of list arrays with non-empty null ranges
|
|
let mut builder = ListBuilder::new(Int64Builder::with_capacity(10));
|
|
builder.values().append_value(1);
|
|
builder.values().append_value(2);
|
|
builder.values().append_value(3);
|
|
builder.append(true);
|
|
builder.append(false);
|
|
let array1 = builder.finish();
|
|
|
|
let mut builder = ListBuilder::new(Int64Builder::with_capacity(10));
|
|
builder.values().append_value(1);
|
|
builder.values().append_value(2);
|
|
builder.values().append_value(3);
|
|
builder.append(true);
|
|
builder.values().append_null();
|
|
builder.values().append_null();
|
|
builder.append(false);
|
|
let array2 = builder.finish();
|
|
|
|
assert_eq!(array1, array2);
|
|
}
|
|
|
|
#[test]
|
|
fn test_list_different_offsets() {
|
|
let a = ListArray::from_iter_primitive::<Int32Type, _, _>([
|
|
Some([Some(0), Some(0)]),
|
|
Some([Some(1), Some(2)]),
|
|
Some([None, None]),
|
|
]);
|
|
let b = ListArray::from_iter_primitive::<Int32Type, _, _>([
|
|
Some([Some(1), Some(2)]),
|
|
Some([None, None]),
|
|
Some([None, None]),
|
|
]);
|
|
let a_slice = a.slice(1, 2);
|
|
let b_slice = b.slice(0, 2);
|
|
assert_eq!(&a_slice, &b_slice);
|
|
}
|
|
|
|
fn make_struct(elements: Vec<Option<(Option<&'static str>, Option<i32>)>>) -> StructArray {
|
|
let mut builder = StructBuilder::new(
|
|
vec![
|
|
Field::new("f1", DataType::Utf8, true),
|
|
Field::new("f2", DataType::Int32, true),
|
|
],
|
|
vec![
|
|
Box::new(StringBuilder::new()),
|
|
Box::new(Int32Builder::new()),
|
|
],
|
|
);
|
|
|
|
for element in elements {
|
|
match element.and_then(|e| e.0) {
|
|
None => builder
|
|
.field_builder::<StringBuilder>(0)
|
|
.unwrap()
|
|
.append_null(),
|
|
Some(s) => builder
|
|
.field_builder::<StringBuilder>(0)
|
|
.unwrap()
|
|
.append_value(s),
|
|
};
|
|
|
|
builder
|
|
.field_builder::<Int32Builder>(1)
|
|
.unwrap()
|
|
.append_option(element.and_then(|e| e.1));
|
|
|
|
builder.append(element.is_some());
|
|
}
|
|
|
|
builder.finish()
|
|
}
|
|
|
|
#[test]
|
|
fn test_struct_equal_slice() {
|
|
let a = make_struct(vec![
|
|
None,
|
|
Some((Some("joe"), Some(1))),
|
|
Some((None, Some(2))),
|
|
Some((None, None)),
|
|
Some((Some("mark"), Some(4))),
|
|
Some((Some("doe"), Some(5))),
|
|
]);
|
|
let a = a.slice(1, 5);
|
|
let a = a.as_any().downcast_ref::<StructArray>().unwrap();
|
|
|
|
let b = make_struct(vec![
|
|
Some((Some("joe"), Some(1))),
|
|
Some((None, Some(2))),
|
|
Some((None, None)),
|
|
Some((Some("mark"), Some(4))),
|
|
Some((Some("doe"), Some(5))),
|
|
]);
|
|
assert_eq!(a, &b);
|
|
|
|
test_equal(&a, &b, true);
|
|
}
|
|
|
|
#[test]
|
|
fn test_list_excess_children_equal() {
|
|
let mut a = ListBuilder::new(FixedSizeBinaryBuilder::new(5));
|
|
a.values().append_value(b"11111").unwrap(); // Masked value
|
|
a.append_null();
|
|
a.values().append_value(b"22222").unwrap();
|
|
a.values().append_null();
|
|
a.append(true);
|
|
let a = a.finish();
|
|
|
|
let mut b = ListBuilder::new(FixedSizeBinaryBuilder::new(5));
|
|
b.append_null();
|
|
b.values().append_value(b"22222").unwrap();
|
|
b.values().append_null();
|
|
b.append(true);
|
|
let b = b.finish();
|
|
|
|
assert_eq!(a.value_offsets(), &[0, 1, 3]);
|
|
assert_eq!(b.value_offsets(), &[0, 0, 2]);
|
|
assert_eq!(a, b);
|
|
}
|