blob: 5137ee263f6821f3ad692102ab1f70040ed47bd4 [file]
// 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.
//! Array expressions
use std::sync::Arc;
use arrow::{
array::{Array, ArrayRef, ListArray, MutableArrayData, make_array},
buffer::{NullBuffer, OffsetBuffer, ScalarBuffer},
datatypes::{DataType, Field},
};
use datafusion::{
common::{Result, ScalarValue},
logical_expr::ColumnarValue,
};
use datafusion_ext_commons::{
df_execution_err, downcast_any, scalar_value::compacted_scalar_value_from_array,
};
pub fn array_reverse(args: &[ColumnarValue]) -> Result<ColumnarValue> {
if args.len() != 1 {
return df_execution_err!("array_reverse requires exactly 1 argument");
}
match &args[0] {
ColumnarValue::Array(array) => Ok(ColumnarValue::Array(reverse_list_array(
downcast_any!(array, ListArray)?,
)?)),
ColumnarValue::Scalar(scalar) if scalar.is_null() => {
Ok(ColumnarValue::Scalar(scalar.clone()))
}
ColumnarValue::Scalar(scalar) => match scalar.data_type() {
DataType::List(_) => {
let array = scalar.to_array()?;
let reversed = reverse_list_array(downcast_any!(&array, ListArray)?)?;
Ok(ColumnarValue::Scalar(ScalarValue::try_from_array(
&reversed, 0,
)?))
}
data_type => df_execution_err!("array_reverse only supports list, got {data_type:?}"),
},
}
}
fn reverse_list_array(array: &ListArray) -> Result<ArrayRef> {
let DataType::List(field) = array.data_type() else {
return df_execution_err!(
"array_reverse only supports list, got {:?}",
array.data_type()
);
};
let mut values = Vec::with_capacity(array.len());
for row_idx in 0..array.len() {
if array.is_null(row_idx) {
values.push(ScalarValue::List(Arc::new(ListArray::new_null(
field.clone(),
1,
))));
} else {
let row = array.value(row_idx);
let mut reversed = Vec::with_capacity(row.len());
for value_idx in (0..row.len()).rev() {
reversed.push(compacted_scalar_value_from_array(&row, value_idx)?);
}
values.push(ScalarValue::List(ScalarValue::new_list(
&reversed,
field.data_type(),
field.is_nullable(),
)));
}
}
ScalarValue::iter_to_array(values)
}
fn as_list_array(array: &ArrayRef) -> Result<ListArray> {
downcast_any!(array, ListArray).cloned()
}
fn columnar_value_to_list_array(arg: &ColumnarValue) -> Result<ListArray> {
match arg {
ColumnarValue::Array(array) if matches!(array.data_type(), DataType::Null) => {
Ok(ListArray::new_null(
Arc::new(Field::new_list_field(DataType::Null, true)),
array.len(),
))
}
ColumnarValue::Array(array) => as_list_array(array),
ColumnarValue::Scalar(scalar) if scalar.is_null() => {
let list_field = match scalar.data_type() {
DataType::List(field) => field,
_ => Arc::new(Field::new_list_field(DataType::Null, true)),
};
Ok(ListArray::new_null(list_field, 1))
}
ColumnarValue::Scalar(scalar) => {
let array = scalar.to_array()?;
as_list_array(&array)
}
}
}
/// Flatten an array of arrays into a single array.
pub fn array_flatten(args: &[ColumnarValue]) -> Result<ColumnarValue> {
if args.len() != 1 {
df_execution_err!("array_flatten expects one argument, got {}", args.len())?;
}
let outer = columnar_value_to_list_array(&args[0])?;
let inner = as_list_array(&outer.values())?;
let inner_values = inner.values();
let inner_values_data = inner_values.to_data();
let mut mutable = MutableArrayData::new(vec![&inner_values_data], true, inner_values.len());
let mut offsets = Vec::with_capacity(outer.len() + 1);
let mut valids = Vec::with_capacity(outer.len());
let mut offset = 0i32;
offsets.push(offset);
for row_idx in 0..outer.len() {
if outer.is_null(row_idx) {
valids.push(false);
offsets.push(offset);
continue;
}
let outer_start = outer.value_offsets()[row_idx] as usize;
let outer_end = outer.value_offsets()[row_idx + 1] as usize;
let row_valid = (outer_start..outer_end).all(|inner_idx| inner.is_valid(inner_idx));
valids.push(row_valid);
if row_valid {
let mut row_len = 0i32;
for inner_idx in outer_start..outer_end {
let inner_start = inner.value_offsets()[inner_idx] as usize;
let inner_end = inner.value_offsets()[inner_idx + 1] as usize;
mutable.extend(0, inner_start, inner_end);
row_len += (inner_end - inner_start) as i32;
}
offset += row_len;
}
offsets.push(offset);
}
let values = make_array(mutable.freeze());
let field = Arc::new(Field::new_list_field(values.data_type().clone(), true));
Ok(ColumnarValue::Array(Arc::new(ListArray::try_new(
field,
OffsetBuffer::new(ScalarBuffer::from(offsets)),
values,
Some(NullBuffer::from(valids)),
)?)))
}
#[cfg(test)]
mod test {
use std::{error::Error, sync::Arc};
use arrow::{
array::{ArrayRef, ListArray},
buffer::{NullBuffer, OffsetBuffer, ScalarBuffer},
datatypes::{Field, Int32Type},
};
use datafusion::common::ScalarValue;
use super::*;
#[test]
fn test_array_reverse_int() -> Result<()> {
let input: ArrayRef = Arc::new(ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
Some(vec![Some(1), None, Some(3)]),
Some(vec![Some(4), Some(5)]),
Some(vec![]),
None,
]));
let result = array_reverse(&[ColumnarValue::Array(input)])?.into_array(4)?;
let expected: ArrayRef = Arc::new(ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
Some(vec![Some(3), None, Some(1)]),
Some(vec![Some(5), Some(4)]),
Some(vec![]),
None,
]));
assert_eq!(&result, &expected);
Ok(())
}
#[test]
fn test_array_reverse_scalar() -> Result<()> {
let input = ScalarValue::List(ScalarValue::new_list(
&[
ScalarValue::from(1),
ScalarValue::from(2),
ScalarValue::from(3),
],
&DataType::Int32,
true,
));
let result = array_reverse(&[ColumnarValue::Scalar(input)])?.into_array(1)?;
let expected = ScalarValue::List(ScalarValue::new_list(
&[
ScalarValue::from(3),
ScalarValue::from(2),
ScalarValue::from(1),
],
&DataType::Int32,
true,
))
.to_array()?;
assert_eq!(&result, &expected);
Ok(())
}
#[test]
fn test_array_flatten_int() -> std::result::Result<(), Box<dyn Error>> {
let inner = ListArray::from_iter_primitive::<Int32Type, _, _>(vec![
Some(vec![Some(1), None]),
Some(vec![Some(3)]),
Some(vec![]),
Some(vec![Some(4), Some(5)]),
Some(vec![Some(6)]),
None,
]);
let inner: ArrayRef = Arc::new(inner);
let input: ArrayRef = Arc::new(ListArray::try_new(
Arc::new(Field::new_list_field(inner.data_type().clone(), true)),
OffsetBuffer::new(ScalarBuffer::from(vec![0, 2, 4, 6, 6, 6])),
inner,
Some(NullBuffer::from(vec![true, true, true, true, false])),
)?);
let result = array_flatten(&[ColumnarValue::Array(input)])?.into_array(5)?;
let expected = vec![
Some(vec![Some(1), None, Some(3)]),
Some(vec![Some(4), Some(5)]),
None,
Some(vec![]),
None,
];
let expected: ArrayRef =
Arc::new(ListArray::from_iter_primitive::<Int32Type, _, _>(expected));
assert_eq!(&result, &expected);
Ok(())
}
}