Skip to main content

reifydb_engine/expression/
compile.rs

1// SPDX-License-Identifier: AGPL-3.0-or-later
2// Copyright (c) 2025 ReifyDB
3
4use reifydb_core::value::column::{Column, data::ColumnData};
5use reifydb_rql::expression::Expression;
6use reifydb_type::{
7	error,
8	error::diagnostic::{
9		cast,
10		operator::{
11			and_can_not_applied_to_number, and_can_not_applied_to_temporal, and_can_not_applied_to_text,
12			and_can_not_applied_to_uuid, between_cannot_be_applied_to_incompatible_types,
13			equal_cannot_be_applied_to_incompatible_types,
14			greater_than_cannot_be_applied_to_incompatible_types,
15			greater_than_equal_cannot_be_applied_to_incompatible_types,
16			less_than_cannot_be_applied_to_incompatible_types,
17			less_than_equal_cannot_be_applied_to_incompatible_types,
18			not_equal_cannot_be_applied_to_incompatible_types, or_can_not_applied_to_number,
19			or_can_not_applied_to_temporal, or_can_not_applied_to_text, or_can_not_applied_to_uuid,
20			xor_can_not_applied_to_number, xor_can_not_applied_to_temporal, xor_can_not_applied_to_text,
21			xor_can_not_applied_to_uuid,
22		},
23		runtime::{variable_is_dataframe, variable_not_found},
24	},
25	fragment::Fragment,
26	return_error,
27	value::{Value, r#type::Type},
28};
29
30use super::context::CompileContext;
31use crate::{
32	expression::{
33		arith::{add::add_columns, div::div_columns, mul::mul_columns, rem::rem_columns, sub::sub_columns},
34		call::call_eval,
35		cast::cast_column_data,
36		compare::{Equal, GreaterThan, GreaterThanEqual, LessThan, LessThanEqual, NotEqual, compare_columns},
37		constant::{constant_value, constant_value_of},
38		context::EvalContext,
39		lookup::column_lookup,
40	},
41	vm::stack::Variable,
42};
43
44pub struct CompiledExpr {
45	inner: CompiledExprInner,
46	access_column_name: Option<String>,
47}
48
49enum CompiledExprInner {
50	Single(Box<dyn Fn(&EvalContext) -> crate::Result<Column> + Send + Sync>),
51	Multi(Box<dyn Fn(&EvalContext) -> crate::Result<Vec<Column>> + Send + Sync>),
52}
53
54impl CompiledExpr {
55	pub fn new(f: impl Fn(&EvalContext) -> crate::Result<Column> + Send + Sync + 'static) -> Self {
56		Self {
57			inner: CompiledExprInner::Single(Box::new(f)),
58			access_column_name: None,
59		}
60	}
61
62	pub fn new_multi(f: impl Fn(&EvalContext) -> crate::Result<Vec<Column>> + Send + Sync + 'static) -> Self {
63		Self {
64			inner: CompiledExprInner::Multi(Box::new(f)),
65			access_column_name: None,
66		}
67	}
68
69	pub fn new_access(
70		name: String,
71		f: impl Fn(&EvalContext) -> crate::Result<Column> + Send + Sync + 'static,
72	) -> Self {
73		Self {
74			inner: CompiledExprInner::Single(Box::new(f)),
75			access_column_name: Some(name),
76		}
77	}
78
79	pub fn access_column_name(&self) -> Option<&str> {
80		self.access_column_name.as_deref()
81	}
82
83	pub fn execute(&self, ctx: &EvalContext) -> crate::Result<Column> {
84		match &self.inner {
85			CompiledExprInner::Single(f) => f(ctx),
86			CompiledExprInner::Multi(f) => {
87				let columns = f(ctx)?;
88				Ok(columns.into_iter().next().unwrap_or_else(|| Column {
89					name: Fragment::internal("none"),
90					data: ColumnData::with_capacity(Type::Option(Box::new(Type::Boolean)), 0),
91				}))
92			}
93		}
94	}
95
96	pub fn execute_multi(&self, ctx: &EvalContext) -> crate::Result<Vec<Column>> {
97		match &self.inner {
98			CompiledExprInner::Single(f) => Ok(vec![f(ctx)?]),
99			CompiledExprInner::Multi(f) => f(ctx),
100		}
101	}
102}
103
104/// Compile an `Expression` into a `CompiledExpr`.
105///
106/// All execution logic is baked into closures at compile time — no match dispatch at runtime.
107pub fn compile_expression(_ctx: &CompileContext, expr: &Expression) -> crate::Result<CompiledExpr> {
108	Ok(match expr {
109		Expression::Constant(e) => {
110			let expr = e.clone();
111			CompiledExpr::new(move |ctx| {
112				let row_count = ctx.take.unwrap_or(ctx.row_count);
113				Ok(Column {
114					name: expr.full_fragment_owned(),
115					data: constant_value(&expr, row_count)?,
116				})
117			})
118		}
119
120		Expression::Column(e) => {
121			let expr = e.clone();
122			CompiledExpr::new(move |ctx| column_lookup(ctx, &expr))
123		}
124
125		Expression::Variable(e) => {
126			let expr = e.clone();
127			CompiledExpr::new(move |ctx| {
128				let variable_name = expr.name();
129
130				if variable_name == "env" {
131					return_error!(variable_is_dataframe(variable_name));
132				}
133
134				match ctx.symbol_table.get(variable_name) {
135					Some(Variable::Scalar(columns)) => {
136						let value = columns.scalar_value();
137						let mut data =
138							ColumnData::with_capacity(value.get_type(), ctx.row_count);
139						for _ in 0..ctx.row_count {
140							data.push_value(value.clone());
141						}
142						Ok(Column {
143							name: Fragment::internal(variable_name),
144							data,
145						})
146					}
147					Some(Variable::Columns(_))
148					| Some(Variable::ForIterator {
149						..
150					}) => {
151						return_error!(variable_is_dataframe(variable_name));
152					}
153					None => {
154						return_error!(variable_not_found(variable_name));
155					}
156				}
157			})
158		}
159
160		Expression::Parameter(e) => {
161			let expr = e.clone();
162			CompiledExpr::new(move |ctx| crate::expression::parameter::parameter_lookup(ctx, &expr))
163		}
164
165		Expression::Alias(e) => {
166			let inner = compile_expression(_ctx, &e.expression)?;
167			let alias = e.alias.0.clone();
168			CompiledExpr::new(move |ctx| {
169				let mut column = inner.execute(ctx)?;
170				column.name = alias.clone();
171				Ok(column)
172			})
173		}
174
175		Expression::Add(e) => {
176			let left = compile_expression(_ctx, &e.left)?;
177			let right = compile_expression(_ctx, &e.right)?;
178			let fragment = e.full_fragment_owned();
179			CompiledExpr::new(move |ctx| {
180				let l = left.execute(ctx)?;
181				let r = right.execute(ctx)?;
182				add_columns(ctx, &l, &r, || fragment.clone())
183			})
184		}
185
186		Expression::Sub(e) => {
187			let left = compile_expression(_ctx, &e.left)?;
188			let right = compile_expression(_ctx, &e.right)?;
189			let fragment = e.full_fragment_owned();
190			CompiledExpr::new(move |ctx| {
191				let l = left.execute(ctx)?;
192				let r = right.execute(ctx)?;
193				sub_columns(ctx, &l, &r, || fragment.clone())
194			})
195		}
196
197		Expression::Mul(e) => {
198			let left = compile_expression(_ctx, &e.left)?;
199			let right = compile_expression(_ctx, &e.right)?;
200			let fragment = e.full_fragment_owned();
201			CompiledExpr::new(move |ctx| {
202				let l = left.execute(ctx)?;
203				let r = right.execute(ctx)?;
204				mul_columns(ctx, &l, &r, || fragment.clone())
205			})
206		}
207
208		Expression::Div(e) => {
209			let left = compile_expression(_ctx, &e.left)?;
210			let right = compile_expression(_ctx, &e.right)?;
211			let fragment = e.full_fragment_owned();
212			CompiledExpr::new(move |ctx| {
213				let l = left.execute(ctx)?;
214				let r = right.execute(ctx)?;
215				div_columns(ctx, &l, &r, || fragment.clone())
216			})
217		}
218
219		Expression::Rem(e) => {
220			let left = compile_expression(_ctx, &e.left)?;
221			let right = compile_expression(_ctx, &e.right)?;
222			let fragment = e.full_fragment_owned();
223			CompiledExpr::new(move |ctx| {
224				let l = left.execute(ctx)?;
225				let r = right.execute(ctx)?;
226				rem_columns(ctx, &l, &r, || fragment.clone())
227			})
228		}
229
230		Expression::Equal(e) => {
231			let left = compile_expression(_ctx, &e.left)?;
232			let right = compile_expression(_ctx, &e.right)?;
233			let fragment = e.full_fragment_owned();
234			CompiledExpr::new(move |ctx| {
235				let l = left.execute(ctx)?;
236				let r = right.execute(ctx)?;
237				let result = compare_columns::<Equal>(
238					&l,
239					&r,
240					fragment.clone(),
241					equal_cannot_be_applied_to_incompatible_types,
242				);
243				result
244			})
245		}
246
247		Expression::NotEqual(e) => {
248			let left = compile_expression(_ctx, &e.left)?;
249			let right = compile_expression(_ctx, &e.right)?;
250			let fragment = e.full_fragment_owned();
251			CompiledExpr::new(move |ctx| {
252				let l = left.execute(ctx)?;
253				let r = right.execute(ctx)?;
254				let result = compare_columns::<NotEqual>(
255					&l,
256					&r,
257					fragment.clone(),
258					not_equal_cannot_be_applied_to_incompatible_types,
259				);
260				result
261			})
262		}
263
264		Expression::GreaterThan(e) => {
265			let left = compile_expression(_ctx, &e.left)?;
266			let right = compile_expression(_ctx, &e.right)?;
267			let fragment = e.full_fragment_owned();
268			CompiledExpr::new(move |ctx| {
269				let l = left.execute(ctx)?;
270				let r = right.execute(ctx)?;
271				let result = compare_columns::<GreaterThan>(
272					&l,
273					&r,
274					fragment.clone(),
275					greater_than_cannot_be_applied_to_incompatible_types,
276				);
277				result
278			})
279		}
280
281		Expression::GreaterThanEqual(e) => {
282			let left = compile_expression(_ctx, &e.left)?;
283			let right = compile_expression(_ctx, &e.right)?;
284			let fragment = e.full_fragment_owned();
285			CompiledExpr::new(move |ctx| {
286				let l = left.execute(ctx)?;
287				let r = right.execute(ctx)?;
288				let result = compare_columns::<GreaterThanEqual>(
289					&l,
290					&r,
291					fragment.clone(),
292					greater_than_equal_cannot_be_applied_to_incompatible_types,
293				);
294				result
295			})
296		}
297
298		Expression::LessThan(e) => {
299			let left = compile_expression(_ctx, &e.left)?;
300			let right = compile_expression(_ctx, &e.right)?;
301			let fragment = e.full_fragment_owned();
302			CompiledExpr::new(move |ctx| {
303				let l = left.execute(ctx)?;
304				let r = right.execute(ctx)?;
305				let result = compare_columns::<LessThan>(
306					&l,
307					&r,
308					fragment.clone(),
309					less_than_cannot_be_applied_to_incompatible_types,
310				);
311				result
312			})
313		}
314
315		Expression::LessThanEqual(e) => {
316			let left = compile_expression(_ctx, &e.left)?;
317			let right = compile_expression(_ctx, &e.right)?;
318			let fragment = e.full_fragment_owned();
319			CompiledExpr::new(move |ctx| {
320				let l = left.execute(ctx)?;
321				let r = right.execute(ctx)?;
322				let result = compare_columns::<LessThanEqual>(
323					&l,
324					&r,
325					fragment.clone(),
326					less_than_equal_cannot_be_applied_to_incompatible_types,
327				);
328				result
329			})
330		}
331
332		Expression::And(e) => {
333			let left = compile_expression(_ctx, &e.left)?;
334			let right = compile_expression(_ctx, &e.right)?;
335			let fragment = e.full_fragment_owned();
336			CompiledExpr::new(move |ctx| {
337				let l = left.execute(ctx)?;
338				let r = right.execute(ctx)?;
339				let result = execute_and(&l, &r, &fragment);
340				result
341			})
342		}
343
344		Expression::Or(e) => {
345			let left = compile_expression(_ctx, &e.left)?;
346			let right = compile_expression(_ctx, &e.right)?;
347			let fragment = e.full_fragment_owned();
348			CompiledExpr::new(move |ctx| {
349				let l = left.execute(ctx)?;
350				let r = right.execute(ctx)?;
351				let result = execute_or(&l, &r, &fragment);
352				result
353			})
354		}
355
356		Expression::Xor(e) => {
357			let left = compile_expression(_ctx, &e.left)?;
358			let right = compile_expression(_ctx, &e.right)?;
359			let fragment = e.full_fragment_owned();
360			CompiledExpr::new(move |ctx| {
361				let l = left.execute(ctx)?;
362				let r = right.execute(ctx)?;
363				let result = execute_xor(&l, &r, &fragment);
364				result
365			})
366		}
367
368		Expression::Prefix(e) => {
369			let expr = e.clone();
370			CompiledExpr::new(move |ctx| {
371				crate::expression::prefix::prefix_eval(ctx, &expr, ctx.functions, ctx.clock)
372			})
373		}
374
375		Expression::Type(e) => {
376			let ty = e.ty.clone();
377			let fragment = e.fragment.clone();
378			CompiledExpr::new(move |ctx| {
379				let row_count = ctx.take.unwrap_or(ctx.row_count);
380				let values: Vec<Box<Value>> =
381					(0..row_count).map(|_| Box::new(Value::Type(ty.clone()))).collect();
382				Ok(Column::new(fragment.text(), ColumnData::any(values)))
383			})
384		}
385
386		Expression::AccessSource(e) => {
387			let col_name = e.column.name.text().to_string();
388			let expr = e.clone();
389			CompiledExpr::new_access(col_name, move |ctx| {
390				crate::expression::access::access_lookup(ctx, &expr)
391			})
392		}
393
394		Expression::Tuple(e) => {
395			if e.expressions.len() == 1 {
396				let inner = compile_expression(_ctx, &e.expressions[0])?;
397				CompiledExpr::new(move |ctx| inner.execute(ctx))
398			} else {
399				unimplemented!("Multi-element tuple evaluation not yet supported: {:?}", e)
400			}
401		}
402
403		Expression::Between(e) => {
404			let value = compile_expression(_ctx, &e.value)?;
405			let lower = compile_expression(_ctx, &e.lower)?;
406			let upper = compile_expression(_ctx, &e.upper)?;
407			let fragment = e.fragment.clone();
408			CompiledExpr::new(move |ctx| {
409				let value_col = value.execute(ctx)?;
410				let lower_col = lower.execute(ctx)?;
411				let upper_col = upper.execute(ctx)?;
412
413				let ge_result = compare_columns::<GreaterThanEqual>(
414					&value_col,
415					&lower_col,
416					fragment.clone(),
417					greater_than_equal_cannot_be_applied_to_incompatible_types,
418				)?;
419				let le_result = compare_columns::<LessThanEqual>(
420					&value_col,
421					&upper_col,
422					fragment.clone(),
423					less_than_equal_cannot_be_applied_to_incompatible_types,
424				)?;
425
426				if !matches!(ge_result.data(), ColumnData::Bool(_))
427					|| !matches!(le_result.data(), ColumnData::Bool(_))
428				{
429					return_error!(between_cannot_be_applied_to_incompatible_types(
430						fragment.clone(),
431						value_col.get_type(),
432						lower_col.get_type(),
433					))
434				}
435
436				match (ge_result.data(), le_result.data()) {
437					(ColumnData::Bool(ge_container), ColumnData::Bool(le_container)) => {
438						let mut data = Vec::with_capacity(ge_container.len());
439						let mut bitvec = Vec::with_capacity(ge_container.len());
440
441						for i in 0..ge_container.len() {
442							if ge_container.is_defined(i) && le_container.is_defined(i) {
443								data.push(ge_container.data().get(i)
444									&& le_container.data().get(i));
445								bitvec.push(true);
446							} else {
447								data.push(false);
448								bitvec.push(false);
449							}
450						}
451
452						Ok(Column {
453							name: fragment.clone(),
454							data: ColumnData::bool_with_bitvec(data, bitvec),
455						})
456					}
457					_ => unreachable!(
458						"Both comparison results should be boolean after the check above"
459					),
460				}
461			})
462		}
463
464		Expression::In(e) => {
465			let list_expressions = match e.list.as_ref() {
466				Expression::Tuple(tuple) => &tuple.expressions,
467				_ => std::slice::from_ref(e.list.as_ref()),
468			};
469			let value = compile_expression(_ctx, &e.value)?;
470			let list: Vec<CompiledExpr> = list_expressions
471				.iter()
472				.map(|expr| compile_expression(_ctx, expr))
473				.collect::<crate::Result<Vec<_>>>()?;
474			let negated = e.negated;
475			let fragment = e.fragment.clone();
476			CompiledExpr::new(move |ctx| {
477				if list.is_empty() {
478					let value_col = value.execute(ctx)?;
479					let len = value_col.data().len();
480					let result = vec![negated; len];
481					return Ok(Column {
482						name: fragment.clone(),
483						data: ColumnData::bool(result),
484					});
485				}
486
487				let value_col = value.execute(ctx)?;
488
489				let first_col = list[0].execute(ctx)?;
490				let mut result = compare_columns::<Equal>(
491					&value_col,
492					&first_col,
493					fragment.clone(),
494					equal_cannot_be_applied_to_incompatible_types,
495				)?;
496
497				for list_expr in list.iter().skip(1) {
498					let list_col = list_expr.execute(ctx)?;
499					let eq_result = compare_columns::<Equal>(
500						&value_col,
501						&list_col,
502						fragment.clone(),
503						equal_cannot_be_applied_to_incompatible_types,
504					)?;
505					result = or_columns(result, eq_result, fragment.clone())?;
506				}
507
508				if negated {
509					result = negate_column(result, fragment.clone());
510				}
511
512				Ok(result)
513			})
514		}
515
516		Expression::Cast(e) => {
517			if let Expression::Constant(const_expr) = e.expression.as_ref() {
518				let const_expr = const_expr.clone();
519				let target_type = e.to.ty.clone();
520				CompiledExpr::new(move |ctx| {
521					let row_count = ctx.take.unwrap_or(ctx.row_count);
522					let data = constant_value(&const_expr, row_count)?;
523					let casted = if data.get_type() == target_type {
524						data
525					} else {
526						constant_value_of(&const_expr, target_type.clone(), row_count)?
527					};
528					Ok(Column {
529						name: const_expr.full_fragment_owned(),
530						data: casted,
531					})
532				})
533			} else {
534				let inner = compile_expression(_ctx, &e.expression)?;
535				let target_type = e.to.ty.clone();
536				let inner_fragment = e.expression.full_fragment_owned();
537				CompiledExpr::new(move |ctx| {
538					let column = inner.execute(ctx)?;
539					let frag = inner_fragment.clone();
540					let casted =
541						cast_column_data(ctx, &column.data(), target_type.clone(), &|| {
542							inner_fragment.clone()
543						})
544						.map_err(|e| {
545							error!(cast::invalid_number(
546								frag,
547								target_type.clone(),
548								e.diagnostic()
549							))
550						})?;
551					Ok(Column {
552						name: column.name_owned(),
553						data: casted,
554					})
555				})
556			}
557		}
558
559		Expression::If(e) => {
560			let condition = compile_expression(_ctx, &e.condition)?;
561			let then_expr = compile_expressions(_ctx, std::slice::from_ref(e.then_expr.as_ref()))?;
562			let else_ifs: Vec<(CompiledExpr, Vec<CompiledExpr>)> = e
563				.else_ifs
564				.iter()
565				.map(|ei| {
566					Ok((
567						compile_expression(_ctx, &ei.condition)?,
568						compile_expressions(_ctx, std::slice::from_ref(ei.then_expr.as_ref()))?,
569					))
570				})
571				.collect::<crate::Result<Vec<_>>>()?;
572			let else_branch: Option<Vec<CompiledExpr>> = match &e.else_expr {
573				Some(expr) => Some(compile_expressions(_ctx, std::slice::from_ref(expr.as_ref()))?),
574				None => None,
575			};
576			let fragment = e.fragment.clone();
577			CompiledExpr::new_multi(move |ctx| {
578				execute_if_multi(ctx, &condition, &then_expr, &else_ifs, &else_branch, &fragment)
579			})
580		}
581
582		Expression::Map(e) => {
583			let expressions = compile_expressions(_ctx, &e.expressions)?;
584			CompiledExpr::new_multi(move |ctx| execute_map_multi(ctx, &expressions))
585		}
586
587		Expression::Extend(e) => {
588			let expressions = compile_expressions(_ctx, &e.expressions)?;
589			CompiledExpr::new_multi(move |ctx| execute_extend_multi(ctx, &expressions))
590		}
591
592		Expression::Call(e) => {
593			let expr = e.clone();
594			CompiledExpr::new(move |ctx| call_eval(ctx, &expr, ctx.functions, ctx.clock))
595		}
596
597		Expression::SumTypeConstructor(_) => {
598			panic!(
599				"SumTypeConstructor in expression context — constructors should be expanded by InlineDataNode before expression compilation"
600			);
601		}
602
603		Expression::IsVariant(e) => {
604			let col_name = match e.expression.as_ref() {
605				Expression::Column(c) => c.0.name.text().to_string(),
606				other => other.full_fragment_owned().text().to_string(),
607			};
608			let tag_col_name = format!("{}_tag", col_name);
609			let tag = e.tag.expect("IS variant tag must be resolved before compilation");
610			let fragment = e.fragment.clone();
611			CompiledExpr::new(move |ctx| {
612				if let Some(tag_col) =
613					ctx.columns.iter().find(|c| c.name().text() == tag_col_name.as_str())
614				{
615					match tag_col.data() {
616						ColumnData::Uint1(container) => {
617							let results: Vec<bool> = container
618								.iter()
619								.take(ctx.row_count)
620								.map(|v| v == Some(tag))
621								.collect();
622							Ok(Column {
623								name: fragment.clone(),
624								data: ColumnData::bool(results),
625							})
626						}
627						_ => Ok(Column {
628							name: fragment.clone(),
629							data: ColumnData::none_typed(Type::Boolean, ctx.row_count),
630						}),
631					}
632				} else {
633					Ok(Column {
634						name: fragment.clone(),
635						data: ColumnData::none_typed(Type::Boolean, ctx.row_count),
636					})
637				}
638			})
639		}
640	})
641}
642
643fn compile_expressions(ctx: &CompileContext, exprs: &[Expression]) -> crate::Result<Vec<CompiledExpr>> {
644	exprs.iter().map(|e| compile_expression(ctx, e)).collect()
645}
646
647// --- Helper functions (moved from execute.rs) ---
648
649fn execute_and(left: &Column, right: &Column, fragment: &Fragment) -> crate::Result<Column> {
650	super::option::binary_op_unwrap_option(left, right, fragment.clone(), |left, right| {
651		match (&left.data(), &right.data()) {
652			(ColumnData::Bool(l_container), ColumnData::Bool(r_container)) => {
653				let data: Vec<bool> = l_container
654					.data()
655					.iter()
656					.zip(r_container.data().iter())
657					.map(|(l_val, r_val)| l_val && r_val)
658					.collect();
659
660				Ok(Column {
661					name: fragment.clone(),
662					data: ColumnData::bool(data),
663				})
664			}
665			(l, r) => {
666				if l.is_number() || r.is_number() {
667					return_error!(and_can_not_applied_to_number(fragment.clone()));
668				} else if l.is_text() || r.is_text() {
669					return_error!(and_can_not_applied_to_text(fragment.clone()));
670				} else if l.is_temporal() || r.is_temporal() {
671					return_error!(and_can_not_applied_to_temporal(fragment.clone()));
672				} else if l.is_uuid() || r.is_uuid() {
673					return_error!(and_can_not_applied_to_uuid(fragment.clone()));
674				} else {
675					unimplemented!("{} and {}", l.get_type(), r.get_type());
676				}
677			}
678		}
679	})
680}
681
682fn execute_or(left: &Column, right: &Column, fragment: &Fragment) -> crate::Result<Column> {
683	super::option::binary_op_unwrap_option(left, right, fragment.clone(), |left, right| {
684		match (&left.data(), &right.data()) {
685			(ColumnData::Bool(l_container), ColumnData::Bool(r_container)) => {
686				let data: Vec<bool> = l_container
687					.data()
688					.iter()
689					.zip(r_container.data().iter())
690					.map(|(l_val, r_val)| l_val || r_val)
691					.collect();
692
693				Ok(Column {
694					name: fragment.clone(),
695					data: ColumnData::bool(data),
696				})
697			}
698			(l, r) => {
699				if l.is_number() || r.is_number() {
700					return_error!(or_can_not_applied_to_number(fragment.clone()));
701				} else if l.is_text() || r.is_text() {
702					return_error!(or_can_not_applied_to_text(fragment.clone()));
703				} else if l.is_temporal() || r.is_temporal() {
704					return_error!(or_can_not_applied_to_temporal(fragment.clone()));
705				} else if l.is_uuid() || r.is_uuid() {
706					return_error!(or_can_not_applied_to_uuid(fragment.clone()));
707				} else {
708					unimplemented!("{} or {}", l.get_type(), r.get_type());
709				}
710			}
711		}
712	})
713}
714
715fn execute_xor(left: &Column, right: &Column, fragment: &Fragment) -> crate::Result<Column> {
716	super::option::binary_op_unwrap_option(left, right, fragment.clone(), |left, right| {
717		match (&left.data(), &right.data()) {
718			(ColumnData::Bool(l_container), ColumnData::Bool(r_container)) => {
719				let data: Vec<bool> = l_container
720					.data()
721					.iter()
722					.zip(r_container.data().iter())
723					.map(|(l_val, r_val)| l_val != r_val)
724					.collect();
725
726				Ok(Column {
727					name: fragment.clone(),
728					data: ColumnData::bool(data),
729				})
730			}
731			(l, r) => {
732				if l.is_number() || r.is_number() {
733					return_error!(xor_can_not_applied_to_number(fragment.clone()));
734				} else if l.is_text() || r.is_text() {
735					return_error!(xor_can_not_applied_to_text(fragment.clone()));
736				} else if l.is_temporal() || r.is_temporal() {
737					return_error!(xor_can_not_applied_to_temporal(fragment.clone()));
738				} else if l.is_uuid() || r.is_uuid() {
739					return_error!(xor_can_not_applied_to_uuid(fragment.clone()));
740				} else {
741					unimplemented!("{} xor {}", l.get_type(), r.get_type());
742				}
743			}
744		}
745	})
746}
747
748fn or_columns(left: Column, right: Column, fragment: Fragment) -> crate::Result<Column> {
749	super::option::binary_op_unwrap_option(&left, &right, fragment.clone(), |left, right| {
750		match (left.data(), right.data()) {
751			(ColumnData::Bool(l), ColumnData::Bool(r)) => {
752				let len = l.len();
753				let mut data = Vec::with_capacity(len);
754				let mut bitvec = Vec::with_capacity(len);
755
756				for i in 0..len {
757					let l_defined = l.is_defined(i);
758					let r_defined = r.is_defined(i);
759					let l_val = l.data().get(i);
760					let r_val = r.data().get(i);
761
762					if l_defined && r_defined {
763						data.push(l_val || r_val);
764						bitvec.push(true);
765					} else {
766						data.push(false);
767						bitvec.push(false);
768					}
769				}
770
771				Ok(Column {
772					name: fragment.clone(),
773					data: ColumnData::bool_with_bitvec(data, bitvec),
774				})
775			}
776			_ => {
777				unreachable!(
778					"OR columns should only be called with boolean columns from equality comparisons"
779				)
780			}
781		}
782	})
783}
784
785fn negate_column(col: Column, fragment: Fragment) -> Column {
786	super::option::unary_op_unwrap_option(&col, |col| match col.data() {
787		ColumnData::Bool(container) => {
788			let len = container.len();
789			let mut data = Vec::with_capacity(len);
790			let mut bitvec = Vec::with_capacity(len);
791
792			for i in 0..len {
793				if container.is_defined(i) {
794					data.push(!container.data().get(i));
795					bitvec.push(true);
796				} else {
797					data.push(false);
798					bitvec.push(false);
799				}
800			}
801
802			Ok(Column {
803				name: fragment.clone(),
804				data: ColumnData::bool_with_bitvec(data, bitvec),
805			})
806		}
807		_ => unreachable!("negate_column should only be called with boolean columns"),
808	})
809	.unwrap()
810}
811
812fn is_truthy(value: &Value) -> bool {
813	match value {
814		Value::Boolean(true) => true,
815		Value::Boolean(false) => false,
816		Value::None {
817			..
818		} => false,
819		Value::Int1(0) | Value::Int2(0) | Value::Int4(0) | Value::Int8(0) | Value::Int16(0) => false,
820		Value::Uint1(0) | Value::Uint2(0) | Value::Uint4(0) | Value::Uint8(0) | Value::Uint16(0) => false,
821		Value::Int1(_) | Value::Int2(_) | Value::Int4(_) | Value::Int8(_) | Value::Int16(_) => true,
822		Value::Uint1(_) | Value::Uint2(_) | Value::Uint4(_) | Value::Uint8(_) | Value::Uint16(_) => true,
823		Value::Utf8(s) => !s.is_empty(),
824		_ => true,
825	}
826}
827
828fn execute_if_multi(
829	ctx: &EvalContext,
830	condition: &CompiledExpr,
831	then_expr: &[CompiledExpr],
832	else_ifs: &[(CompiledExpr, Vec<CompiledExpr>)],
833	else_branch: &Option<Vec<CompiledExpr>>,
834	_fragment: &Fragment,
835) -> crate::Result<Vec<Column>> {
836	let condition_column = condition.execute(ctx)?;
837
838	let mut result_data: Option<Vec<ColumnData>> = None;
839	let mut result_names: Vec<Fragment> = Vec::new();
840
841	for row_idx in 0..ctx.row_count {
842		let condition_value = condition_column.data().get_value(row_idx);
843
844		let branch_results = if is_truthy(&condition_value) {
845			execute_multi_exprs(ctx, then_expr)?
846		} else {
847			let mut found_branch = false;
848			let mut branch_columns = None;
849
850			for (else_if_condition, else_if_then) in else_ifs {
851				let else_if_col = else_if_condition.execute(ctx)?;
852				let else_if_value = else_if_col.data().get_value(row_idx);
853
854				if is_truthy(&else_if_value) {
855					branch_columns = Some(execute_multi_exprs(ctx, else_if_then)?);
856					found_branch = true;
857					break;
858				}
859			}
860
861			if found_branch {
862				branch_columns.unwrap()
863			} else if let Some(else_exprs) = else_branch {
864				execute_multi_exprs(ctx, else_exprs)?
865			} else {
866				vec![]
867			}
868		};
869
870		// Handle empty branch results (from empty blocks like `{}` or no-branch-taken)
871		let is_empty_result = branch_results.is_empty();
872		if is_empty_result {
873			if let Some(data) = result_data.as_mut() {
874				for col_data in data.iter_mut() {
875					col_data.push_value(Value::none());
876				}
877			}
878			continue;
879		}
880
881		// Initialize from first non-empty branch, backfilling previous empty rows
882		if result_data.is_none() {
883			let mut data: Vec<ColumnData> = branch_results
884				.iter()
885				.map(|col| ColumnData::with_capacity(col.data().get_type(), ctx.row_count))
886				.collect();
887			for _ in 0..row_idx {
888				for col_data in data.iter_mut() {
889					col_data.push_value(Value::none());
890				}
891			}
892			result_data = Some(data);
893			result_names = branch_results.iter().map(|col| col.name.clone()).collect();
894		}
895
896		let data = result_data.as_mut().unwrap();
897		for (i, branch_col) in branch_results.iter().enumerate() {
898			if i < data.len() {
899				let branch_value = branch_col.data().get_value(row_idx);
900				data[i].push_value(branch_value);
901			}
902		}
903	}
904
905	let result_data = result_data.unwrap_or_default();
906	let result: Vec<Column> = result_data
907		.into_iter()
908		.enumerate()
909		.map(|(i, data)| Column {
910			name: result_names.get(i).cloned().unwrap_or_else(|| Fragment::internal("column")),
911			data,
912		})
913		.collect();
914
915	if result.is_empty() {
916		Ok(vec![Column {
917			name: Fragment::internal("none"),
918			data: ColumnData::none_typed(Type::Boolean, ctx.row_count),
919		}])
920	} else {
921		Ok(result)
922	}
923}
924
925fn execute_multi_exprs(ctx: &EvalContext, exprs: &[CompiledExpr]) -> crate::Result<Vec<Column>> {
926	let mut result = Vec::new();
927	for expr in exprs {
928		result.extend(expr.execute_multi(ctx)?);
929	}
930	Ok(result)
931}
932
933fn execute_map_multi(ctx: &EvalContext, expressions: &[CompiledExpr]) -> crate::Result<Vec<Column>> {
934	let mut result = Vec::with_capacity(expressions.len());
935
936	for expr in expressions {
937		let column = expr.execute(ctx)?;
938		let name = column.name.text().to_string();
939		result.push(Column {
940			name: Fragment::internal(name),
941			data: column.data,
942		});
943	}
944
945	Ok(result)
946}
947
948fn execute_extend_multi(ctx: &EvalContext, expressions: &[CompiledExpr]) -> crate::Result<Vec<Column>> {
949	let mut result = Vec::with_capacity(expressions.len());
950
951	for expr in expressions {
952		let column = expr.execute(ctx)?;
953		let name = column.name.text().to_string();
954		result.push(Column {
955			name: Fragment::internal(name),
956			data: column.data,
957		});
958	}
959
960	Ok(result)
961}