reifydb_evaluate/expression/
call.rs1use reifydb_core::value::column::{
5 ColumnWithName,
6 buffer::ColumnBuffer,
7 columns::Columns,
8 view::group_by::{GroupId, GroupRows},
9};
10use reifydb_routine_abi::{FunctionKind, context::FunctionContext, error::RoutineError};
11use reifydb_rql::expression::{CallExpression, Expression, name::display_label};
12use reifydb_value::{error::Error, fragment::Fragment, value::value_type::ValueType};
13
14use crate::{Result, error::EvaluateError, expression::context::EvalContext};
15
16pub(crate) fn call_builtin(ctx: &EvalContext, call: &CallExpression, arguments: Columns) -> Result<ColumnWithName> {
17 let function_name = call.func.0.text();
18 let fn_fragment = call.func.0.clone();
19 let result_label = display_label(&Expression::Call(call.clone()));
20
21 assert!(
22 ctx.symbols.get_function(function_name).is_none(),
23 "UDF '{}' should have been hoisted to UdfEvalNode",
24 function_name
25 );
26
27 let routine = ctx.routines.get_function(function_name).ok_or_else(|| -> Error {
28 EvaluateError::UnknownFunction {
29 name: function_name.to_string(),
30 fragment: fn_fragment.clone(),
31 }
32 .into()
33 })?;
34
35 let mut fn_ctx = FunctionContext {
36 fragment: fn_fragment.clone(),
37 identity: ctx.identity,
38 row_count: ctx.row_count,
39 runtime_context: ctx.runtime_context,
40 };
41
42 if ctx.is_aggregate_context && routine.kinds().contains(&FunctionKind::Aggregate) {
43 let mut accumulator =
44 routine.accumulator(&mut fn_ctx).ok_or_else(|| RoutineError::FunctionExecutionFailed {
45 function: fn_fragment.clone(),
46 reason: format!("Function {} is not an aggregate", function_name),
47 })?;
48
49 let column = if call.args.is_empty() {
50 ColumnWithName {
51 name: Fragment::internal("dummy"),
52 data: ColumnBuffer::with_capacity(ValueType::Int4, ctx.row_count),
53 }
54 } else {
55 ColumnWithName::new(arguments.name_at(0).clone(), arguments[0].clone())
56 };
57
58 let all_rows: GroupRows = vec![(GroupId(0), (0..ctx.row_count).collect())];
59
60 accumulator
61 .update(&Columns::new(vec![column]), &all_rows)
62 .map_err(|e| e.with_context(fn_fragment.clone(), false))?;
63
64 let (_keys, result_data) = accumulator.finalize().map_err(|e| e.with_context(fn_fragment, false))?;
65
66 return Ok(ColumnWithName::new(result_label.clone(), result_data));
67 }
68
69 let result_columns = routine.call(&mut fn_ctx, &arguments).map_err(|e| e.with_context(fn_fragment, false))?;
70
71 if result_columns.is_empty() {
72 return Err(RoutineError::FunctionExecutionFailed {
73 function: call.func.0.clone(),
74 reason: "Function returned no columns".to_string(),
75 }
76 .into());
77 }
78 let result_data = result_columns.data_at(0).clone();
79 Ok(ColumnWithName::new(result_label, result_data))
80}