use rudb_common::{Error, Result, Value};
use rudb_kernels::{cast, combine, compare, is_true};
use rudb_plan::{Expr, ExprRef, Plan};
use rudb_vector::{Chunk, Vector};
use crate::prepared::{comparison, connective, narrow};
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()
}