1use akar_common::arrow_vector::{ArrowVector, VectorAccess};
15use akar_common::error::ProcessorError;
16use akar_common::types::{PhysicalTypeID, Value};
17use akar_common::vector::{DataChunk, ValueVector};
18use akar_function::registry::{FunctionRegistry, ScalarFunction};
19use akar_function::scalar::evaluate_scalar;
20use akar_parser::ast::{BinaryOp, Constant, Expression, Query, UnaryOp};
21use arrow::array::ArrayRef;
22use std::sync::{Arc, Mutex};
23
24pub type SubqueryFn = Arc<dyn Fn(&Query) -> Result<Vec<DataChunk>, ProcessorError> + Send + Sync>;
25pub type SequenceFn = Arc<dyn Fn(&str, bool) -> Result<Value, ProcessorError> + Send + Sync>;
26
27impl std::fmt::Debug for ExpressionEvaluator {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 f.debug_struct("ExpressionEvaluator").finish()
31 }
32}
33
34pub struct ExpressionEvaluator {
35 registry: Arc<Mutex<FunctionRegistry>>,
36 pub subquery_fn: Option<SubqueryFn>,
39 pub sequence_fn: Option<SequenceFn>,
42}
43
44impl ExpressionEvaluator {
45 pub fn new(registry: Arc<Mutex<FunctionRegistry>>) -> Self {
46 Self {
47 registry,
48 subquery_fn: None,
49 sequence_fn: None,
50 }
51 }
52
53 pub fn with_subquery_fn(mut self, f: SubqueryFn) -> Self {
55 self.subquery_fn = Some(f);
56 self
57 }
58
59 pub fn with_sequence_fn(mut self, f: SequenceFn) -> Self {
61 self.sequence_fn = Some(f);
62 self
63 }
64
65 fn evaluate_subquery(&self, query: &Query) -> Result<Vec<DataChunk>, ProcessorError> {
67 if let Some(ref f) = self.subquery_fn {
68 f(query)
69 } else {
70 Err("No subquery executor configured".into())
71 }
72 }
73
74 pub fn evaluate_to_arrow(&self, expr: &Expression, chunk: &DataChunk) -> Result<ArrowVector, ProcessorError> {
78 self.evaluate_arrow(expr, chunk)
79 }
80
81 pub fn evaluate(&self, expr: &Expression, chunk: &DataChunk) -> Result<ValueVector, ProcessorError> {
83 match expr {
84 Expression::Constant(c) => self.evaluate_constant(c, chunk.size),
85 Expression::Variable(name) => self.evaluate_variable(name, chunk),
86 Expression::PropertyAccess(obj, prop) => self.evaluate_property_access(obj, prop, chunk),
87 Expression::FunctionCall(name, args) => {
88 let refs: Vec<&Expression> = args.iter().collect();
89 self.evaluate_function_call(name, &refs, chunk)
90 }
91 Expression::BinaryOp(op, left, right) => self.evaluate_binary_op(op, left, right, chunk),
92 Expression::UnaryOp(op, inner) => self.evaluate_unary_op(op, inner, chunk),
93 Expression::List(items) => self.evaluate_list_literal(items, chunk),
94 Expression::Map(items) => self.evaluate_map_literal(items, chunk),
95 Expression::Parameter(_) => {
96 let mut v = ValueVector::new(akar_common::types::PhysicalTypeID::Int64, chunk.size);
99 v.resize(chunk.size);
100 for i in 0..chunk.size {
101 v.set_null(i, true);
102 }
103 Ok(v)
104 }
105 Expression::ExistsSubquery(query) => {
106 let result = self.evaluate_subquery(query)?;
110 let exists = !result.is_empty() && result.iter().any(|c| c.size > 0);
111 let mut v = ValueVector::new(akar_common::types::PhysicalTypeID::Bool, chunk.size);
112 v.resize(chunk.size);
113 for i in 0..chunk.size {
114 store_value_in_vector_simple(&mut v, i, &Value::Bool(exists))?;
115 }
116 Ok(v)
117 }
118 Expression::Case(case_expr) => self.evaluate_case(case_expr, chunk),
119 Expression::Star => {
120 Err("STAR expression should be expanded by the binder before reaching the evaluator".into())
121 }
122 Expression::ListPredicate {
123 quantifier,
124 list,
125 var_name,
126 predicate,
127 } => self.evaluate_list_predicate(quantifier, list, var_name, predicate, chunk),
128 Expression::Lambda { .. } => {
129 Err("Lambda expression should only appear as argument to list_transform/filter/reduce".into())
130 }
131 }
132 }
133
134 pub fn evaluate_arrow(&self, expr: &Expression, chunk: &DataChunk) -> Result<ArrowVector, ProcessorError> {
140 match expr {
141 Expression::Constant(c) => self.evaluate_arrow_constant(c, chunk.size),
142 Expression::Variable(name) => self.evaluate_arrow_variable(name, chunk),
143 Expression::PropertyAccess(obj, prop) => self.evaluate_arrow_property_access(obj, prop, chunk),
144 Expression::FunctionCall(name, args) => {
145 let refs: Vec<&Expression> = args.iter().collect();
146 self.evaluate_arrow_function_call(name, &refs, chunk)
147 }
148 Expression::BinaryOp(op, left, right) => self.evaluate_arrow_binary_op(op, left, right, chunk),
149 Expression::UnaryOp(op, inner) => self.evaluate_arrow_unary_op(op, inner, chunk),
150 _ => {
152 let legacy = self.evaluate(expr, chunk)?;
153 Ok(ArrowVector::from_legacy(&legacy))
154 }
155 }
156 }
157
158 fn evaluate_arrow_constant(&self, c: &Constant, size: usize) -> Result<ArrowVector, ProcessorError> {
160 match c {
161 Constant::Null => {
162 let mut builder = arrow::array::Int64Builder::with_capacity(size);
163 builder.append_nulls(size);
164 Ok(ArrowVector::new(Arc::new(builder.finish()), PhysicalTypeID::Int64))
165 }
166 Constant::Bool(b) => {
167 let mut builder = arrow::array::BooleanBuilder::with_capacity(size);
168 for _ in 0..size {
169 builder.append_value(*b);
170 }
171 Ok(ArrowVector::new(Arc::new(builder.finish()), PhysicalTypeID::Bool))
172 }
173 Constant::Integer(i) => {
174 let mut builder = arrow::array::Int64Builder::with_capacity(size);
175 let v = *i;
176 for _ in 0..size {
177 builder.append_value(v);
178 }
179 Ok(ArrowVector::new(Arc::new(builder.finish()), PhysicalTypeID::Int64))
180 }
181 Constant::Float(f) => {
182 let mut builder = arrow::array::Float64Builder::with_capacity(size);
183 let v = *f;
184 for _ in 0..size {
185 builder.append_value(v);
186 }
187 Ok(ArrowVector::new(Arc::new(builder.finish()), PhysicalTypeID::Double))
188 }
189 Constant::String(s) => {
190 let mut builder = arrow::array::StringBuilder::with_capacity(size, size * s.len().max(1));
191 for _ in 0..size {
192 builder.append_value(s);
193 }
194 Ok(ArrowVector::new(Arc::new(builder.finish()), PhysicalTypeID::String))
195 }
196 }
197 }
198
199 fn evaluate_arrow_variable(&self, name: &str, chunk: &DataChunk) -> Result<ArrowVector, ProcessorError> {
201 let idx = if let Ok(idx) = name.parse::<usize>() {
202 idx
203 } else if !chunk.field_names.is_empty() {
204 if let Some(idx) = chunk.field_names.iter().position(|n| n == name) {
205 idx
206 } else {
207 return Err(format!("Variable '{}' not found in field_names", name).into());
208 }
209 } else {
210 return Err(format!("Variable '{}' not found (chunk has no field_names)", name).into());
211 };
212
213 let field = chunk
214 .fields
215 .get(idx)
216 .ok_or_else(|| format!("Variable '{}' (index {}) not found in chunk fields", name, idx))?;
217 Ok(ArrowVector::new(field.clone(), chunk.field_types[idx]))
218 }
219
220 fn evaluate_arrow_property_access(
222 &self,
223 obj: &Expression,
224 prop: &str,
225 chunk: &DataChunk,
226 ) -> Result<ArrowVector, ProcessorError> {
227 let qualified_prop = if let Expression::Variable(var_name) = obj {
228 format!("{}.{}", var_name, prop)
229 } else {
230 prop.to_string()
231 };
232
233 if !chunk.field_names.is_empty()
234 && let Some(idx) = chunk.field_names.iter().position(|n| n == &qualified_prop || n == prop)
235 {
236 let field = chunk
237 .fields
238 .get(idx)
239 .ok_or_else(|| format!("Property '{}' not found in chunk", prop))?;
240 return Ok(ArrowVector::new(field.clone(), chunk.field_types[idx]));
241 }
242 let legacy = self.evaluate(obj, chunk)?;
243 Ok(ArrowVector::from_legacy(&legacy))
244 }
245
246 fn evaluate_arrow_binary_op(
248 &self,
249 op: &BinaryOp,
250 left: &Expression,
251 right: &Expression,
252 chunk: &DataChunk,
253 ) -> Result<ArrowVector, ProcessorError> {
254 match op {
255 BinaryOp::In | BinaryOp::NotIn => {
256 let legacy = self.evaluate_in_op(op, left, right, chunk)?;
257 return Ok(ArrowVector::from_legacy(&legacy));
258 }
259 BinaryOp::Concat | BinaryOp::StartsWith | BinaryOp::EndsWith | BinaryOp::Contains | BinaryOp::Like => {
260 let func_name = match op {
261 BinaryOp::Concat => "concat",
262 BinaryOp::StartsWith => "starts_with",
263 BinaryOp::EndsWith => "ends_with",
264 BinaryOp::Contains => "contains",
265 BinaryOp::Like => "like",
266 _ => unreachable!(),
267 };
268 return self.evaluate_arrow_function_call(func_name, &[left, right], chunk);
269 }
270 _ => {}
271 }
272
273 let kernel_name = match op {
274 BinaryOp::Add => "add",
275 BinaryOp::Subtract => "sub",
276 BinaryOp::Multiply => "mul",
277 BinaryOp::Divide => "div",
278 BinaryOp::Modulo => "mod",
279 BinaryOp::Equal => "eq",
280 BinaryOp::NotEqual => "neq",
281 BinaryOp::LessThan => "lt",
282 BinaryOp::LessThanOrEqual => "lt_eq",
283 BinaryOp::GreaterThan => "gt",
284 BinaryOp::GreaterThanOrEqual => "gt_eq",
285 BinaryOp::And => "and",
286 BinaryOp::Or => "or",
287 BinaryOp::Xor => "xor",
288 _ => return Err(format!("Unsupported binary op: {:?}", op).into()),
289 };
290
291 let left_arrow = self.evaluate_arrow(left, chunk)?;
292 let right_arrow = self.evaluate_arrow(right, chunk)?;
293
294 match self.apply_arrow_kernel(kernel_name, &left_arrow, &right_arrow) {
295 Ok(result) => Ok(result),
296 Err(_) => {
297 let legacy = self.evaluate_binary_op(op, left, right, chunk)?;
298 Ok(ArrowVector::from_legacy(&legacy))
299 }
300 }
301 }
302
303 fn evaluate_arrow_unary_op(
305 &self,
306 op: &UnaryOp,
307 inner: &Expression,
308 chunk: &DataChunk,
309 ) -> Result<ArrowVector, ProcessorError> {
310 match op {
311 UnaryOp::Not => {
312 let inner_arrow = self.evaluate_arrow(inner, chunk)?;
313 self.apply_arrow_unary_kernel("not", &inner_arrow).or_else(|_| {
314 let legacy = self.evaluate_unary_op(&UnaryOp::Not, inner, chunk)?;
315 Ok(ArrowVector::from_legacy(&legacy))
316 })
317 }
318 UnaryOp::Negate => {
319 let inner_arrow = self.evaluate_arrow(inner, chunk)?;
320 self.apply_arrow_unary_kernel("negate", &inner_arrow).or_else(|_| {
321 let legacy = self.evaluate_unary_op(&UnaryOp::Negate, inner, chunk)?;
322 Ok(ArrowVector::from_legacy(&legacy))
323 })
324 }
325 UnaryOp::IsNull => {
326 let inner_arrow = self.evaluate_arrow(inner, chunk)?;
327 self.apply_arrow_unary_kernel("is_null", &inner_arrow)
328 }
329 UnaryOp::IsNotNull => {
330 let inner_arrow = self.evaluate_arrow(inner, chunk)?;
331 self.apply_arrow_unary_kernel("is_not_null", &inner_arrow)
332 }
333 }
334 }
335
336 fn apply_arrow_kernel(
338 &self,
339 name: &str,
340 left: &ArrowVector,
341 right: &ArrowVector,
342 ) -> Result<ArrowVector, ProcessorError> {
343 use arrow::compute::kernels::boolean::{and_kleene, or_kleene};
344 use arrow::compute::kernels::cmp::{eq, gt, gt_eq, lt, lt_eq, neq};
345 use arrow::compute::kernels::numeric::{add, div, mul, rem, sub};
346
347 let result: ArrayRef = match name {
348 "add" => Arc::new(add(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
349 "sub" => Arc::new(sub(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
350 "mul" => Arc::new(mul(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
351 "div" => Arc::new(div(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
352 "mod" => Arc::new(rem(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
353 "eq" => Arc::new(eq(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
354 "neq" => Arc::new(neq(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
355 "lt" => Arc::new(lt(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
356 "lt_eq" => Arc::new(lt_eq(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
357 "gt" => Arc::new(gt(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
358 "gt_eq" => Arc::new(gt_eq(&left.array, &right.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
359 "and" => {
360 let l = left
361 .array
362 .as_any()
363 .downcast_ref::<arrow::array::BooleanArray>()
364 .ok_or_else(|| format!("Arrow {name}: expected BooleanArray, got {:?}", left.array.data_type()))?;
365 let r = right
366 .array
367 .as_any()
368 .downcast_ref::<arrow::array::BooleanArray>()
369 .ok_or_else(|| format!("Arrow {name}: expected BooleanArray, got {:?}", right.array.data_type()))?;
370 Arc::new(and_kleene(l, r).map_err(|e| format!("Arrow {name} failed: {e}"))?)
371 }
372 "or" => {
373 let l = left
374 .array
375 .as_any()
376 .downcast_ref::<arrow::array::BooleanArray>()
377 .ok_or_else(|| format!("Arrow {name}: expected BooleanArray, got {:?}", left.array.data_type()))?;
378 let r = right
379 .array
380 .as_any()
381 .downcast_ref::<arrow::array::BooleanArray>()
382 .ok_or_else(|| format!("Arrow {name}: expected BooleanArray, got {:?}", right.array.data_type()))?;
383 Arc::new(or_kleene(l, r).map_err(|e| format!("Arrow {name} failed: {e}"))?)
384 }
385 "xor" => {
386 let l = left
388 .array
389 .as_any()
390 .downcast_ref::<arrow::array::BooleanArray>()
391 .ok_or_else(|| format!("Arrow {name}: expected BooleanArray, got {:?}", left.array.data_type()))?;
392 let r = right
393 .array
394 .as_any()
395 .downcast_ref::<arrow::array::BooleanArray>()
396 .ok_or_else(|| format!("Arrow {name}: expected BooleanArray, got {:?}", right.array.data_type()))?;
397 let not_r =
398 arrow::compute::kernels::boolean::not(r).map_err(|e| format!("Arrow xor/not failed: {e}"))?;
399 let not_l =
400 arrow::compute::kernels::boolean::not(l).map_err(|e| format!("Arrow xor/not failed: {e}"))?;
401 let l_and_not_r = and_kleene(l, ¬_r).map_err(|e| format!("Arrow xor/and failed: {e}"))?;
402 let not_l_and_r = and_kleene(¬_l, r).map_err(|e| format!("Arrow xor/and failed: {e}"))?;
403 Arc::new(or_kleene(&l_and_not_r, ¬_l_and_r).map_err(|e| format!("Arrow xor/or failed: {e}"))?)
404 }
405 _ => return Err(format!("Unknown binary kernel: {name}").into()),
406 };
407
408 let phys_type = match name {
409 "eq" | "neq" | "lt" | "lt_eq" | "gt" | "gt_eq" | "and" | "or" | "xor" => PhysicalTypeID::Bool,
410 _ => left.physical_type,
411 };
412
413 Ok(ArrowVector::new(result, phys_type))
414 }
415
416 fn apply_arrow_unary_kernel(&self, name: &str, arr: &ArrowVector) -> Result<ArrowVector, ProcessorError> {
418 use arrow::compute::kernels::boolean::{is_not_null, is_null, not};
419 use arrow::compute::kernels::numeric::neg;
420
421 let result: ArrayRef = match name {
422 "not" => {
423 let arr_ref = arr
424 .array
425 .as_any()
426 .downcast_ref::<arrow::array::BooleanArray>()
427 .ok_or_else(|| format!("Arrow {name}: expected BooleanArray, got {:?}", arr.array.data_type()))?;
428 Arc::new(not(arr_ref).map_err(|e| format!("Arrow {name} failed: {e}"))?)
429 }
430 "negate" => Arc::new(neg(&*arr.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
431 "is_null" => Arc::new(is_null(&*arr.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
432 "is_not_null" => Arc::new(is_not_null(&*arr.array).map_err(|e| format!("Arrow {name} failed: {e}"))?),
433 _ => return Err(format!("Unknown unary kernel: {name}").into()),
434 };
435
436 let phys_type = if matches!(name, "is_null" | "is_not_null" | "not") {
437 PhysicalTypeID::Bool
438 } else {
439 arr.physical_type
440 };
441
442 Ok(ArrowVector::new(result, phys_type))
443 }
444
445 fn evaluate_arrow_function_call(
449 &self,
450 name: &str,
451 args: &[&Expression],
452 chunk: &DataChunk,
453 ) -> Result<ArrowVector, ProcessorError> {
454 if let Some(_lambda) = self.extract_lambda_arg(args) {
456 match name {
457 "list_transform" | "list_filter" | "list_reduce" => {
458 let legacy = self.evaluate_function_call(name, args, chunk)?;
459 return Ok(ArrowVector::from_legacy(&legacy));
460 }
461 _ => {}
462 }
463 }
464
465 let arg_arrows: Vec<ArrowVector> = args
467 .iter()
468 .map(|arg| self.evaluate_arrow(arg, chunk))
469 .collect::<Result<Vec<_>, _>>()?;
470
471 if arg_arrows.is_empty() {
472 return Err(format!("Function '{}' requires at least one argument", name).into());
473 }
474
475 let num_rows = arg_arrows[0].size();
476
477 let func = {
479 let reg = self.registry.lock().map_err(|e| format!("Lock poisoned: {e}"))?;
480 reg.get_scalar(name).cloned()
481 };
482 let func = match func {
483 Some(f) => f,
484 None => return Err(format!("Unknown function: '{}'", name).into()),
485 };
486
487 if matches!(func, ScalarFunction::SequenceOp { .. }) {
489 let legacy = self.evaluate_function_call(name, args, chunk)?;
490 return Ok(ArrowVector::from_legacy(&legacy));
491 }
492
493 let mut first_error: Option<String> = None;
494 let mut row_results: Vec<Value> = Vec::with_capacity(num_rows);
495
496 for row in 0..num_rows {
497 let arg_values: Vec<Value> = arg_arrows
498 .iter()
499 .map(|arr| {
500 if row < arr.size() && !arr.is_null(row) {
501 arr.get_value(row).unwrap_or(Value::Null)
502 } else {
503 Value::Null
504 }
505 })
506 .collect();
507
508 if name != "coalesce" && name != "ifnull" && arg_values.iter().any(|v| matches!(v, Value::Null)) {
509 row_results.push(Value::Null);
510 continue;
511 }
512
513 match evaluate_scalar(&func, &arg_values) {
514 Ok(val) => row_results.push(val),
515 Err(e) => {
516 row_results.push(Value::Null);
517 if first_error.is_none() {
518 first_error = Some(e);
519 }
520 }
521 }
522 }
523
524 let result_type = row_results
525 .iter()
526 .find(|v| !matches!(v, Value::Null))
527 .map(|v| v.physical_type())
528 .unwrap_or(PhysicalTypeID::Int64);
529
530 let arrow_result = build_arrow_from_values(&row_results, result_type, num_rows)?;
532
533 if row_results.iter().all(|v| matches!(v, Value::Null))
534 && let Some(e) = first_error
535 {
536 return Err(e.into());
537 }
538
539 Ok(arrow_result)
540 }
541
542 fn evaluate_constant(&self, c: &Constant, size: usize) -> Result<ValueVector, ProcessorError> {
544 let val: Value = match c {
545 Constant::Null => Value::Null,
546 Constant::Bool(b) => Value::Bool(*b),
547 Constant::Integer(i) => Value::Int64(*i),
548 Constant::Float(f) => Value::Double(*f),
549 Constant::String(s) => Value::String(s.clone()),
550 };
551
552 let physical_type = val.physical_type();
553 let mut v = ValueVector::new(physical_type, size);
554 v.resize(size);
555 for i in 0..size {
556 store_value_in_vector(&mut v, i, &val)?;
557 }
558 Ok(v)
559 }
560
561 fn evaluate_variable(&self, name: &str, chunk: &DataChunk) -> Result<ValueVector, ProcessorError> {
567 if let Ok(idx) = name.parse::<usize>() {
568 if idx >= chunk.fields.len() {
569 return Err(format!(
570 "Variable '{}' (index {}) not found in chunk with {} fields",
571 name,
572 idx,
573 chunk.fields.len()
574 )
575 .into());
576 }
577 let phys_type = chunk.field_types[idx];
578 let mut v = ValueVector::new(phys_type, chunk.size);
579 v.resize(chunk.size);
580 for i in 0..chunk.size {
581 if let Some(val) = chunk.get_value(idx, i) {
582 store_value_in_vector(&mut v, i, &val)?;
583 } else {
584 v.set_null(i, true);
585 }
586 }
587 return Ok(v);
588 }
589
590 if !chunk.field_names.is_empty() {
591 if let Some(idx) = chunk.field_names.iter().position(|n| n == name) {
592 let phys_type = chunk.field_types[idx];
593 let mut v = ValueVector::new(phys_type, chunk.size);
594 v.resize(chunk.size);
595 for i in 0..chunk.size {
596 if let Some(val) = chunk.get_value(idx, i) {
597 store_value_in_vector(&mut v, i, &val)?;
598 } else {
599 v.set_null(i, true);
600 }
601 }
602 return Ok(v);
603 }
604 }
605
606 if !chunk.fields.is_empty() {
607 let phys_type = chunk.field_types[0];
608 let mut v = ValueVector::new(phys_type, chunk.size);
609 v.resize(chunk.size);
610 for i in 0..chunk.size {
611 if let Some(val) = chunk.get_value(0, i) {
612 store_value_in_vector(&mut v, i, &val)?;
613 } else {
614 v.set_null(i, true);
615 }
616 }
617 Ok(v)
618 } else {
619 Ok(ValueVector::new(akar_common::types::PhysicalTypeID::Int64, 0))
620 }
621 }
622
623 fn evaluate_property_access(
629 &self,
630 obj: &Expression,
631 prop: &str,
632 chunk: &DataChunk,
633 ) -> Result<ValueVector, ProcessorError> {
634 let qualified_prop = if let Expression::Variable(var_name) = obj {
636 format!("{}.{}", var_name, prop)
637 } else {
638 prop.to_string()
639 };
640
641 if !chunk.field_names.is_empty()
643 && let Some(idx) = chunk.field_names.iter().position(|n| n == &qualified_prop || n == prop)
644 {
645 if chunk.fields.get(idx).is_none() {
646 return Err(format!("Column '{}' (index {}) not found in chunk", prop, idx).into());
647 }
648 let phys_type = chunk.field_types[idx];
649 let mut v = ValueVector::new(phys_type, chunk.size);
650 v.resize(chunk.size);
651 for i in 0..chunk.size {
652 if let Some(val) = chunk.get_value(idx, i) {
653 store_value_in_vector(&mut v, i, &val)?;
654 } else {
655 v.set_null(i, true);
656 }
657 }
658 return Ok(v);
659 }
660 self.evaluate(obj, chunk)
662 }
663
664 fn evaluate_function_call(
666 &self,
667 name: &str,
668 args: &[&Expression],
669 chunk: &DataChunk,
670 ) -> Result<ValueVector, ProcessorError> {
671 if let Some(lambda) = self.extract_lambda_arg(args) {
675 match name {
676 "list_transform" => return self.evaluate_list_transform(args, lambda, chunk),
677 "list_filter" => return self.evaluate_list_filter(args, lambda, chunk),
678 "list_reduce" => return self.evaluate_list_reduce(args, lambda, chunk),
679 _ => {}
680 }
681 }
682
683 let arg_vectors: Vec<ValueVector> = args
685 .iter()
686 .map(|arg| self.evaluate(arg, chunk))
687 .collect::<Result<Vec<_>, _>>()?;
688
689 if arg_vectors.is_empty() {
690 return Err(format!("Function '{}' requires at least one argument", name).into());
691 }
692
693 let num_rows = arg_vectors[0].size();
694
695 let func = {
697 let reg = self.registry.lock().map_err(|e| format!("Lock poisoned: {e}"))?;
698 reg.get_scalar(name).cloned()
699 };
700
701 let func = match func {
702 Some(f) => f,
703 None => return Err(format!("Unknown function: '{}'", name).into()),
704 };
705
706 if matches!(func, ScalarFunction::SequenceOp { .. }) {
708 return self.evaluate_sequence_op(name, &func, &arg_vectors, num_rows);
709 }
710
711 let mut row_results: Vec<Value> = Vec::with_capacity(num_rows);
714 let mut first_error: Option<String> = None;
715
716 for row in 0..num_rows {
717 let arg_values: Vec<Value> = arg_vectors
718 .iter()
719 .map(|vec| {
720 if row < vec.size() && !vec.is_null(row) {
721 vec.get_value(row).unwrap_or(Value::Null)
722 } else {
723 Value::Null
724 }
725 })
726 .collect();
727
728 if name == "AND" || name == "OR" {
730 let l = &arg_values[0];
731 let r = &arg_values[1];
732 if name == "AND" {
733 if matches!(l, Value::Bool(false)) || matches!(r, Value::Bool(false)) {
734 row_results.push(Value::Bool(false));
735 continue;
736 }
737 if matches!(l, Value::Null) || matches!(r, Value::Null) {
738 row_results.push(Value::Null);
739 continue;
740 }
741 } else {
742 if matches!(l, Value::Bool(true)) || matches!(r, Value::Bool(true)) {
743 row_results.push(Value::Bool(true));
744 continue;
745 }
746 if matches!(l, Value::Null) || matches!(r, Value::Null) {
747 row_results.push(Value::Null);
748 continue;
749 }
750 }
751 }
752
753 if name != "coalesce" && name != "ifnull" && arg_values.iter().any(|v| matches!(v, Value::Null)) {
756 row_results.push(Value::Null);
757 continue;
758 }
759
760 match evaluate_scalar(&func, &arg_values) {
761 Ok(val) => row_results.push(val),
762 Err(e) => {
763 row_results.push(Value::Null);
764 if first_error.is_none() {
765 first_error = Some(e);
766 }
767 }
768 }
769 }
770
771 let result_type = row_results
772 .iter()
773 .find(|v| !matches!(v, Value::Null))
774 .map(|v| v.physical_type())
775 .unwrap_or(akar_common::types::PhysicalTypeID::Int64);
776
777 let mut result_vec = ValueVector::new(result_type, num_rows);
778 result_vec.resize(num_rows);
779 for (row, val) in row_results.iter().enumerate() {
780 store_value_in_vector(&mut result_vec, row, val)?;
781 }
782
783 if row_results.iter().all(|v| matches!(v, Value::Null))
784 && let Some(e) = first_error
785 {
786 return Err(e.into());
787 }
788
789 Ok(result_vec)
790 }
791
792 fn evaluate_binary_op(
794 &self,
795 op: &BinaryOp,
796 left: &Expression,
797 right: &Expression,
798 chunk: &DataChunk,
799 ) -> Result<ValueVector, ProcessorError> {
800 let func_name = match op {
802 BinaryOp::Add => "+",
803 BinaryOp::Subtract => "-",
804 BinaryOp::Multiply => "*",
805 BinaryOp::Divide => "/",
806 BinaryOp::Modulo => "%",
807 BinaryOp::Equal => "=",
808 BinaryOp::NotEqual => "<>",
809 BinaryOp::LessThan => "<",
810 BinaryOp::LessThanOrEqual => "<=",
811 BinaryOp::GreaterThan => ">",
812 BinaryOp::GreaterThanOrEqual => ">=",
813 BinaryOp::And => "AND",
814 BinaryOp::Or => "OR",
815 BinaryOp::Xor => "XOR",
816 BinaryOp::Concat => "concat",
817 BinaryOp::In | BinaryOp::NotIn => {
819 return self.evaluate_in_op(op, left, right, chunk);
820 }
821 BinaryOp::StartsWith => "starts_with",
822 BinaryOp::EndsWith => "ends_with",
823 BinaryOp::Contains => "contains",
824 BinaryOp::Like => {
825 return self.evaluate_function_call("like", &[left, right], chunk);
826 }
827 };
828
829 self.evaluate_function_call(func_name, &[left, right], chunk)
831 }
832
833 fn evaluate_unary_op(
835 &self,
836 op: &UnaryOp,
837 inner: &Expression,
838 chunk: &DataChunk,
839 ) -> Result<ValueVector, ProcessorError> {
840 match op {
841 UnaryOp::Not => self.evaluate_function_call("NOT", std::slice::from_ref(&inner), chunk),
842 UnaryOp::Negate => self.evaluate_function_call("-", std::slice::from_ref(&inner), chunk),
843 UnaryOp::IsNull => {
844 let vec = self.evaluate(inner, chunk)?;
845 let num_rows = vec.size();
846 let mut result = ValueVector::new(akar_common::types::PhysicalTypeID::Bool, num_rows);
847 result.resize(num_rows);
848 for i in 0..num_rows {
849 let is_null = vec.is_null(i) || matches!(vec.get_value(i), Some(Value::Null) | None);
850 store_value_in_vector_simple(&mut result, i, &Value::Bool(is_null))?;
851 }
852 Ok(result)
853 }
854 UnaryOp::IsNotNull => {
855 let vec = self.evaluate(inner, chunk)?;
856 let num_rows = vec.size();
857 let mut result = ValueVector::new(akar_common::types::PhysicalTypeID::Bool, num_rows);
858 result.resize(num_rows);
859 for i in 0..num_rows {
860 let is_null = vec.is_null(i) || matches!(vec.get_value(i), Some(Value::Null) | None);
861 store_value_in_vector_simple(&mut result, i, &Value::Bool(!is_null))?;
862 }
863 Ok(result)
864 }
865 }
866 }
867
868 fn evaluate_in_op(
870 &self,
871 op: &BinaryOp,
872 left: &Expression,
873 right: &Expression,
874 chunk: &DataChunk,
875 ) -> Result<ValueVector, ProcessorError> {
876 let left_arr = self.evaluate_arrow(left, chunk)?;
877 let num_rows = chunk.size;
878 let mut result = ValueVector::new(akar_common::types::PhysicalTypeID::Bool, num_rows);
879 result.resize(num_rows);
880 for row in 0..num_rows {
881 let lv = left_arr.get_value(row).unwrap_or(Value::Null);
882 if matches!(lv, Value::Null) {
883 result.set_null(row, true);
884 continue;
885 }
886 let (in_list, has_null) = match right {
887 Expression::List(items) => {
888 let mut matched = false;
889 let mut has_null_item = false;
890 for item in items {
891 let item_vec = self.evaluate(item, chunk)?;
892 let iv = item_vec.get_value(row).unwrap_or(Value::Null);
893 if matches!(iv, Value::Null) {
894 has_null_item = true;
895 } else if iv == lv {
896 matched = true;
897 break;
898 }
899 }
900 (matched, has_null_item)
901 }
902 _ => {
903 let right_arr = self.evaluate_arrow(right, chunk)?;
904 let rv = right_arr.get_value(row).unwrap_or(Value::Null);
905 match &rv {
906 Value::List(ritems) => {
907 let matched = ritems.contains(&lv);
908 let has_null_item = if matched {
909 false
910 } else {
911 ritems.iter().any(|item| matches!(item, Value::Null))
912 };
913 (matched, has_null_item)
914 }
915 _ => (lv == rv, false),
916 }
917 }
918 };
919 let result_val = if *op == BinaryOp::NotIn { !in_list } else { in_list };
920 if !in_list && has_null {
921 result.set_null(row, true);
922 } else {
923 store_value_in_vector_simple(&mut result, row, &Value::Bool(result_val))?;
924 }
925 }
926 Ok(result)
927 }
928
929 fn evaluate_case(
931 &self,
932 case_expr: &akar_parser::ast::CaseExpr,
933 chunk: &DataChunk,
934 ) -> Result<ValueVector, ProcessorError> {
935 let num_rows = chunk.size;
936 let subject_vec = if let Some(subj) = &case_expr.subject {
938 Some(self.evaluate(subj, chunk)?)
939 } else {
940 None
941 };
942
943 let result_type = {
947 let first_then = self.evaluate(&case_expr.alternatives[0].then, chunk)?;
948 first_then.physical_type()
949 };
950
951 let mut result = ValueVector::new(result_type, num_rows);
952 result.resize(num_rows);
953
954 for row in 0..num_rows {
956 let subject_val = subject_vec.as_ref().and_then(|sv| sv.get_value(row));
957
958 let mut matched = false;
959 for alt in &case_expr.alternatives {
960 let when_vec = self.evaluate(&alt.when, chunk)?;
961 let when_val = when_vec.get_value(row).unwrap_or(Value::Null);
962
963 let branch_taken = if let Some(ref sv) = subject_val {
966 when_val != Value::Null && when_val == *sv
967 } else {
968 matches!(when_val, Value::Bool(true))
969 };
970
971 if branch_taken {
972 let then_vec = self.evaluate(&alt.then, chunk)?;
973 let then_val = then_vec.get_value(row).unwrap_or(Value::Null);
974 store_value_in_vector(&mut result, row, &then_val)?;
975 matched = true;
976 break;
977 }
978 }
979
980 if !matched {
981 if let Some(else_e) = &case_expr.else_expr {
982 let else_vec = self.evaluate(else_e, chunk)?;
983 let else_val = else_vec.get_value(row).unwrap_or(Value::Null);
984 store_value_in_vector(&mut result, row, &else_val)?;
985 } else {
986 result.set_null(row, true);
987 }
988 }
989 }
990
991 Ok(result)
992 }
993
994 fn evaluate_list_literal(&self, items: &[Expression], chunk: &DataChunk) -> Result<ValueVector, ProcessorError> {
996 if items.is_empty() {
997 let mut v = ValueVector::new(akar_common::types::PhysicalTypeID::List, chunk.size);
998 v.resize(chunk.size);
999 for i in 0..chunk.size {
1000 store_value_in_vector(&mut v, i, &Value::List(vec![]))?;
1001 }
1002 return Ok(v);
1003 }
1004
1005 let num_rows = chunk.size;
1006 let mut result_vec = ValueVector::new(akar_common::types::PhysicalTypeID::List, num_rows);
1007 result_vec.resize(num_rows);
1008
1009 for row in 0..num_rows {
1010 let mut list_values = Vec::with_capacity(items.len());
1013 for item in items {
1014 let item_vec = self.evaluate(item, chunk)?;
1015 let val = if row < item_vec.size() {
1016 item_vec.get_value(row).unwrap_or(Value::Null)
1017 } else {
1018 Value::Null
1019 };
1020 list_values.push(val);
1021 }
1022 store_value_in_vector(&mut result_vec, row, &Value::List(list_values))?;
1023 }
1024
1025 Ok(result_vec)
1026 }
1027
1028 fn evaluate_map_literal(
1030 &self,
1031 items: &[(String, Expression)],
1032 chunk: &DataChunk,
1033 ) -> Result<ValueVector, ProcessorError> {
1034 let num_rows = chunk.size;
1035 let mut result_vec = ValueVector::new(akar_common::types::PhysicalTypeID::Struct, num_rows);
1036 result_vec.resize(num_rows);
1037
1038 for row in 0..num_rows {
1039 let mut map_values = Vec::with_capacity(items.len());
1040 for (key, item) in items {
1041 let item_vec = self.evaluate(item, chunk)?;
1042 let val = if row < item_vec.size() {
1043 item_vec.get_value(row).unwrap_or(Value::Null)
1044 } else {
1045 Value::Null
1046 };
1047 map_values.push((Value::String(key.clone()), val));
1048 }
1049 store_value_in_vector(&mut result_vec, row, &Value::Map(map_values))?;
1050 }
1051
1052 Ok(result_vec)
1053 }
1054
1055 fn evaluate_list_predicate(
1059 &self,
1060 quantifier: &akar_parser::ast::Quantifier,
1061 list: &Expression,
1062 _var_name: &str,
1063 predicate: &Expression,
1064 chunk: &DataChunk,
1065 ) -> Result<ValueVector, ProcessorError> {
1066 let list_vec = self.evaluate(list, chunk)?;
1068 let num_rows = chunk.size;
1069 let mut result = ValueVector::new(akar_common::types::PhysicalTypeID::Bool, num_rows);
1070 result.resize(num_rows);
1071
1072 for row in 0..num_rows {
1073 let list_val = list_vec.get_value(row).unwrap_or(Value::Null);
1074 let items = match &list_val {
1075 Value::List(items) => items.as_slice(),
1076 _ => {
1077 store_value_in_vector(&mut result, row, &Value::Bool(false))?;
1079 continue;
1080 }
1081 };
1082
1083 let mut true_count = 0u64;
1086 for item in items {
1087 let mut elem_vec = ValueVector::new(item.physical_type(), 1);
1089 elem_vec.resize(1);
1090 store_value_in_vector(&mut elem_vec, 0, item)?;
1091 let mini_chunk = {
1092 let arrow_fields = vec![&elem_vec]
1093 .into_iter()
1094 .map(|v| akar_common::arrow_vector::ArrowVector::from_legacy(v).array)
1095 .collect::<Vec<_>>();
1096 let arrow_field_types = vec![&elem_vec]
1097 .into_iter()
1098 .map(|v| v.physical_type())
1099 .collect::<Vec<_>>();
1100 DataChunk::new(arrow_fields, arrow_field_types)
1101 };
1102
1103 let pred_vec = self.evaluate(predicate, &mini_chunk)?;
1104 let pred_val = pred_vec.get_value(0).unwrap_or(Value::Null);
1105
1106 if matches!(pred_val, Value::Bool(true)) {
1107 true_count += 1;
1108 }
1109 }
1110
1111 let elem_count = items.len() as u64;
1113 let bool_result = match quantifier {
1114 akar_parser::ast::Quantifier::Any => true_count > 0,
1115 akar_parser::ast::Quantifier::All => !items.is_empty() && true_count == elem_count,
1116 akar_parser::ast::Quantifier::None => true_count == 0,
1117 akar_parser::ast::Quantifier::Single => true_count == 1,
1118 };
1119 store_value_in_vector(&mut result, row, &Value::Bool(bool_result))?;
1120 }
1121
1122 Ok(result)
1123 }
1124
1125 fn extract_lambda_arg<'a>(&self, args: &'a [&Expression]) -> Option<&'a Expression> {
1127 args.iter().find(|a| matches!(a, Expression::Lambda { .. })).copied()
1128 }
1129
1130 fn evaluate_list_transform(
1132 &self,
1133 args: &[&Expression],
1134 lambda: &Expression,
1135 chunk: &DataChunk,
1136 ) -> Result<ValueVector, ProcessorError> {
1137 let list_expr = args
1138 .iter()
1139 .find(|a| !matches!(a, Expression::Lambda { .. }))
1140 .ok_or("list_transform requires a list argument")?;
1141
1142 let (var_name, body) = match lambda {
1143 Expression::Lambda { var_name, body } => (var_name, body),
1144 _ => return Err("Expected lambda expression".into()),
1145 };
1146
1147 let list_vec = self.evaluate(list_expr, chunk)?;
1148 let num_rows = chunk.size;
1149 let mut result = ValueVector::new(akar_common::types::PhysicalTypeID::List, num_rows);
1150 result.resize(num_rows);
1151
1152 for row in 0..num_rows {
1153 let list_val = list_vec.get_value(row).unwrap_or(Value::Null);
1154 let items = match list_val {
1155 Value::List(items) => items,
1156 _ => {
1157 store_value_in_vector(&mut result, row, &Value::List(vec![]))?;
1158 continue;
1159 }
1160 };
1161
1162 let mut transformed: Vec<Value> = Vec::with_capacity(items.len());
1163 for item in items {
1164 let mut elem_vec = ValueVector::new(item.physical_type(), 1);
1165 elem_vec.resize(1);
1166 store_value_in_vector(&mut elem_vec, 0, &item)?;
1167 let mut mini_chunk = {
1168 let arrow_fields = vec![&elem_vec]
1169 .into_iter()
1170 .map(|v| akar_common::arrow_vector::ArrowVector::from_legacy(v).array)
1171 .collect::<Vec<_>>();
1172 let arrow_field_types = vec![&elem_vec]
1173 .into_iter()
1174 .map(|v| v.physical_type())
1175 .collect::<Vec<_>>();
1176 DataChunk::new(arrow_fields, arrow_field_types)
1177 };
1178 mini_chunk.field_names.push(var_name.clone());
1179
1180 let body_vec = self.evaluate(body, &mini_chunk)?;
1181 let body_val = body_vec.get_value(0).unwrap_or(Value::Null);
1182 transformed.push(body_val);
1183 }
1184 store_value_in_vector(&mut result, row, &Value::List(transformed))?;
1185 }
1186
1187 Ok(result)
1188 }
1189
1190 fn evaluate_list_filter(
1192 &self,
1193 args: &[&Expression],
1194 lambda: &Expression,
1195 chunk: &DataChunk,
1196 ) -> Result<ValueVector, ProcessorError> {
1197 let list_expr = args
1198 .iter()
1199 .find(|a| !matches!(a, Expression::Lambda { .. }))
1200 .ok_or("list_filter requires a list argument")?;
1201
1202 let (var_name, body) = match lambda {
1203 Expression::Lambda { var_name, body } => (var_name, body),
1204 _ => return Err("Expected lambda expression".into()),
1205 };
1206
1207 let list_vec = self.evaluate(list_expr, chunk)?;
1208 let num_rows = chunk.size;
1209 let mut result = ValueVector::new(akar_common::types::PhysicalTypeID::List, num_rows);
1210 result.resize(num_rows);
1211
1212 for row in 0..num_rows {
1213 let list_val = list_vec.get_value(row).unwrap_or(Value::Null);
1214 let items = match list_val {
1215 Value::List(items) => items,
1216 _ => {
1217 store_value_in_vector(&mut result, row, &Value::List(vec![]))?;
1218 continue;
1219 }
1220 };
1221
1222 let mut filtered: Vec<Value> = Vec::with_capacity(items.len());
1223 for item in items {
1224 let mut elem_vec = ValueVector::new(item.physical_type(), 1);
1225 elem_vec.resize(1);
1226 store_value_in_vector(&mut elem_vec, 0, &item)?;
1227 let mut mini_chunk = {
1228 let arrow_fields = vec![&elem_vec]
1229 .into_iter()
1230 .map(|v| akar_common::arrow_vector::ArrowVector::from_legacy(v).array)
1231 .collect::<Vec<_>>();
1232 let arrow_field_types = vec![&elem_vec]
1233 .into_iter()
1234 .map(|v| v.physical_type())
1235 .collect::<Vec<_>>();
1236 DataChunk::new(arrow_fields, arrow_field_types)
1237 };
1238 mini_chunk.field_names.push(var_name.clone());
1239
1240 let pred_vec = self.evaluate(body, &mini_chunk)?;
1241 let pred_val = pred_vec.get_value(0).unwrap_or(Value::Null);
1242
1243 if matches!(pred_val, Value::Bool(true)) {
1244 filtered.push(item);
1245 } else if let Value::Int64(x) = pred_val {
1246 if x != 0 {
1247 filtered.push(item);
1248 }
1249 }
1250 }
1251 store_value_in_vector(&mut result, row, &Value::List(filtered))?;
1252 }
1253
1254 Ok(result)
1255 }
1256
1257 fn evaluate_list_reduce(
1259 &self,
1260 args: &[&Expression],
1261 lambda: &Expression,
1262 chunk: &DataChunk,
1263 ) -> Result<ValueVector, ProcessorError> {
1264 let list_expr = args
1265 .iter()
1266 .find(|a| !matches!(a, Expression::Lambda { .. }))
1267 .ok_or("list_reduce requires a list argument")?;
1268
1269 let initial_expr = args
1271 .iter()
1272 .filter(|a| !matches!(a, Expression::Lambda { .. }))
1273 .nth(1) .ok_or("list_reduce requires an initial value argument")?;
1275
1276 let (var_name, body) = match lambda {
1277 Expression::Lambda { var_name, body } => (var_name, body),
1278 _ => return Err("Expected lambda expression".into()),
1279 };
1280
1281 let acc_name = var_name.clone();
1283 let elem_name = match body.as_ref() {
1284 Expression::BinaryOp(_op, left, right) => {
1285 let left_var = if let Expression::Variable(v) = left.as_ref() {
1288 Some(v.clone())
1289 } else {
1290 None
1291 };
1292 let right_var = if let Expression::Variable(v) = right.as_ref() {
1293 Some(v.clone())
1294 } else {
1295 None
1296 };
1297
1298 if left_var.as_deref() == Some(&acc_name) {
1299 right_var.unwrap_or_default()
1300 } else if right_var.as_deref() == Some(&acc_name) {
1301 left_var.unwrap_or_default()
1302 } else {
1303 String::new()
1304 }
1305 }
1306 _ => String::new(),
1307 };
1308
1309 let list_vec = self.evaluate(list_expr, chunk)?;
1310 let initial_vec = self.evaluate(initial_expr, chunk)?;
1311 let num_rows = chunk.size;
1312 let mut result = ValueVector::new(akar_common::types::PhysicalTypeID::Int64, num_rows);
1313 result.resize(num_rows);
1314
1315 let field_names_template = {
1317 let mut names = vec![acc_name.clone()];
1318 if !elem_name.is_empty() {
1319 names.push(elem_name.clone());
1320 }
1321 names
1322 };
1323
1324 for row in 0..num_rows {
1325 let list_val = list_vec.get_value(row).unwrap_or(Value::Null);
1326 let items = match list_val {
1327 Value::List(items) => items,
1328 _ => {
1329 store_value_in_vector(&mut result, row, &Value::Null)?;
1330 continue;
1331 }
1332 };
1333
1334 let mut acc = initial_vec.get_value(row).unwrap_or(Value::Null);
1335 for item in items {
1336 let mut acc_vec = ValueVector::new(acc.physical_type(), 1);
1338 acc_vec.resize(1);
1339 store_value_in_vector(&mut acc_vec, 0, &acc)?;
1340 let mut elem_vec = ValueVector::new(item.physical_type(), 1);
1341 elem_vec.resize(1);
1342 store_value_in_vector(&mut elem_vec, 0, &item)?;
1343 let mut mini_chunk = {
1344 let arrow_fields = vec![&acc_vec, &elem_vec]
1345 .into_iter()
1346 .map(|v| akar_common::arrow_vector::ArrowVector::from_legacy(v).array)
1347 .collect::<Vec<_>>();
1348 let arrow_field_types = vec![&acc_vec, &elem_vec]
1349 .into_iter()
1350 .map(|v| v.physical_type())
1351 .collect::<Vec<_>>();
1352 DataChunk::new(arrow_fields, arrow_field_types)
1353 };
1354 mini_chunk.field_names = field_names_template.clone();
1355
1356 let body_vec = self.evaluate(body, &mini_chunk)?;
1357 acc = body_vec.get_value(0).unwrap_or(Value::Null);
1358 }
1359 store_value_in_vector(&mut result, row, &acc)?;
1360 }
1361
1362 Ok(result)
1363 }
1364}
1365
1366fn store_value_in_vector_simple(v: &mut ValueVector, row: usize, val: &Value) -> Result<(), String> {
1369 match val {
1370 Value::Null => {
1371 v.set_null(row, true);
1372 }
1373 Value::Bool(x) => {
1374 if v.physical_type() == akar_common::types::PhysicalTypeID::Bool {
1375 v.data_mut()[row] = if *x { 1 } else { 0 };
1376 v.set_null(row, false);
1377 }
1378 }
1379 Value::Int64(x) => {
1380 let offset = row * 8;
1381 if offset + 8 <= v.data().len() {
1382 v.data_mut()[offset..offset + 8].copy_from_slice(&x.to_le_bytes());
1383 v.set_null(row, false);
1384 }
1385 }
1386 Value::UInt64(x) => {
1387 let offset = row * 8;
1388 if offset + 8 <= v.data().len() {
1389 v.data_mut()[offset..offset + 8].copy_from_slice(&x.to_le_bytes());
1390 v.set_null(row, false);
1391 }
1392 }
1393 Value::Double(x) => {
1394 let offset = row * 8;
1395 if offset + 8 <= v.data().len() {
1396 v.data_mut()[offset..offset + 8].copy_from_slice(&x.to_le_bytes());
1397 v.set_null(row, false);
1398 }
1399 }
1400 Value::String(s) => {
1401 let bytes = s.as_bytes();
1402 if bytes.len() > 255 {
1403 return Err(format!(
1404 "Cannot store string of {} bytes: inline string storage limit is 255 bytes",
1405 bytes.len()
1406 ));
1407 }
1408 let offset = row * 256;
1409 if offset < v.data().len() {
1410 v.data_mut()[offset] = bytes.len() as u8;
1411 if offset + 1 + bytes.len() <= v.data().len() {
1412 v.data_mut()[offset + 1..offset + 1 + bytes.len()].copy_from_slice(bytes);
1413 }
1414 v.set_null(row, false);
1415 }
1416 }
1417 _ => {
1418 v.set_null(row, true);
1419 }
1420 }
1421 Ok(())
1422}
1423
1424fn store_value_in_vector(v: &mut ValueVector, row: usize, val: &Value) -> Result<(), String> {
1427 match val {
1428 Value::Null => {
1429 v.set_null(row, true);
1430 }
1431 Value::Bool(x) => {
1432 if v.physical_type() == akar_common::types::PhysicalTypeID::Bool {
1433 v.data_mut()[row] = if *x { 1 } else { 0 };
1434 v.set_null(row, false);
1435 }
1436 }
1437 Value::Int64(x) => {
1438 let offset = row * 8;
1439 if offset + 8 <= v.data().len() {
1440 v.data_mut()[offset..offset + 8].copy_from_slice(&x.to_le_bytes());
1441 v.set_null(row, false);
1442 }
1443 }
1444 Value::UInt64(x) => {
1445 let offset = row * 8;
1446 if offset + 8 <= v.data().len() {
1447 v.data_mut()[offset..offset + 8].copy_from_slice(&x.to_le_bytes());
1448 v.set_null(row, false);
1449 }
1450 }
1451 Value::Date(x) => {
1452 let offset = row * 8;
1453 if offset + 8 <= v.data().len() {
1454 v.data_mut()[offset..offset + 8].copy_from_slice(&(x.0 as i64).to_le_bytes());
1455 v.set_null(row, false);
1456 }
1457 }
1458 Value::Timestamp(x) | Value::TimestampNs(x) | Value::TimestampMs(x) | Value::TimestampSec(x) => {
1459 let offset = row * 8;
1460 if offset + 8 <= v.data().len() {
1461 v.data_mut()[offset..offset + 8].copy_from_slice(&x.0.to_le_bytes());
1462 v.set_null(row, false);
1463 }
1464 }
1465 Value::TimestampTz(x) => {
1466 let offset = row * 8;
1467 if offset + 8 <= v.data().len() {
1468 v.data_mut()[offset..offset + 8].copy_from_slice(&x.0.to_le_bytes());
1469 v.set_null(row, false);
1470 }
1471 }
1472 Value::DTime(x) => {
1473 let offset = row * 8;
1474 if offset + 8 <= v.data().len() {
1475 v.data_mut()[offset..offset + 8].copy_from_slice(&x.to_le_bytes());
1476 v.set_null(row, false);
1477 }
1478 }
1479 Value::Int32(x) => {
1480 let offset = row * 4;
1481 if offset + 4 <= v.data().len() {
1482 v.data_mut()[offset..offset + 4].copy_from_slice(&x.to_le_bytes());
1483 v.set_null(row, false);
1484 }
1485 }
1486 Value::Double(x) => {
1487 let offset = row * 8;
1488 if offset + 8 <= v.data().len() {
1489 v.data_mut()[offset..offset + 8].copy_from_slice(&x.to_le_bytes());
1490 v.set_null(row, false);
1491 }
1492 }
1493 Value::Float(x) => {
1494 let offset = row * 4;
1495 if offset + 4 <= v.data().len() {
1496 v.data_mut()[offset..offset + 4].copy_from_slice(&x.to_le_bytes());
1497 v.set_null(row, false);
1498 }
1499 }
1500 Value::String(s) => {
1501 let bytes = s.as_bytes();
1502 if bytes.len() > 255 {
1503 return Err(format!(
1504 "Cannot store string of {} bytes: inline string storage limit is 255 bytes",
1505 bytes.len()
1506 ));
1507 }
1508 let offset = row * 256;
1509 if offset < v.data().len() {
1510 v.data_mut()[offset] = bytes.len() as u8;
1511 if offset + 1 + bytes.len() <= v.data().len() {
1512 v.data_mut()[offset + 1..offset + 1 + bytes.len()].copy_from_slice(bytes);
1513 }
1514 v.set_null(row, false);
1515 }
1516 }
1517 _ => {
1518 v.set_null(row, true);
1520 }
1521 }
1522 Ok(())
1523}
1524
1525fn build_arrow_from_values(
1528 values: &[Value],
1529 phys_type: PhysicalTypeID,
1530 num_rows: usize,
1531) -> Result<ArrowVector, ProcessorError> {
1532 match phys_type {
1533 PhysicalTypeID::Bool => {
1534 let mut builder = arrow::array::BooleanBuilder::with_capacity(num_rows);
1535 for v in values {
1536 match v {
1537 Value::Null => builder.append_null(),
1538 Value::Bool(b) => builder.append_value(*b),
1539 _ => builder.append_null(),
1540 }
1541 }
1542 Ok(ArrowVector::new(Arc::new(builder.finish()), phys_type))
1543 }
1544 PhysicalTypeID::Int64 => {
1545 let mut builder = arrow::array::Int64Builder::with_capacity(num_rows);
1546 for v in values {
1547 match v {
1548 Value::Null => builder.append_null(),
1549 Value::Int64(n) => builder.append_value(*n),
1550 Value::Int32(n) => builder.append_value(*n as i64),
1551 Value::Date(n) => builder.append_value(n.0 as i64),
1552 Value::Timestamp(n) | Value::TimestampNs(n) | Value::TimestampMs(n) | Value::TimestampSec(n) => {
1553 builder.append_value(n.0)
1554 }
1555 Value::TimestampTz(n) => builder.append_value(n.0),
1556 Value::DTime(n) => builder.append_value(*n),
1557 _ => builder.append_null(),
1558 }
1559 }
1560 Ok(ArrowVector::new(Arc::new(builder.finish()), phys_type))
1561 }
1562 PhysicalTypeID::Int32 => {
1563 let mut builder = arrow::array::Int32Builder::with_capacity(num_rows);
1564 for v in values {
1565 match v {
1566 Value::Null => builder.append_null(),
1567 Value::Int32(n) => builder.append_value(*n),
1568 _ => builder.append_null(),
1569 }
1570 }
1571 Ok(ArrowVector::new(Arc::new(builder.finish()), phys_type))
1572 }
1573 PhysicalTypeID::Double => {
1574 let mut builder = arrow::array::Float64Builder::with_capacity(num_rows);
1575 for v in values {
1576 match v {
1577 Value::Null => builder.append_null(),
1578 Value::Double(n) => builder.append_value(*n),
1579 _ => builder.append_null(),
1580 }
1581 }
1582 Ok(ArrowVector::new(Arc::new(builder.finish()), phys_type))
1583 }
1584 PhysicalTypeID::Float => {
1585 let mut builder = arrow::array::Float32Builder::with_capacity(num_rows);
1586 for v in values {
1587 match v {
1588 Value::Null => builder.append_null(),
1589 Value::Float(n) => builder.append_value(*n),
1590 Value::Double(n) => builder.append_value(*n as f32),
1591 _ => builder.append_null(),
1592 }
1593 }
1594 Ok(ArrowVector::new(Arc::new(builder.finish()), phys_type))
1595 }
1596 PhysicalTypeID::String => {
1597 let mut builder = arrow::array::StringBuilder::with_capacity(num_rows, num_rows * 16);
1598 for v in values {
1599 match v {
1600 Value::Null => builder.append_null(),
1601 Value::String(s) => builder.append_value(s),
1602 _ => builder.append_null(),
1603 }
1604 }
1605 Ok(ArrowVector::new(Arc::new(builder.finish()), phys_type))
1606 }
1607 _ => {
1608 let mut builder = arrow::array::Int64Builder::with_capacity(num_rows);
1610 builder.append_nulls(num_rows);
1611 Ok(ArrowVector::new(Arc::new(builder.finish()), PhysicalTypeID::Int64))
1612 }
1613 }
1614}
1615
1616impl ExpressionEvaluator {
1617 fn evaluate_sequence_op(
1620 &self,
1621 name: &str,
1622 func: &ScalarFunction,
1623 arg_vectors: &[ValueVector],
1624 num_rows: usize,
1625 ) -> Result<ValueVector, ProcessorError> {
1626 let is_nextval = match func {
1627 ScalarFunction::SequenceOp { is_nextval } => *is_nextval,
1628 _ => return Err(format!("Internal error: expected SequenceOp for '{}'", name).into()),
1629 };
1630
1631 let seq_fn = self
1632 .sequence_fn
1633 .as_ref()
1634 .ok_or_else(|| format!("No sequence callback configured for '{}'", name))?;
1635
1636 let mut result_vec = ValueVector::new(akar_common::types::PhysicalTypeID::Int64, num_rows);
1637 result_vec.resize(num_rows);
1638
1639 for row in 0..num_rows {
1640 let seq_name = if row < arg_vectors[0].size() && !arg_vectors[0].is_null(row) {
1641 match arg_vectors[0].get_value(row) {
1642 Some(Value::String(s)) => s,
1643 _ => return Err("nextval/currval requires a string argument (sequence name)".into()),
1644 }
1645 } else {
1646 result_vec.set_null(row, true);
1647 continue;
1648 };
1649
1650 match seq_fn(&seq_name, is_nextval) {
1651 Ok(val) => {
1652 store_value_in_vector(&mut result_vec, row, &val)?;
1653 }
1654 Err(e) => {
1655 result_vec.set_null(row, true);
1656 if row == 0 {
1657 return Err(e);
1658 }
1659 }
1660 }
1661 }
1662
1663 Ok(result_vec)
1664 }
1665}
1666
1667#[cfg(test)]
1668mod tests {
1669 use super::*;
1670 use akar_common::types::PhysicalTypeID;
1671 use akar_common::vector::ValueVector;
1672 use akar_function::registry::FunctionRegistry;
1673 use hashbrown::HashMap;
1674
1675 fn make_registry() -> Arc<Mutex<FunctionRegistry>> {
1676 Arc::new(Mutex::new(FunctionRegistry::new()))
1677 }
1678
1679 fn make_chunk(values: &[i64]) -> DataChunk {
1680 let mut v = ValueVector::new(PhysicalTypeID::Int64, values.len());
1681 v.resize(values.len());
1682 for (i, val) in values.iter().enumerate() {
1683 v.set_i64(i, *val);
1684 }
1685 {
1686 let arrow_fields = vec![akar_common::arrow_vector::ArrowVector::from_legacy(&v).array];
1687 let arrow_field_types = vec![v.physical_type()];
1688 DataChunk::new(arrow_fields, arrow_field_types)
1689 }
1690 }
1691
1692 #[test]
1693 fn test_evaluate_constant_int() {
1694 let eval = ExpressionEvaluator::new(make_registry());
1695 let expr = Expression::Constant(Constant::Integer(42));
1696 let chunk = make_chunk(&[]);
1697 let result = eval.evaluate(&expr, &chunk).unwrap();
1698 assert_eq!(result.size(), 0);
1699 }
1700
1701 #[test]
1702 fn test_evaluate_constant_bool() {
1703 let eval = ExpressionEvaluator::new(make_registry());
1704 let expr = Expression::Constant(Constant::Bool(true));
1705 let chunk = make_chunk(&[1, 2, 3]);
1706 let result = eval.evaluate(&expr, &chunk).unwrap();
1707 assert_eq!(result.size(), 3);
1708 for i in 0..3 {
1710 assert!(!result.is_null(i));
1711 }
1712 }
1713
1714 #[test]
1715 fn test_evaluate_variable() {
1716 let eval = ExpressionEvaluator::new(make_registry());
1717 let chunk = make_chunk(&[10, 20, 30]);
1718 let expr = Expression::Variable("0".into());
1719 let result = eval.evaluate(&expr, &chunk).unwrap();
1720 assert_eq!(result.size(), 3);
1721 assert_eq!(result.get_i64(0), Some(10));
1722 assert_eq!(result.get_i64(1), Some(20));
1723 assert_eq!(result.get_i64(2), Some(30));
1724 }
1725
1726 #[test]
1727 fn test_evaluate_binary_equal() {
1728 let eval = ExpressionEvaluator::new(make_registry());
1729 let left = Box::new(Expression::Variable("0".into()));
1731 let right = Box::new(Expression::Constant(Constant::Integer(0)));
1732 let expr = Expression::BinaryOp(BinaryOp::Equal, left, right);
1733 let chunk = make_chunk(&[0, 1, 2]);
1734 let result = eval.evaluate(&expr, &chunk).unwrap();
1735 assert_eq!(result.size(), 3);
1736 assert_eq!(result.get_value(0), Some(Value::Bool(true)));
1737 assert_eq!(result.get_value(1), Some(Value::Bool(false)));
1738 assert_eq!(result.get_value(2), Some(Value::Bool(false)));
1739 }
1740
1741 #[test]
1742 fn test_evaluate_binary_greater_than() {
1743 let eval = ExpressionEvaluator::new(make_registry());
1744 let left = Box::new(Expression::Variable("0".into()));
1746 let right = Box::new(Expression::Constant(Constant::Integer(2)));
1747 let expr = Expression::BinaryOp(BinaryOp::GreaterThan, left, right);
1748 let chunk = make_chunk(&[3, 1, 5]);
1749 let result = eval.evaluate(&expr, &chunk).unwrap();
1750 assert_eq!(result.size(), 3);
1751 assert_eq!(result.get_value(0), Some(Value::Bool(true)));
1752 assert_eq!(result.get_value(1), Some(Value::Bool(false)));
1753 assert_eq!(result.get_value(2), Some(Value::Bool(true)));
1754 }
1755
1756 #[test]
1757 fn test_evaluate_binary_and() {
1758 let eval = ExpressionEvaluator::new(make_registry());
1759 let mut v0 = ValueVector::new(PhysicalTypeID::Bool, 2);
1761 v0.resize(2);
1762 store_value_in_vector(&mut v0, 0, &Value::Bool(true)).unwrap();
1763 store_value_in_vector(&mut v0, 1, &Value::Bool(false)).unwrap();
1764 let mut v1 = ValueVector::new(PhysicalTypeID::Bool, 2);
1765 v1.resize(2);
1766 store_value_in_vector(&mut v1, 0, &Value::Bool(true)).unwrap();
1767 store_value_in_vector(&mut v1, 1, &Value::Bool(true)).unwrap();
1768 let chunk = {
1769 let arrow_fields = vec![
1770 akar_common::arrow_vector::ArrowVector::from_legacy(&v0).array,
1771 akar_common::arrow_vector::ArrowVector::from_legacy(&v1).array,
1772 ];
1773 let arrow_field_types = vec![v0.physical_type(), v1.physical_type()];
1774 DataChunk::new(arrow_fields, arrow_field_types)
1775 };
1776
1777 let left = Box::new(Expression::Variable("0".into()));
1779 let right = Box::new(Expression::Variable("1".into()));
1780 let expr = Expression::BinaryOp(BinaryOp::And, left, right);
1781 let result = eval.evaluate(&expr, &chunk).unwrap();
1782 assert_eq!(result.size(), 2);
1783 assert_eq!(result.get_value(0), Some(Value::Bool(true)));
1784 assert_eq!(result.get_value(1), Some(Value::Bool(false)));
1785 }
1786
1787 #[test]
1788 fn test_evaluate_function_call_string_length() {
1789 let eval = ExpressionEvaluator::new(make_registry());
1790 let chunk = akar_common::vector::DataChunk::new(vec![], vec![]);
1791 let expr = Expression::FunctionCall(
1792 "length".into(),
1793 vec![Expression::Constant(Constant::String("hello".into()))],
1794 );
1795 let result = eval.evaluate(&expr, &chunk).unwrap();
1796 assert_eq!(result.size(), 0);
1797 }
1798
1799 #[test]
1800 fn test_evaluate_not() {
1801 let eval = ExpressionEvaluator::new(make_registry());
1802 let mut v = ValueVector::new(PhysicalTypeID::Bool, 3);
1803 v.resize(3);
1804 store_value_in_vector(&mut v, 0, &Value::Bool(true)).unwrap();
1805 store_value_in_vector(&mut v, 1, &Value::Bool(false)).unwrap();
1806 store_value_in_vector(&mut v, 2, &Value::Bool(true)).unwrap();
1807 let chunk = {
1808 let arrow_fields = vec![akar_common::arrow_vector::ArrowVector::from_legacy(&v).array];
1809 let arrow_field_types = vec![v.physical_type()];
1810 DataChunk::new(arrow_fields, arrow_field_types)
1811 };
1812 let expr = Expression::UnaryOp(UnaryOp::Not, Box::new(Expression::Variable("0".into())));
1814 let result = eval.evaluate(&expr, &chunk).unwrap();
1815 assert_eq!(result.size(), 3);
1816 assert_eq!(result.get_value(0), Some(Value::Bool(false)));
1817 assert_eq!(result.get_value(1), Some(Value::Bool(true)));
1818 assert_eq!(result.get_value(2), Some(Value::Bool(false)));
1819 }
1820
1821 #[test]
1822 fn test_sequence_nextval_currval_with_callback() {
1823 let state = Arc::new(Mutex::new(HashMap::new()));
1824 state.lock().unwrap().insert("my_seq".to_string(), 10_i64);
1825
1826 let state_for_fn = state.clone();
1827 let seq_fn: Arc<dyn Fn(&str, bool) -> Result<Value, ProcessorError> + Send + Sync> =
1828 Arc::new(move |seq_name: &str, is_nextval: bool| {
1829 let mut map = state_for_fn.lock().map_err(|e| format!("Lock error: {e}"))?;
1830 let current = map
1831 .get_mut(seq_name)
1832 .ok_or_else(|| format!("Sequence '{}' not found", seq_name))?;
1833 if is_nextval {
1834 let out = *current;
1835 *current += 2;
1836 Ok(Value::Int64(out))
1837 } else {
1838 Ok(Value::Int64(*current))
1839 }
1840 });
1841
1842 let eval = ExpressionEvaluator::new(make_registry()).with_sequence_fn(seq_fn);
1843 let chunk = make_chunk(&[1, 2, 3]);
1844
1845 let nextval_expr = Expression::FunctionCall(
1846 "nextval".into(),
1847 vec![Expression::Constant(Constant::String("my_seq".into()))],
1848 );
1849 let nextvals = eval.evaluate(&nextval_expr, &chunk).unwrap();
1850 assert_eq!(nextvals.get_value(0), Some(Value::Int64(10)));
1851 assert_eq!(nextvals.get_value(1), Some(Value::Int64(12)));
1852 assert_eq!(nextvals.get_value(2), Some(Value::Int64(14)));
1853
1854 let currval_expr = Expression::FunctionCall(
1855 "currval".into(),
1856 vec![Expression::Constant(Constant::String("my_seq".into()))],
1857 );
1858 let curr = eval.evaluate(&currval_expr, &make_chunk(&[1])).unwrap();
1859 assert_eq!(curr.get_value(0), Some(Value::Int64(16)));
1860 }
1861
1862 #[test]
1863 fn test_sequence_requires_callback() {
1864 let eval = ExpressionEvaluator::new(make_registry());
1865 let expr = Expression::FunctionCall(
1866 "nextval".into(),
1867 vec![Expression::Constant(Constant::String("my_seq".into()))],
1868 );
1869 let err = eval.evaluate(&expr, &make_chunk(&[1])).unwrap_err();
1870 assert!(
1871 err.to_string().contains("No sequence callback configured"),
1872 "Unexpected error: {err}"
1873 );
1874 }
1875
1876 #[test]
1877 fn test_sequence_requires_string_arg() {
1878 let seq_fn: Arc<dyn Fn(&str, bool) -> Result<Value, ProcessorError> + Send + Sync> =
1879 Arc::new(|_seq_name: &str, _is_nextval: bool| Ok(Value::Int64(1)));
1880 let eval = ExpressionEvaluator::new(make_registry()).with_sequence_fn(seq_fn);
1881
1882 let expr = Expression::FunctionCall("nextval".into(), vec![Expression::Constant(Constant::Integer(42))]);
1883 let err = eval.evaluate(&expr, &make_chunk(&[1])).unwrap_err();
1884 assert!(
1885 err.to_string().contains("requires a string argument"),
1886 "Unexpected error: {err}"
1887 );
1888 }
1889}