use rudb_common::{Error, Result, Value};
use rudb_kernels::{Comparison, Connective, cast, combine, compare, is_true};
use rudb_plan::{CompareOp, ConjunctionOp, Expr, ExprRef, Plan};
use rudb_vector::{Chunk, Selection, Vector};
use crate::schema::Schema;
pub fn evaluate(plan: &Plan, expr: ExprRef, schema: &Schema, chunk: &Chunk) -> Result<Vector> {
let ty = plan.expr_type(expr).clone();
match *plan.expr(expr) {
Expr::Column(binding) => {
let position = schema.position_of(binding).ok_or_else(|| {
Error::internal(format!(
"column #{}.{} is not in the schema this operator was given",
binding.table, binding.column
))
})?;
Ok(chunk.column(position)?.clone())
}
Expr::Constant(reference) => {
Ok(Vector::constant(ty, plan.value(reference).clone(), chunk.len()))
}
Expr::Cast { input, try_cast } => {
let inner = evaluate(plan, input, schema, chunk)?;
cast(&inner, &ty, try_cast)
}
Expr::Compare { op, left, right } => {
let left = evaluate(plan, left, schema, chunk)?;
let right = evaluate(plan, right, schema, chunk)?;
compare(comparison(op), &left, &right)
}
Expr::Conjunction { op, children } => {
let children = evaluate_all(plan, plan.expr_list(children), schema, chunk)?;
combine(connective(op), &children)
}
Expr::Function { name, args } => {
let args = evaluate_all(plan, plan.expr_list(args), schema, chunk)?;
rudb_kernels::call(plan.string(name), &args, &ty)
}
Expr::Aggregate { name, .. } => Err(Error::internal(format!(
"the {} aggregate was evaluated as an ordinary expression",
plan.string(name)
))),
Expr::Case { arms, otherwise } => {
let arms = plan.arm_list(arms).to_vec();
let mut answers = vec![Value::Null; chunk.len()];
let mut pending: Vec<usize> = (0..chunk.len()).collect();
for arm in arms {
if pending.is_empty() {
break;
}
let narrowed = narrow(chunk, &pending)?;
let flags = evaluate(plan, arm.when, schema, &narrowed)?;
let mut taken = Vec::new();
let mut still = Vec::new();
for (at, &row) in pending.iter().enumerate() {
if is_true(&flags.value_at(at)) {
taken.push((at, row));
} else {
still.push(row);
}
}
if !taken.is_empty() {
let positions: Vec<usize> = taken.iter().map(|&(at, _)| at).collect();
let matched = narrow(&narrowed, &positions)?;
let results = evaluate(plan, arm.then, schema, &matched)?;
for (slot, &(_, row)) in taken.iter().enumerate() {
answers[row] = results.value_at(slot);
}
}
pending = still;
}
if let Some(otherwise) = otherwise {
if !pending.is_empty() {
let narrowed = narrow(chunk, &pending)?;
let results = evaluate(plan, otherwise, schema, &narrowed)?;
for (slot, &row) in pending.iter().enumerate() {
answers[row] = results.value_at(slot);
}
}
}
Vector::from_values(ty, &answers)
}
}
}
pub fn evaluate_all(
plan: &Plan,
exprs: &[ExprRef],
schema: &Schema,
chunk: &Chunk,
) -> Result<Vec<Vector>> {
exprs.iter().map(|&expr| evaluate(plan, expr, schema, chunk)).collect()
}
fn narrow(chunk: &Chunk, rows: &[usize]) -> Result<Chunk> {
let mut selection = Selection::with_capacity(rows.len());
for &row in rows {
selection.push(row);
}
chunk.clone().select(&selection)
}
fn comparison(op: CompareOp) -> Comparison {
match op {
CompareOp::Equal => Comparison::Equal,
CompareOp::NotEqual => Comparison::NotEqual,
CompareOp::Less => Comparison::Less,
CompareOp::LessOrEqual => Comparison::LessOrEqual,
CompareOp::Greater => Comparison::Greater,
CompareOp::GreaterOrEqual => Comparison::GreaterOrEqual,
CompareOp::DistinctFrom => Comparison::DistinctFrom,
CompareOp::NotDistinctFrom => Comparison::NotDistinctFrom,
}
}
fn connective(op: ConjunctionOp) -> Connective {
match op {
ConjunctionOp::And => Connective::And,
ConjunctionOp::Or => Connective::Or,
}
}