blob: 4c81e136aa8c74abd2a5d83cf91f0db18f747f62 [file]
// Copyright 2022 The Blaze Authors
//
// Licensed 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::sync::Arc;
use arrow::{array::ArrayRef, record_batch::RecordBatch};
use datafusion::common::{Result, ScalarValue};
use datafusion_ext_commons::slim_bytes::SlimBytes;
use crate::{
agg::{
acc::{create_acc_from_initial_value, OwnedAccumStateRow},
Agg,
},
window::{window_context::WindowContext, WindowFunctionProcessor},
};
pub struct AggProcessor {
cur_partition: SlimBytes,
agg: Arc<dyn Agg>,
acc_init: OwnedAccumStateRow,
acc: OwnedAccumStateRow,
}
impl AggProcessor {
pub fn try_new(agg: Arc<dyn Agg>) -> Result<Self> {
let (acc, accum_state_val_addrs) = create_acc_from_initial_value(agg.accums_initial())?;
let mut agg = agg;
unsafe {
// safety - accum_state_val_addrs is guaranteed not to be used at this time
Arc::get_mut_unchecked(&mut agg).set_accum_state_val_addrs(&accum_state_val_addrs);
}
Ok(Self {
cur_partition: Default::default(),
agg,
acc_init: acc.clone(),
acc,
})
}
}
impl WindowFunctionProcessor for AggProcessor {
fn process_batch(&mut self, context: &WindowContext, batch: &RecordBatch) -> Result<ArrayRef> {
let partition_rows = context.get_partition_rows(batch)?;
let mut output = vec![];
let children_cols: Vec<ArrayRef> = self
.agg
.exprs()
.iter()
.map(|expr| {
expr.evaluate(batch)
.and_then(|v| v.into_array(batch.num_rows()))
})
.collect::<Result<_>>()?;
for row_idx in 0..batch.num_rows() {
let same_partition = !context.has_partition() || {
let partition_row = partition_rows.row(row_idx);
if partition_row.as_ref() != self.cur_partition.as_ref() {
self.cur_partition = partition_row.as_ref().into();
false
} else {
true
}
};
if !same_partition {
self.acc = self.acc_init.clone();
}
self.agg
.partial_update(&mut self.acc.as_mut(), &children_cols, row_idx)
.map_err(|err| err.context("window: agg_processor partial_update() error"))?;
output.push(self.agg.final_merge(&mut self.acc.clone().as_mut())?);
}
Ok(Arc::new(ScalarValue::iter_to_array(output.into_iter())?))
}
fn process_batch_without_partitions(
&mut self,
_: &WindowContext,
batch: &RecordBatch,
) -> Result<ArrayRef> {
let mut output = vec![];
let children_cols: Vec<ArrayRef> = self
.agg
.exprs()
.iter()
.map(|expr| {
expr.evaluate(batch)
.and_then(|v| v.into_array(batch.num_rows()))
})
.collect::<Result<_>>()?;
for row_idx in 0..batch.num_rows() {
self.agg
.partial_update(&mut self.acc.as_mut(), &children_cols, row_idx)
.map_err(|err| err.context("window: agg_processor partial_update() error"))?;
output.push(self.agg.final_merge(&mut self.acc.clone().as_mut())?);
}
Ok(Arc::new(ScalarValue::iter_to_array(output.into_iter())?))
}
}