blob: 6e185791100b1bf2f9a08f75dad46f98684feab9 [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.
use std::{
any::Any,
fmt::{Debug, Formatter},
sync::Arc,
};
use arrow::{array::*, datatypes::*};
use datafusion::{common::Result, physical_expr::PhysicalExprRef};
use datafusion_ext_commons::{downcast_any, scalar_value::compacted_scalar_value_from_array};
use crate::{
agg::{
Agg,
acc::{
AccBooleanColumn, AccBytes, AccBytesColumn, AccColumnRef, AccPrimColumn,
AccScalarValueColumn, create_acc_generic_column,
},
agg::IdxSelection,
},
idx_for_zipped,
};
pub struct AggFirstIgnoresNull {
child: PhysicalExprRef,
data_type: DataType,
acc_array_data_types: Vec<DataType>,
}
impl AggFirstIgnoresNull {
pub fn try_new(child: PhysicalExprRef, data_type: DataType) -> Result<Self> {
let acc_array_data_types = vec![data_type.clone()];
Ok(Self {
child,
data_type,
acc_array_data_types,
})
}
}
impl Debug for AggFirstIgnoresNull {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "FirstIgnoresNull({:?})", self.child)
}
}
impl Agg for AggFirstIgnoresNull {
fn as_any(&self) -> &dyn Any {
self
}
fn exprs(&self) -> Vec<PhysicalExprRef> {
vec![self.child.clone()]
}
fn with_new_exprs(&self, exprs: Vec<PhysicalExprRef>) -> Result<Arc<dyn Agg>> {
Ok(Arc::new(Self::try_new(
exprs[0].clone(),
self.data_type.clone(),
)?))
}
fn data_type(&self) -> &DataType {
&self.data_type
}
fn nullable(&self) -> bool {
true
}
fn create_acc_column(&self, num_rows: usize) -> AccColumnRef {
create_acc_generic_column(self.data_type.clone(), num_rows)
}
fn acc_array_data_types(&self) -> &[DataType] {
&self.acc_array_data_types
}
fn partial_update(
&self,
accs: &mut AccColumnRef,
acc_idx: IdxSelection<'_>,
partial_args: &[ArrayRef],
partial_arg_idx: IdxSelection<'_>,
) -> Result<()> {
let partial_arg = &partial_args[0];
accs.ensure_size(acc_idx);
macro_rules! handle_bytes {
($array:expr) => {{
let accs = downcast_any!(accs, mut AccBytesColumn)?;
let partial_arg = $array;
idx_for_zipped! {
((acc_idx, partial_arg_idx) in (acc_idx, partial_arg_idx)) => {
if accs.value(acc_idx).is_none() && partial_arg.is_valid(partial_arg_idx) {
accs.set_value(acc_idx, Some(AccBytes::from_slice_copy(partial_arg.value(partial_arg_idx).as_ref())));
}
}
}
}}
}
downcast_primitive_array! {
partial_arg => {
if let Ok(accs) = downcast_any!(accs, mut AccPrimColumn<_>) {
idx_for_zipped! {
((acc_idx, partial_arg_idx) in (acc_idx, partial_arg_idx)) => {
if accs.value(acc_idx).is_none() && partial_arg.is_valid(partial_arg_idx) {
accs.set_value(acc_idx, Some(partial_arg.value(partial_arg_idx)));
}
}
}
}
}
DataType::Boolean => {
let accs = downcast_any!(accs, mut AccBooleanColumn)?;
let partial_arg = downcast_any!(partial_arg, BooleanArray)?;
idx_for_zipped! {
((acc_idx, partial_arg_idx) in (acc_idx, partial_arg_idx)) => {
if accs.value(acc_idx).is_none() && partial_arg.is_valid(partial_arg_idx) {
accs.set_value(acc_idx, Some(partial_arg.value(partial_arg_idx)));
}
}
}
}
DataType::Utf8 => handle_bytes!(downcast_any!(partial_arg, StringArray)?),
DataType::Binary => handle_bytes!(downcast_any!(partial_arg, BinaryArray)?),
_other => {
let accs = downcast_any!(accs, mut AccScalarValueColumn)?;
idx_for_zipped! {
((acc_idx, partial_arg_idx) in (acc_idx, partial_arg_idx)) => {
if accs.value(acc_idx).is_null() && partial_arg.is_valid(partial_arg_idx) {
accs.set_value(acc_idx, compacted_scalar_value_from_array(partial_arg, partial_arg_idx)?);
}
}
}
}
}
Ok(())
}
fn partial_merge(
&self,
accs: &mut AccColumnRef,
acc_idx: IdxSelection<'_>,
merging_accs: &mut AccColumnRef,
merging_acc_idx: IdxSelection<'_>,
) -> Result<()> {
accs.ensure_size(acc_idx);
// primitive types
macro_rules! handle_primitive {
($ty:ty) => {{
type TNative = <$ty as ArrowPrimitiveType>::Native;
let accs = downcast_any!(accs, mut AccPrimColumn<TNative>)?;
let merging_accs = downcast_any!(merging_accs, mut AccPrimColumn<_>)?;
idx_for_zipped! {
((acc_idx, merging_acc_idx) in (acc_idx, merging_acc_idx)) => {
if accs.value(acc_idx).is_none() && merging_accs.value(merging_acc_idx).is_some() {
accs.set_value(acc_idx, merging_accs.value(merging_acc_idx));
}
}
}
}}
}
macro_rules! handle_boolean {
() => {{
let accs = downcast_any!(accs, mut AccBooleanColumn)?;
let merging_accs = downcast_any!(merging_accs, mut AccBooleanColumn)?;
idx_for_zipped! {
((acc_idx, merging_acc_idx) in (acc_idx, merging_acc_idx)) => {
if accs.value(acc_idx).is_none() && merging_accs.value(merging_acc_idx).is_some() {
accs.set_value(acc_idx, merging_accs.value(merging_acc_idx));
}
}
}
}};
}
macro_rules! handle_bytes {
() => {{
let accs = downcast_any!(accs, mut AccBytesColumn)?;
let merging_accs = downcast_any!(merging_accs, mut AccBytesColumn)?;
idx_for_zipped! {
((acc_idx, merging_acc_idx) in (acc_idx, merging_acc_idx)) => {
if accs.value(acc_idx).is_none() && merging_accs.value(merging_acc_idx).is_some() {
accs.set_value(acc_idx, merging_accs.take_value(merging_acc_idx));
}
}
}
}};
}
downcast_primitive! {
(&self.data_type) => (handle_primitive),
DataType::Boolean => handle_boolean!(),
DataType::Utf8 | DataType::Binary => handle_bytes!(),
DataType::Null => {}
_ => {
let accs = downcast_any!(accs, mut AccScalarValueColumn)?;
let merging_accs = downcast_any!(merging_accs, mut AccScalarValueColumn)?;
idx_for_zipped! {
((acc_idx, merging_acc_idx) in (acc_idx, merging_acc_idx)) => {
if accs.value(acc_idx).is_null() && !merging_accs.value(merging_acc_idx).is_null() {
accs.set_value(acc_idx, merging_accs.take_value(merging_acc_idx));
}
}
}
}
}
Ok(())
}
fn final_merge(&self, accs: &mut AccColumnRef, acc_idx: IdxSelection<'_>) -> Result<ArrayRef> {
Ok(accs.freeze_to_arrays(acc_idx)?[0].clone())
}
}