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::{attempt, 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 ("try", [only]) = (plan.string(name), plan.expr_list(args)) {
99 let only = *only;
100 return attempt(chunk, &ty, |rows| {
101 evaluate_in_time_zone(plan, only, schema, rows, time_zone)
102 });
103 }
104 if let Some((lambda, inputs)) = crate::lambda::lambda_call(plan, args) {
105 let runner =
106 crate::lambda::Lambda::new(plan, plan.string(name), lambda, &inputs, schema)?;
107 let Expr::Lambda { body, .. } = *plan.expr(lambda) else {
108 return Err(Error::internal("a lambda call without a lambda"));
109 };
110 let inputs = evaluate_all_in_time_zone(plan, &inputs, schema, chunk, time_zone)?;
111 let inputs: Vec<&Vector> = inputs.iter().collect();
112 return runner
113 .run(&inputs, chunk, &mut |inner| {
114 evaluate_in_time_zone(plan, body, runner.schema(), inner, time_zone)
115 })
116 .map_err(|error| error.with_fallback_span(plan.expr_span(expr)));
117 }
118 if plan.string(name) == "random" && plan.expr_list(args).is_empty() {
120 return rudb_kernels::random(chunk.len());
121 }
122 let args =
123 evaluate_all_in_time_zone(plan, plan.expr_list(args), schema, chunk, time_zone)?;
124 rudb_kernels::call(plan.string(name), &args, &ty, Some(&|| written(plan, expr, schema)))
127 }
128 Expr::Aggregate { name, .. } => Err(Error::internal(format!(
129 "the {} aggregate was evaluated as an ordinary expression",
130 plan.string(name)
131 ))),
132 Expr::Window { name, .. } => Err(Error::internal(format!(
133 "the {} window function was evaluated as an ordinary expression",
134 plan.string(name)
135 ))),
136 Expr::Case { arms, otherwise } => {
137 let arms = plan.arm_list(arms).to_vec();
138 let mut answers = vec![Value::Null; chunk.len()];
139 let mut pending: Vec<usize> = (0..chunk.len()).collect();
140 for arm in arms {
141 if pending.is_empty() {
142 break;
143 }
144 let narrowed = narrow(chunk, &pending)?;
145 let flags = evaluate_in_time_zone(plan, arm.when, schema, &narrowed, time_zone)?;
146 let mut taken = Vec::new();
147 let mut still = Vec::new();
148 for (at, &row) in pending.iter().enumerate() {
152 if is_true(&flags.value_at(at)) {
153 taken.push((at, row));
154 } else {
155 still.push(row);
156 }
157 }
158 if !taken.is_empty() {
159 let positions: Vec<usize> = taken.iter().map(|&(at, _)| at).collect();
160 let matched = narrow(&narrowed, &positions)?;
161 let results =
162 evaluate_in_time_zone(plan, arm.then, schema, &matched, time_zone)?;
163 for (slot, &(_, row)) in taken.iter().enumerate() {
165 answers[row] = results.try_value_at(slot)?;
166 }
167 }
168 pending = still;
169 }
170 if let Some(otherwise) = otherwise
171 && !pending.is_empty()
172 {
173 let narrowed = narrow(chunk, &pending)?;
174 let results = evaluate_in_time_zone(plan, otherwise, schema, &narrowed, time_zone)?;
175 for (slot, &row) in pending.iter().enumerate() {
177 answers[row] = results.try_value_at(slot)?;
178 }
179 }
180 Vector::from_values(ty, &answers)
181 }
182 };
183 result.map_err(|error| error.with_fallback_span(plan.expr_span(expr)))
184}
185
186pub fn evaluate_all(
192 plan: &Plan,
193 exprs: &[ExprRef],
194 schema: &Schema,
195 chunk: &Chunk,
196) -> Result<Vec<Vector>> {
197 evaluate_all_in_time_zone(plan, exprs, schema, chunk, SessionTimeZone::default())
198}
199
200pub(crate) fn evaluate_all_in_time_zone(
202 plan: &Plan,
203 exprs: &[ExprRef],
204 schema: &Schema,
205 chunk: &Chunk,
206 time_zone: SessionTimeZone,
207) -> Result<Vec<Vector>> {
208 exprs.iter().map(|&expr| evaluate_in_time_zone(plan, expr, schema, chunk, time_zone)).collect()
209}