1mod arith;
5mod cast;
6mod compare;
7mod conditional;
8mod construct;
9mod contains;
10mod direct;
11mod error;
12mod field_access;
13mod in_list;
14mod literal;
15mod prefix;
16mod routine;
17mod schema;
18mod variant;
19mod xor;
20
21use std::sync::Arc;
22
23use arrow_array::{ArrayRef, RecordBatch, RecordBatchOptions, new_empty_array};
24use arrow_schema::{FieldRef, SchemaRef};
25use datafusion_expr::{
26 BinaryExpr, Expr, Operator, ScalarUDF, ScalarUDFImpl, Signature, Volatility, execution_props::ExecutionProps,
27 expr::ScalarFunction, physical_planning_context::PhysicalPlanningContext,
28};
29use datafusion_physical_expr::{PhysicalExpr, create_physical_expr};
30use reifydb_core::{
31 expression::{Expression, PrefixExpression, PrefixOperator, name::display_label},
32 internal_error,
33 value::column::{arith::ArithOp, factory::default_typed},
34};
35use reifydb_runtime::sync::mutex::Mutex;
36use reifydb_value::{
37 error::{BinaryOp, Diagnostic, Error, LogicalOp},
38 fragment::Fragment,
39 value::{
40 column_view::ColumnView,
41 value_type::{
42 ValueType,
43 field::{FieldType, from_field, to_field},
44 },
45 },
46};
47
48use crate::{
49 Result,
50 expression::{context::EvalContext, logic::execute_logical_op, prefix::prefix_apply},
51 lower::{
52 cast::lower_cast,
53 direct::{Direct, Spliced},
54 error::from_datafusion,
55 schema::positional_schema,
56 },
57};
58
59pub struct LoweredExpr {
60 expression: Expression,
61 operator: &'static str,
62 state: Mutex<Option<Arc<Ready>>>,
63}
64
65struct Ready {
66 schema: SchemaRef,
67 plan: Plan,
68}
69
70enum Plan {
71 Lowered {
72 expr: Arc<dyn PhysicalExpr>,
73 field: FieldRef,
74 },
75 Direct(Direct),
76 Spliced(Spliced),
77 Failed(Box<Diagnostic>),
78}
79
80struct Node {
81 expr: Expr,
82 field: FieldRef,
83}
84
85enum Stop {
86 RowChanging,
87 Error(Error),
88}
89
90impl From<Error> for Stop {
91 fn from(error: Error) -> Self {
92 Stop::Error(error)
93 }
94}
95
96type Lowered<T> = std::result::Result<T, Stop>;
97
98pub fn compile_check(expression: &Expression) -> Result<()> {
99 match variant::compile_time_error(expression) {
100 Some(error) => Err(error),
101 None => Ok(()),
102 }
103}
104
105impl LoweredExpr {
106 pub fn new(expression: Expression, operator: &'static str) -> Self {
107 Self {
108 expression,
109 operator,
110 state: Mutex::new(None),
111 }
112 }
113
114 pub fn access_column_name(&self) -> Option<&str> {
115 match &self.expression {
116 Expression::AccessSource(access) => Some(access.column.name.text()),
117 _ => None,
118 }
119 }
120
121 pub fn evaluate(&self, ctx: &EvalContext) -> Result<(FieldRef, ArrayRef)> {
122 let ready = self.ready(ctx);
123 match &ready.plan {
124 Plan::Lowered {
125 expr,
126 field,
127 } => {
128 let sized;
129 let batch = if ctx.batch.num_columns() == 0 && ctx.batch.num_rows() != ctx.row_count {
130 sized = RecordBatch::try_new_with_options(
131 ctx.batch.schema(),
132 vec![],
133 &RecordBatchOptions::new().with_row_count(Some(ctx.row_count)),
134 )
135 .map_err(|err| from_datafusion(self.operator, err.into()))?;
136 &sized
137 } else {
138 &ctx.batch
139 };
140 let value = expr.evaluate(batch).map_err(|err| from_datafusion(self.operator, err))?;
141 let array = value
142 .into_array(ctx.row_count)
143 .map_err(|err| from_datafusion(self.operator, err))?;
144 let array = match ctx.take {
145 Some(take) if take < array.len() => array.slice(0, take),
146 _ => array,
147 };
148 if !field.is_nullable() && array.logical_null_count() > 0 {
149 let mut field_type = from_field(field)?;
150 field_type.value_type = field_type
151 .value_type
152 .map(|value_type| ValueType::Option(Box::new(value_type)));
153 return Ok((Arc::new(to_field(field.name(), &field_type)), array));
154 }
155 Ok((field.clone(), array))
156 }
157 Plan::Direct(direct) => direct.evaluate(ctx),
158 Plan::Spliced(spliced) => spliced.evaluate(ctx),
159 Plan::Failed(diagnostic) => Err(Error(diagnostic.clone())),
160 }
161 }
162
163 pub fn output_field(&self, ctx: &EvalContext) -> Option<FieldRef> {
164 match &self.ready(ctx).plan {
165 Plan::Lowered {
166 field,
167 ..
168 } => Some(field.clone()),
169 Plan::Direct(_) | Plan::Spliced(_) | Plan::Failed(_) => None,
170 }
171 }
172
173 fn ready(&self, ctx: &EvalContext) -> Arc<Ready> {
174 let schema = ctx.batch.schema();
175 let mut state = self.state.lock();
176 if let Some(ready) = state.as_ref()
177 && same_schema(&ready.schema, &schema)
178 {
179 return ready.clone();
180 }
181 let ready = Arc::new(Ready {
182 plan: self.plan(ctx),
183 schema,
184 });
185 if !matches!(ready.plan, Plan::Failed(_)) {
186 *state = Some(ready.clone());
187 }
188 ready
189 }
190
191 fn plan(&self, ctx: &EvalContext) -> Plan {
192 match lower_root(ctx, self.operator, &self.expression) {
193 Ok((expr, field)) => Plan::Lowered {
194 expr,
195 field,
196 },
197 Err(Stop::Error(error)) => Plan::Failed(error.0),
198 Err(Stop::RowChanging) => {
199 let planned = match &self.expression {
200 Expression::Call(_) => {
201 Direct::new(ctx, self.operator, &self.expression).map(Plan::Direct)
202 }
203 Expression::Alias(alias)
204 if matches!(alias.expression.as_ref(), Expression::Call(_)) =>
205 {
206 Direct::new(ctx, self.operator, &self.expression).map(Plan::Direct)
207 }
208 _ => Spliced::new(ctx, self.operator, &self.expression).map(Plan::Spliced),
209 };
210 planned.unwrap_or_else(|error| Plan::Failed(error.0))
211 }
212 }
213 }
214}
215
216fn same_schema(left: &SchemaRef, right: &SchemaRef) -> bool {
217 Arc::ptr_eq(left, right) || left == right
218}
219
220fn lower_root<'e>(
221 ctx: &EvalContext,
222 operator: &'static str,
223 expression: &'e Expression,
224) -> Lowered<(Arc<dyn PhysicalExpr>, FieldRef)> {
225 if let Some(error) = variant::compile_time_error(expression) {
226 return Err(Stop::Error(error));
227 }
228 let node = lower_node(ctx, operator, expression)?;
229 let schema = positional_schema(operator, ctx.batch.schema_ref())?;
230 let expr =
231 create_physical_expr(&node.expr, &schema, &ExecutionProps::new(), &PhysicalPlanningContext::default())
232 .map_err(|err| from_datafusion(operator, err))?;
233 Ok((expr, node.field))
234}
235
236fn lower_node<'e>(ctx: &EvalContext, operator: &'static str, expression: &'e Expression) -> Lowered<Node> {
237 match expression {
238 Expression::Column(column) => Ok(schema::column(ctx, operator, column)?),
239 Expression::AccessSource(access) => Ok(schema::access(ctx, access)?),
240 Expression::Constant(constant) => {
241 Ok(literal::constant(operator, constant, display_label(expression).text())?)
242 }
243 Expression::Prefix(prefix) => match prefix.operator {
244 PrefixOperator::Not(_) => lower_not(ctx, operator, expression, prefix),
245 PrefixOperator::Minus(_) | PrefixOperator::Plus(_) => {
246 prefix::lower_prefix(ctx, operator, expression, prefix)
247 }
248 },
249 Expression::And(and) => lower_logical(
250 ctx,
251 operator,
252 expression,
253 (&and.left, &and.right),
254 &and.full_fragment_owned(),
255 (LogicalOp::And, Operator::And),
256 ),
257 Expression::Or(or) => lower_logical(
258 ctx,
259 operator,
260 expression,
261 (&or.left, &or.right),
262 &or.full_fragment_owned(),
263 (LogicalOp::Or, Operator::Or),
264 ),
265 Expression::Equal(e) => compare::lower_compare(
266 ctx,
267 operator,
268 expression,
269 (&e.left, &e.right),
270 e.full_fragment_owned(),
271 (BinaryOp::Equal, Operator::Eq),
272 ),
273 Expression::NotEqual(e) => compare::lower_compare(
274 ctx,
275 operator,
276 expression,
277 (&e.left, &e.right),
278 e.full_fragment_owned(),
279 (BinaryOp::NotEqual, Operator::NotEq),
280 ),
281 Expression::LessThan(e) => compare::lower_compare(
282 ctx,
283 operator,
284 expression,
285 (&e.left, &e.right),
286 e.full_fragment_owned(),
287 (BinaryOp::LessThan, Operator::Lt),
288 ),
289 Expression::LessThanEqual(e) => compare::lower_compare(
290 ctx,
291 operator,
292 expression,
293 (&e.left, &e.right),
294 e.full_fragment_owned(),
295 (BinaryOp::LessThanEqual, Operator::LtEq),
296 ),
297 Expression::GreaterThan(e) => compare::lower_compare(
298 ctx,
299 operator,
300 expression,
301 (&e.left, &e.right),
302 e.full_fragment_owned(),
303 (BinaryOp::GreaterThan, Operator::Gt),
304 ),
305 Expression::GreaterThanEqual(e) => compare::lower_compare(
306 ctx,
307 operator,
308 expression,
309 (&e.left, &e.right),
310 e.full_fragment_owned(),
311 (BinaryOp::GreaterThanEqual, Operator::GtEq),
312 ),
313 Expression::Between(e) => compare::lower_between(ctx, operator, expression, e),
314 Expression::Add(e) => arith::lower_arith(
315 ctx,
316 operator,
317 expression,
318 (&e.left, &e.right),
319 e.full_fragment_owned(),
320 ArithOp::Add,
321 ),
322 Expression::Sub(e) => arith::lower_arith(
323 ctx,
324 operator,
325 expression,
326 (&e.left, &e.right),
327 e.full_fragment_owned(),
328 ArithOp::Sub,
329 ),
330 Expression::Mul(e) => arith::lower_arith(
331 ctx,
332 operator,
333 expression,
334 (&e.left, &e.right),
335 e.full_fragment_owned(),
336 ArithOp::Mul,
337 ),
338 Expression::Div(e) => arith::lower_arith(
339 ctx,
340 operator,
341 expression,
342 (&e.left, &e.right),
343 e.full_fragment_owned(),
344 ArithOp::Div,
345 ),
346 Expression::Rem(e) => arith::lower_arith(
347 ctx,
348 operator,
349 expression,
350 (&e.left, &e.right),
351 e.full_fragment_owned(),
352 ArithOp::Rem,
353 ),
354 Expression::Call(call) => routine::lower_call(ctx, operator, expression, call),
355 Expression::Variable(variable) => Ok(literal::variable(ctx, operator, variable)?),
356 Expression::Parameter(parameter) => Ok(literal::parameter(ctx, operator, parameter)?),
357 Expression::Type(ty) => Ok(literal::type_literal(operator, &ty.ty, &ty.fragment)?),
358 Expression::FieldAccess(access) => match access.object.as_ref() {
359 Expression::Variable(variable) => {
360 Ok(literal::variable_field(ctx, operator, variable, access.field.text())?)
361 }
362 _ => field_access::lower_field_access(ctx, operator, expression, access),
363 },
364 Expression::Alias(alias) => {
365 let inner = lower_node(ctx, operator, &alias.expression)?;
366 Ok(Node {
367 expr: inner.expr,
368 field: Arc::new(inner.field.as_ref().clone().with_name(alias.alias.name())),
369 })
370 }
371 Expression::Cast(cast) => lower_cast(ctx, operator, expression, cast),
372 Expression::In(e) => in_list::lower_in(ctx, operator, expression, e),
373 Expression::If(e) => conditional::lower_if(ctx, operator, expression, e),
374 Expression::Xor(e) => xor::lower_xor(ctx, operator, expression, e),
375 Expression::Tuple(e) => construct::lower_construct(
376 ctx,
377 operator,
378 construct::Shape::Tuple,
379 e.expressions.iter().collect(),
380 &e.fragment,
381 ),
382 Expression::List(e) => construct::lower_construct(
383 ctx,
384 operator,
385 construct::Shape::List,
386 e.expressions.iter().collect(),
387 &e.fragment,
388 ),
389 Expression::Record(e) => construct::lower_construct(
390 ctx,
391 operator,
392 construct::Shape::Record(e.fields.iter().map(|(name, _)| name.text().to_string()).collect()),
393 e.fields.iter().map(|(_, expression)| expression).collect(),
394 &e.fragment,
395 ),
396 Expression::Map(e) => construct::lower_projection(ctx, operator, &e.expressions, &e.fragment),
397 Expression::Extend(e) => construct::lower_projection(ctx, operator, &e.expressions, &e.fragment),
398 Expression::Contains(e) => contains::lower_contains(ctx, operator, expression, e),
399 Expression::IsVariant(e) => Ok(variant::lower_is_variant(ctx, operator, e)?),
400 Expression::SumTypeConstructor(_) => Err(Stop::Error(
401 variant::compile_time_error(expression).expect("a sum type constructor is a compile error"),
402 )),
403 }
404}
405
406fn lower_logical<'e>(
407 ctx: &EvalContext,
408 operator: &'static str,
409 expression: &'e Expression,
410 (left, right): (&'e Expression, &'e Expression),
411 fragment: &Fragment,
412 (logical_op, df_op): (LogicalOp, Operator),
413) -> Lowered<Node> {
414 let left = lower_node(ctx, operator, left)?;
415 let right = lower_node(ctx, operator, right)?;
416 execute_logical_op(&logic_probe(&left.field)?, &logic_probe(&right.field)?, fragment, logical_op)?;
417 let nullable = left.field.is_nullable() || right.field.is_nullable();
418 Ok(Node {
419 expr: Expr::BinaryExpr(BinaryExpr::new(
420 Box::new(bool_operand(left)?),
421 df_op,
422 Box::new(bool_operand(right)?),
423 )),
424 field: bool_field(display_label(expression).text(), nullable),
425 })
426}
427
428fn lower_not<'e>(
429 ctx: &EvalContext,
430 operator: &'static str,
431 expression: &'e Expression,
432 prefix: &'e PrefixExpression,
433) -> Lowered<Node> {
434 let inner = lower_node(ctx, operator, &prefix.expression)?;
435 if !is_untyped_none(&inner.field)? {
436 let fragment = prefix.full_fragment_owned();
437 prefix_apply(&empty_of(&inner.field), &prefix.operator, &fragment)?;
438 if let Some(value_type) = from_field(&inner.field)?.value_type {
439 prefix_apply(&default_typed("probe", value_type, 1), &prefix.operator, &fragment)?;
440 }
441 }
442 let nullable = inner.field.is_nullable();
443 Ok(Node {
444 expr: Expr::Not(Box::new(bool_operand(inner)?)),
445 field: bool_field(display_label(expression).text(), nullable),
446 })
447}
448
449fn logic_probe(field: &FieldRef) -> Result<(FieldRef, ArrayRef)> {
450 if is_untyped_none(field)? {
451 return Ok(empty_of(&bool_field("none", true)));
452 }
453 Ok(empty_of(&Arc::new(field.as_ref().clone().with_nullable(false))))
454}
455
456fn bool_operand(node: Node) -> Result<Expr> {
457 if is_untyped_none(&node.field)? {
458 return Ok(literal::none_bool());
459 }
460 Ok(node.expr)
461}
462
463fn is_untyped_none(field: &FieldRef) -> Result<bool> {
464 Ok(ColumnView::try_from(&empty_of(field))?.is_untyped_none())
465}
466
467fn inner_type(field: &FieldRef) -> Result<ValueType> {
468 match from_field(field)?.value_type {
469 Some(value_type) => Ok(value_type.inner_type().clone()),
470 None => Err(internal_error!("operand {} has no value type", field.name())),
471 }
472}
473
474fn empty_of(field: &FieldRef) -> (FieldRef, ArrayRef) {
475 (field.clone(), new_empty_array(field.data_type()))
476}
477
478fn bool_field(name: &str, nullable: bool) -> FieldRef {
479 typed_field(name, ValueType::Boolean, nullable)
480}
481
482fn typed_field(name: &str, value_type: ValueType, nullable: bool) -> FieldRef {
483 let value_type = match nullable {
484 true => ValueType::Option(Box::new(value_type)),
485 false => value_type,
486 };
487 Arc::new(to_field(name, &FieldType::from(value_type)))
488}
489
490fn udf(function: impl ScalarUDFImpl + 'static, args: Vec<Expr>) -> Expr {
491 Expr::ScalarFunction(ScalarFunction::new_udf(Arc::new(ScalarUDF::new_from_impl(function)), args))
492}
493
494fn volatile() -> Signature {
495 Signature::user_defined(Volatility::Volatile)
496}