1use rudb_common::{Error, Result, SessionTimeZone, Value};
24use rudb_kernels::{cast_in_time_zone, combine, compare, is_true};
25use rudb_plan::{Expr, ExprRef, Plan};
26use rudb_vector::{Chunk, Vector};
27
28use crate::prepared::{comparison, connective, narrow};
29use crate::schema::Schema;
30use crate::written::written;
31
32pub fn evaluate(plan: &Plan, expr: ExprRef, schema: &Schema, chunk: &Chunk) -> Result<Vector> {
41 evaluate_in_time_zone(plan, expr, schema, chunk, SessionTimeZone::default())
42}
43
44pub(crate) fn evaluate_in_time_zone(
46 plan: &Plan,
47 expr: ExprRef,
48 schema: &Schema,
49 chunk: &Chunk,
50 time_zone: SessionTimeZone,
51) -> Result<Vector> {
52 let ty = plan.expr_type(expr).clone();
53 let result = match *plan.expr(expr) {
54 Expr::Column(binding) => {
55 let position = schema.position_of(binding).ok_or_else(|| {
56 Error::internal(format!(
57 "column #{}.{} is not in the schema this operator was given",
58 binding.table, binding.column
59 ))
60 })?;
61 Ok(chunk.column(position)?.clone())
62 }
63 Expr::Constant(reference) => {
64 Ok(Vector::constant(ty, plan.value(reference).clone(), chunk.len()))
65 }
66 Expr::Cast { input, try_cast } => {
67 let inner = evaluate_in_time_zone(plan, input, schema, chunk, time_zone)?;
68 cast_in_time_zone(&inner, &ty, try_cast, Some(time_zone))
69 }
70 Expr::Compare { op, left, right } => {
71 let left = evaluate_in_time_zone(plan, left, schema, chunk, time_zone)?;
72 let right = evaluate_in_time_zone(plan, right, schema, chunk, time_zone)?;
73 compare(comparison(op), &left, &right)
74 }
75 Expr::Conjunction { op, children } => {
76 let children = evaluate_all_in_time_zone(
77 plan,
78 plan.expr_list(children),
79 schema,
80 chunk,
81 time_zone,
82 )?;
83 combine(connective(op), &children)
84 }
85 Expr::Function { name, args } => {
86 let args =
87 evaluate_all_in_time_zone(plan, plan.expr_list(args), schema, chunk, time_zone)?;
88 rudb_kernels::call(plan.string(name), &args, &ty, Some(&|| written(plan, expr, schema)))
91 }
92 Expr::Aggregate { name, .. } => Err(Error::internal(format!(
93 "the {} aggregate was evaluated as an ordinary expression",
94 plan.string(name)
95 ))),
96 Expr::Window { name, .. } => Err(Error::internal(format!(
97 "the {} window function was evaluated as an ordinary expression",
98 plan.string(name)
99 ))),
100 Expr::Case { arms, otherwise } => {
101 let arms = plan.arm_list(arms).to_vec();
102 let mut answers = vec![Value::Null; chunk.len()];
103 let mut pending: Vec<usize> = (0..chunk.len()).collect();
104 for arm in arms {
105 if pending.is_empty() {
106 break;
107 }
108 let narrowed = narrow(chunk, &pending)?;
109 let flags = evaluate_in_time_zone(plan, arm.when, schema, &narrowed, time_zone)?;
110 let mut taken = Vec::new();
111 let mut still = Vec::new();
112 for (at, &row) in pending.iter().enumerate() {
116 if is_true(&flags.value_at(at)) {
117 taken.push((at, row));
118 } else {
119 still.push(row);
120 }
121 }
122 if !taken.is_empty() {
123 let positions: Vec<usize> = taken.iter().map(|&(at, _)| at).collect();
124 let matched = narrow(&narrowed, &positions)?;
125 let results =
126 evaluate_in_time_zone(plan, arm.then, schema, &matched, time_zone)?;
127 for (slot, &(_, row)) in taken.iter().enumerate() {
129 answers[row] = results.try_value_at(slot)?;
130 }
131 }
132 pending = still;
133 }
134 if let Some(otherwise) = otherwise {
135 if !pending.is_empty() {
136 let narrowed = narrow(chunk, &pending)?;
137 let results =
138 evaluate_in_time_zone(plan, otherwise, schema, &narrowed, time_zone)?;
139 for (slot, &row) in pending.iter().enumerate() {
141 answers[row] = results.try_value_at(slot)?;
142 }
143 }
144 }
145 Vector::from_values(ty, &answers)
146 }
147 };
148 result.map_err(|error| error.with_fallback_span(plan.expr_span(expr)))
149}
150
151pub fn evaluate_all(
157 plan: &Plan,
158 exprs: &[ExprRef],
159 schema: &Schema,
160 chunk: &Chunk,
161) -> Result<Vec<Vector>> {
162 evaluate_all_in_time_zone(plan, exprs, schema, chunk, SessionTimeZone::default())
163}
164
165pub(crate) fn evaluate_all_in_time_zone(
167 plan: &Plan,
168 exprs: &[ExprRef],
169 schema: &Schema,
170 chunk: &Chunk,
171 time_zone: SessionTimeZone,
172) -> Result<Vec<Vector>> {
173 exprs.iter().map(|&expr| evaluate_in_time_zone(plan, expr, schema, chunk, time_zone)).collect()
174}