use glaredb_error::Result;
use super::PhysicalScalarExpression;
use super::evaluator::ExpressionEvaluator;
use crate::arrays::array::selection::Selection;
use crate::arrays::batch::Batch;
use crate::arrays::datatype::DataType;
use crate::arrays::executor::scalar::UnaryExecutor;
use crate::expr::conjunction_expr::ConjunctionOperator;
#[derive(Debug)]
pub struct SelectionEvaluator {
pub(crate) selection: Vec<usize>,
pub(crate) selection_sec: Vec<usize>,
pub(crate) output: Batch,
pub(crate) evaluator: ExpressionEvaluator,
}
impl SelectionEvaluator {
pub fn try_new(
expression: impl Into<PhysicalScalarExpression>,
batch_size: usize,
) -> Result<Self> {
let evaluator = ExpressionEvaluator::try_new([expression.into()], batch_size)?;
let output = Batch::new([DataType::boolean()], batch_size)?;
let selection = Vec::with_capacity(batch_size);
let selection_sec = Vec::with_capacity(batch_size);
Ok(SelectionEvaluator {
selection,
selection_sec,
output,
evaluator,
})
}
pub fn selection(&self) -> &[usize] {
&self.selection
}
pub fn select(&mut self, input: &mut Batch) -> Result<&[usize]> {
debug_assert_eq!(1, self.evaluator.num_expressions());
debug_assert_eq!(1, self.output.arrays.len());
debug_assert_eq!(&DataType::boolean(), self.output.arrays[0].datatype());
let (exprs, states) = self.evaluator.eval_parts_mut();
match &exprs[0] {
PhysicalScalarExpression::Conjunction(conj) if conj.op == ConjunctionOperator::And => {
self.selection.clear();
self.selection_sec.clear();
let state = &mut states[0];
self.selection.extend(input.selection());
for (expr_idx, expr) in conj.expr.inputs.iter().enumerate() {
self.output.reset_for_write()?;
let child_state = &mut state.inputs[expr_idx];
child_state.reset_for_write()?;
ExpressionEvaluator::eval_expression(
expr,
input,
child_state,
Selection::slice(&self.selection),
&mut self.output.arrays[0],
)?;
self.selection_sec.clear();
UnaryExecutor::select(
&self.output.arrays[0],
0..self.selection.len(),
|local_idx| {
let row = self.selection[local_idx];
self.selection_sec.push(row);
},
|_| {
},
)?;
std::mem::swap(&mut self.selection, &mut self.selection_sec);
if self.selection.is_empty() {
break;
}
}
Ok(&self.selection)
}
_ => {
self.selection.clear();
self.output.reset_for_write()?;
self.evaluator
.eval_batch(input, input.selection(), &mut self.output)?;
UnaryExecutor::select(
&self.output.arrays[0],
0..input.num_rows(),
|idx| self.selection.push(idx),
|_| {}, )?;
Ok(&self.selection)
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::expr::physical::column_expr::PhysicalColumnExpr;
use crate::functions::scalar::builtin::debug::FUNCTION_SET_DEBUG_ERROR_ON_EXECUTE;
use crate::logical::binder::table_list::TableList;
use crate::testutil::exprs::plan_scalar;
use crate::{expr, generate_batch};
#[test]
fn select_simple() {
let mut evaluator =
SelectionEvaluator::try_new(PhysicalColumnExpr::new(0, DataType::boolean()), 1024)
.unwrap();
let mut input = generate_batch!([true, false, true, true], [8, 9, 7, 6]);
let selection = evaluator.select(&mut input).unwrap();
assert_eq!(&[0, 2, 3], selection);
let mut input = generate_batch!([true, false, false, false], [2, 2, 2, 2]);
let selection = evaluator.select(&mut input).unwrap();
assert_eq!(&[0], selection);
}
#[test]
fn select_with_null() {
let mut evaluator =
SelectionEvaluator::try_new(PhysicalColumnExpr::new(0, DataType::boolean()), 1024)
.unwrap();
let mut input = generate_batch!([Some(true), Some(false), None, Some(true)], [8, 9, 7, 6]);
let selection = evaluator.select(&mut input).unwrap();
assert_eq!(&[0, 3], selection);
}
#[test]
fn select_and_short_circuit() {
let mut list = TableList::empty();
let t0 = list
.push_table(None, [DataType::boolean(), DataType::int32()], ["c1", "c2"])
.unwrap();
let expr = plan_scalar(
&list,
expr::and([
expr::eq(expr::column((t0, 0), DataType::boolean()), expr::lit(true))
.unwrap()
.into(),
expr::gt(expr::column((t0, 1), DataType::int32()), expr::lit(4))
.unwrap()
.into(),
])
.unwrap(),
);
let mut evaluator = SelectionEvaluator::try_new(expr, 16).unwrap();
let mut input = generate_batch!([true, false, true, true, false, true], [5, 5, 1, 6, 2, 8]);
let selection = evaluator.select(&mut input).unwrap();
let expected = [0, 3, 5];
assert_eq!(&expected, selection);
}
#[test]
fn select_and_short_circuit_no_eval_last() {
let mut list = TableList::empty();
let t0 = list
.push_table(None, [DataType::boolean(), DataType::int32()], ["c1", "c2"])
.unwrap();
let expr = plan_scalar(
&list,
expr::and([
expr::eq(expr::column((t0, 0), DataType::boolean()), expr::lit(true))
.unwrap()
.into(),
expr::gt(expr::column((t0, 1), DataType::int32()), expr::lit(4))
.unwrap()
.into(),
expr::eq(
expr::scalar_function(&FUNCTION_SET_DEBUG_ERROR_ON_EXECUTE, Vec::new())
.unwrap(),
expr::lit(3),
)
.unwrap()
.into(),
])
.unwrap(),
);
let mut evaluator = SelectionEvaluator::try_new(expr, 16).unwrap();
let mut input = generate_batch!([true, false, true, true, false, true], [4, 5, 1, 2, 2, 1]);
let selection = evaluator.select(&mut input).unwrap();
assert!(selection.is_empty());
}
}