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::LambdaParam(binding) => {
64 let position = schema.position_of(binding).ok_or_else(|| {
65 Error::internal(format!(
66 "lambda parameter @{}.{} is not in the schema its body was given",
67 binding.table, binding.column
68 ))
69 })?;
70 Ok(chunk.column(position)?.clone())
71 }
72 Expr::Lambda { .. } => {
73 Err(Error::internal("a lambda was evaluated outside the function that takes it"))
74 }
75 Expr::Constant(reference) => {
76 Ok(Vector::constant(ty, plan.value(reference).clone(), chunk.len()))
77 }
78 Expr::Cast { input, try_cast } => {
79 let inner = evaluate_in_time_zone(plan, input, schema, chunk, time_zone)?;
80 cast_in_time_zone(&inner, &ty, try_cast, Some(time_zone))
81 }
82 Expr::Compare { op, left, right } => {
83 let left = evaluate_in_time_zone(plan, left, schema, chunk, time_zone)?;
84 let right = evaluate_in_time_zone(plan, right, schema, chunk, time_zone)?;
85 compare(comparison(op), &left, &right)
86 }
87 Expr::Conjunction { op, children } => {
88 let children = evaluate_all_in_time_zone(
89 plan,
90 plan.expr_list(children),
91 schema,
92 chunk,
93 time_zone,
94 )?;
95 combine(connective(op), &children)
96 }
97 Expr::Function { name, args } => {
98 if let Some((lambda, inputs)) = crate::lambda::lambda_call(plan, args) {
99 let runner =
100 crate::lambda::Lambda::new(plan, plan.string(name), lambda, &inputs, schema)?;
101 let Expr::Lambda { body, .. } = *plan.expr(lambda) else {
102 return Err(Error::internal("a lambda call without a lambda"));
103 };
104 let inputs = evaluate_all_in_time_zone(plan, &inputs, schema, chunk, time_zone)?;
105 let inputs: Vec<&Vector> = inputs.iter().collect();
106 return runner
107 .run(&inputs, chunk, &mut |inner| {
108 evaluate_in_time_zone(plan, body, runner.schema(), inner, time_zone)
109 })
110 .map_err(|error| error.with_fallback_span(plan.expr_span(expr)));
111 }
112 let args =
113 evaluate_all_in_time_zone(plan, plan.expr_list(args), schema, chunk, time_zone)?;
114 rudb_kernels::call(plan.string(name), &args, &ty, Some(&|| written(plan, expr, schema)))
117 }
118 Expr::Aggregate { name, .. } => Err(Error::internal(format!(
119 "the {} aggregate was evaluated as an ordinary expression",
120 plan.string(name)
121 ))),
122 Expr::Window { name, .. } => Err(Error::internal(format!(
123 "the {} window function was evaluated as an ordinary expression",
124 plan.string(name)
125 ))),
126 Expr::Case { arms, otherwise } => {
127 let arms = plan.arm_list(arms).to_vec();
128 let mut answers = vec![Value::Null; chunk.len()];
129 let mut pending: Vec<usize> = (0..chunk.len()).collect();
130 for arm in arms {
131 if pending.is_empty() {
132 break;
133 }
134 let narrowed = narrow(chunk, &pending)?;
135 let flags = evaluate_in_time_zone(plan, arm.when, schema, &narrowed, time_zone)?;
136 let mut taken = Vec::new();
137 let mut still = Vec::new();
138 for (at, &row) in pending.iter().enumerate() {
142 if is_true(&flags.value_at(at)) {
143 taken.push((at, row));
144 } else {
145 still.push(row);
146 }
147 }
148 if !taken.is_empty() {
149 let positions: Vec<usize> = taken.iter().map(|&(at, _)| at).collect();
150 let matched = narrow(&narrowed, &positions)?;
151 let results =
152 evaluate_in_time_zone(plan, arm.then, schema, &matched, time_zone)?;
153 for (slot, &(_, row)) in taken.iter().enumerate() {
155 answers[row] = results.try_value_at(slot)?;
156 }
157 }
158 pending = still;
159 }
160 if let Some(otherwise) = otherwise {
161 if !pending.is_empty() {
162 let narrowed = narrow(chunk, &pending)?;
163 let results =
164 evaluate_in_time_zone(plan, otherwise, schema, &narrowed, time_zone)?;
165 for (slot, &row) in pending.iter().enumerate() {
167 answers[row] = results.try_value_at(slot)?;
168 }
169 }
170 }
171 Vector::from_values(ty, &answers)
172 }
173 };
174 result.map_err(|error| error.with_fallback_span(plan.expr_span(expr)))
175}
176
177pub fn evaluate_all(
183 plan: &Plan,
184 exprs: &[ExprRef],
185 schema: &Schema,
186 chunk: &Chunk,
187) -> Result<Vec<Vector>> {
188 evaluate_all_in_time_zone(plan, exprs, schema, chunk, SessionTimeZone::default())
189}
190
191pub(crate) fn evaluate_all_in_time_zone(
193 plan: &Plan,
194 exprs: &[ExprRef],
195 schema: &Schema,
196 chunk: &Chunk,
197 time_zone: SessionTimeZone,
198) -> Result<Vec<Vector>> {
199 exprs.iter().map(|&expr| evaluate_in_time_zone(plan, expr, schema, chunk, time_zone)).collect()
200}