1use std::cell::Cell;
27use std::sync::Arc;
28
29use radixdb_core::CompactArc;
30use radixdb_core::SmartString;
31use radixdb_core::StringMap;
32use rustc_hash::{FxHashMap, FxHashSet};
33
34use super::execution_context::ExecuteContext;
35use super::ops::{CompiledPattern, Op};
36use super::program::{Program, ProgramBuilder};
37use super::vm::ExprVM;
38use radixdb_core::{DataType, Row, Value, ValueSet};
39use radixdb_functions::{global_registry, FunctionRegistry};
40use radixdb_sql::ast::*;
41
42pub fn string_to_datatype(type_str: &str) -> DataType {
45 let upper = type_str.to_uppercase();
46 let base_type = upper.split('(').next().unwrap_or(&upper).trim();
47 match base_type {
48 "INTEGER" | "INT" | "BIGINT" | "SMALLINT" | "TINYINT" => DataType::Integer,
49 "FLOAT" | "DOUBLE" | "REAL" => DataType::Float,
50 "DECIMAL" | "NUMERIC" => DataType::Decimal,
51 "TEXT" | "VARCHAR" | "CHAR" | "STRING" | "CLOB" => DataType::Text,
52 "BOOLEAN" | "BOOL" => DataType::Boolean,
53 "TIMESTAMP" | "DATETIME" | "TIME" => DataType::Timestamp,
54 "DATE" => DataType::Date,
55 "JSON" | "JSONB" => DataType::Json,
56 "UUID" => DataType::Uuid,
57 "BYTES" | "BLOB" | "BINARY" | "VARBINARY" => DataType::Bytes,
58 "VECTOR" => DataType::Vector,
59 _ => DataType::Text,
60 }
61}
62
63pub fn expression_to_string(expr: &Expression) -> String {
65 match expr {
66 Expression::Identifier(id) => id.value.to_string(),
67 Expression::QualifiedIdentifier(qid) => {
68 format!("{}.{}", qid.qualifier.value, qid.name.value)
69 }
70 Expression::IntegerLiteral(lit) => lit.value.to_string(),
71 Expression::FloatLiteral(lit) => lit.value.to_string(),
72 Expression::StringLiteral(lit) => format!("'{}'", lit.value),
73 Expression::BooleanLiteral(lit) => lit.value.to_string(),
74 Expression::FunctionCall(func) => {
75 let args: Vec<String> = func.arguments.iter().map(expression_to_string).collect();
76 format!("{}({})", func.function, args.join(", "))
77 }
78 Expression::Infix(infix) => format!(
79 "{} {} {}",
80 expression_to_string(&infix.left),
81 infix.operator,
82 expression_to_string(&infix.right)
83 ),
84 _ => format!("{expr}"),
85 }
86}
87
88#[derive(Debug, Clone)]
90pub enum CompileError {
91 ColumnNotFound(String),
93 FunctionNotFound(String),
95 InvalidExpression(String),
97 UnsupportedExpression(String),
99 TypeError(String),
101}
102
103impl std::fmt::Display for CompileError {
104 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
105 match self {
106 CompileError::ColumnNotFound(name) => {
107 write!(f, "Column '{}' not found", name)
108 }
109 CompileError::FunctionNotFound(name) => write!(f, "Function not found: {}", name),
110 CompileError::InvalidExpression(msg) => write!(f, "Invalid expression: {}", msg),
111 CompileError::UnsupportedExpression(msg) => {
112 write!(f, "Unsupported expression: {}", msg)
113 }
114 CompileError::TypeError(msg) => write!(f, "Type error: {}", msg),
115 }
116 }
117}
118
119impl std::error::Error for CompileError {}
120
121#[derive(Debug, Clone, Copy)]
123pub enum ColumnSource {
124 Row1(u16),
126 Row2(u16),
128}
129
130pub struct CompileContext<'a> {
137 columns: StringMap<u16>,
139
140 qualified_columns: StringMap<StringMap<ColumnSource>>,
144
145 columns2: Option<StringMap<u16>>,
147
148 row2_tables: FxHashSet<String>,
150
151 outer_columns: Option<FxHashMap<CompactArc<str>, u16>>,
153
154 functions: &'a FunctionRegistry,
156
157 expression_aliases: StringMap<u16>,
159
160 column_aliases: StringMap<String>,
162
163 invalid_context: Option<String>,
166}
167
168impl<'a> CompileContext<'a> {
169 pub fn new(columns: &[String], functions: &'a FunctionRegistry) -> Self {
171 let invalid_context = (columns.len() > (u16::MAX as usize + 1)).then(|| {
172 format!(
173 "primary row has {} columns; expression bytecode supports at most {}",
174 columns.len(),
175 u16::MAX as usize + 1
176 )
177 });
178 let mut col_map = StringMap::new();
179 let mut qualified_map: StringMap<StringMap<ColumnSource>> = StringMap::new();
180
181 for (i, col) in columns.iter().enumerate() {
182 let Ok(index) = u16::try_from(i) else {
183 continue;
184 };
185 let lower = col.to_lowercase();
186 col_map.insert(lower.clone(), index);
187
188 if let Some(dot_idx) = col.rfind('.') {
190 let table = col[..dot_idx].to_lowercase();
191 let column = col[dot_idx + 1..].to_lowercase();
192 qualified_map
193 .entry(table)
194 .or_default()
195 .insert(column.clone(), ColumnSource::Row1(index));
196
197 col_map.entry(column).or_insert(index);
200 }
201 }
202
203 Self {
204 columns: col_map,
205 qualified_columns: qualified_map,
206 columns2: None,
207 row2_tables: FxHashSet::default(),
208 outer_columns: None,
209 functions,
210 expression_aliases: StringMap::new(),
211 column_aliases: StringMap::new(),
212 invalid_context,
213 }
214 }
215
216 pub fn with_global_registry(columns: &[String]) -> Self {
218 Self::new(columns, global_registry())
219 }
220
221 pub fn with_second_row(mut self, columns2: &[String]) -> Self {
223 if columns2.len() > (u16::MAX as usize + 1) {
224 self.invalid_context = Some(format!(
225 "second row has {} columns; expression bytecode supports at most {}",
226 columns2.len(),
227 u16::MAX as usize + 1
228 ));
229 }
230 let mut col_map = StringMap::new();
231 for (i, col) in columns2.iter().enumerate() {
232 let Ok(index) = u16::try_from(i) else {
233 continue;
234 };
235 let lower = col.to_lowercase();
236 col_map.insert(lower.clone(), index);
237
238 if let Some(dot_idx) = col.rfind('.') {
240 let table = col[..dot_idx].to_lowercase();
241 let column = col[dot_idx + 1..].to_lowercase();
242
243 self.row2_tables.insert(table.clone());
245
246 self.qualified_columns
248 .entry(table)
249 .or_default()
250 .insert(column.clone(), ColumnSource::Row2(index));
251
252 col_map.entry(column).or_insert(index);
254 }
255 }
256 self.columns2 = Some(col_map);
257 self
258 }
259
260 pub fn with_outer_columns(mut self, outer_cols: &[String]) -> Self {
262 if outer_cols.len() > (u16::MAX as usize + 1) {
263 self.invalid_context = Some(format!(
264 "outer row has {} columns; expression bytecode supports at most {}",
265 outer_cols.len(),
266 u16::MAX as usize + 1
267 ));
268 }
269 let mut map = FxHashMap::default();
270 for (i, col) in outer_cols.iter().enumerate() {
271 if let Ok(index) = u16::try_from(i) {
272 map.insert(CompactArc::from(col.to_lowercase().as_str()), index);
273 }
274 }
275 self.outer_columns = Some(map);
276 self
277 }
278
279 pub fn with_expression_aliases(mut self, aliases: StringMap<u16>) -> Self {
281 self.expression_aliases = aliases;
282 self
283 }
284
285 pub fn with_column_aliases(mut self, aliases: StringMap<String>) -> Self {
287 self.column_aliases = aliases;
288 self
289 }
290
291 fn resolve_column(&self, name: &str) -> Option<ColumnSource> {
293 let lower = name.to_lowercase();
294
295 if let Some(original) = self.column_aliases.get(&lower) {
297 if let Some(&idx) = self.columns.get(original) {
298 return Some(ColumnSource::Row1(idx));
299 }
300 }
301
302 if let Some(&idx) = self.columns.get(&lower) {
304 return Some(ColumnSource::Row1(idx));
305 }
306
307 if let Some(ref cols2) = self.columns2 {
309 if let Some(&idx) = cols2.get(&lower) {
310 return Some(ColumnSource::Row2(idx));
311 }
312 }
313
314 None
315 }
316
317 fn resolve_qualified(&self, table: &str, column: &str) -> Option<ColumnSource> {
319 let table_lower = table.to_lowercase();
320 let column_lower = column.to_lowercase();
321
322 if let Some(table_cols) = self.qualified_columns.get(&table_lower) {
323 if let Some(&source) = table_cols.get(&column_lower) {
324 return Some(source);
325 }
326 }
327
328 if let Some(ref outer_cols) = self.outer_columns {
332 let qualified_name = format!("{}.{}", table_lower, column_lower);
333 if outer_cols.contains_key(qualified_name.as_str()) {
334 return None;
336 }
337 }
338
339 self.resolve_column(&column_lower)
341 }
342
343 fn resolve_outer_column(&self, name: &str) -> Option<CompactArc<str>> {
345 let lower = name.to_lowercase();
346 self.outer_columns.as_ref().and_then(|cols| {
347 if cols.contains_key(lower.as_str()) {
348 Some(CompactArc::from(lower.as_str()))
349 } else {
350 None
351 }
352 })
353 }
354
355 fn check_expression_alias(&self, expr: &Expression) -> Option<u16> {
357 if self.expression_aliases.is_empty() {
358 return None;
359 }
360 let expr_str = expression_to_string(expr).to_lowercase();
361 self.expression_aliases.get(&expr_str).copied()
362 }
363}
364
365pub struct ExprCompiler<'a> {
367 ctx: &'a CompileContext<'a>,
368 folding: Cell<bool>,
370}
371
372impl<'a> ExprCompiler<'a> {
373 pub fn new(ctx: &'a CompileContext<'a>) -> Self {
374 Self {
375 ctx,
376 folding: Cell::new(false),
377 }
378 }
379
380 pub fn compile(&self, expr: &Expression) -> Result<Program, CompileError> {
382 if let Some(error) = &self.ctx.invalid_context {
383 return Err(CompileError::InvalidExpression(error.clone()));
384 }
385 let mut builder = ProgramBuilder::new();
386 self.compile_expr(expr, &mut builder)?;
387 builder.emit(Op::Return);
388 if builder.is_overflowed() {
389 return Err(CompileError::InvalidExpression(
390 "expression bytecode exceeds the u16 instruction limit".to_string(),
391 ));
392 }
393 builder
394 .build()
395 .map_err(|error| CompileError::InvalidExpression(error.to_string()))
396 }
397
398 pub fn compile_filter(&self, expr: &Expression) -> Result<Program, CompileError> {
400 if let Some(error) = &self.ctx.invalid_context {
401 return Err(CompileError::InvalidExpression(error.clone()));
402 }
403 let mut builder = ProgramBuilder::new();
405 self.compile_expr(expr, &mut builder)?;
406 builder.emit(Op::Return);
407 if builder.is_overflowed() {
408 return Err(CompileError::InvalidExpression(
409 "expression bytecode exceeds the u16 instruction limit".to_string(),
410 ));
411 }
412 builder
413 .build()
414 .map_err(|error| CompileError::InvalidExpression(error.to_string()))
415 }
416
417 fn flatten_concat_chain_infix<'b>(
420 infix: &'b InfixExpression,
421 operands: &mut Vec<&'b Expression>,
422 ) {
423 if let Expression::Infix(left_infix) = &*infix.left {
425 if left_infix.op_type == InfixOperator::Concat {
426 Self::flatten_concat_chain_infix(left_infix, operands);
427 } else {
428 operands.push(&infix.left);
429 }
430 } else {
431 operands.push(&infix.left);
432 }
433 if let Expression::Infix(right_infix) = &*infix.right {
435 if right_infix.op_type == InfixOperator::Concat {
436 Self::flatten_concat_chain_infix(right_infix, operands);
437 } else {
438 operands.push(&infix.right);
439 }
440 } else {
441 operands.push(&infix.right);
442 }
443 }
444
445 fn try_fold_constant(&self, expr: &Expression) -> Option<Value> {
449 use std::cell::RefCell;
450
451 thread_local! {
452 static FOLD_VM: RefCell<ExprVM> = RefCell::new(ExprVM::new());
453 static FOLD_ROW: Row = Row::new();
454 }
455
456 self.folding.set(true);
457
458 let empty_cols: &[String] = &[];
459 let ctx = CompileContext::new(empty_cols, self.ctx.functions);
460 let compiler = ExprCompiler::new(&ctx);
461 compiler.folding.set(true);
462
463 let mut builder = ProgramBuilder::new();
464 let ok = compiler.compile_expr(expr, &mut builder);
465 self.folding.set(false);
466
467 ok.ok()?;
468 builder.emit(Op::Return);
469 let program = builder.build_unoptimized().ok()?;
470
471 FOLD_ROW.with(|empty_row| {
472 let exec_ctx = ExecuteContext::new(empty_row);
473 FOLD_VM.with(|vm_cell| {
474 let mut vm = vm_cell.borrow_mut();
475 vm.execute(&program, &exec_ctx).ok()
476 })
477 })
478 }
479
480 fn compile_expr(
482 &self,
483 expr: &Expression,
484 builder: &mut ProgramBuilder,
485 ) -> Result<(), CompileError> {
486 if let Some(idx) = self.ctx.check_expression_alias(expr) {
488 builder.emit(Op::LoadAggregateResult(idx));
489 return Ok(());
490 }
491
492 if !self.folding.get() && is_foldable_expr(expr, self.ctx.functions) {
498 if let Some(value) = self.try_fold_constant(expr) {
499 builder.emit(Op::LoadConst(value));
500 return Ok(());
501 }
502 }
503
504 match expr {
505 Expression::IntegerLiteral(lit) => {
507 builder.emit(Op::LoadConst(Value::Integer(lit.value)));
508 }
509
510 Expression::FloatLiteral(lit) => {
511 builder.emit(Op::LoadConst(Value::Float(lit.value)));
512 }
513
514 Expression::StringLiteral(lit) => {
515 let value = if let Some(ref hint) = lit.type_hint {
517 match hint.to_uppercase().as_str() {
518 "TIMESTAMP" | "DATETIME" => {
519 radixdb_core::value::parse_timestamp(&lit.value)
520 .map(Value::Timestamp)
521 .unwrap_or_else(|_| Value::Text(lit.value.clone()))
522 }
523 "DATE" => radixdb_core::value::parse_date_days_since_unix_epoch(&lit.value)
524 .map(Value::date)
525 .unwrap_or_else(|| Value::Text(lit.value.clone())),
526 _ => Value::Text(lit.value.clone()),
527 }
528 } else {
529 Value::Text(lit.value.clone())
530 };
531 builder.emit(Op::LoadConst(value));
532 }
533
534 Expression::BooleanLiteral(lit) => {
535 builder.emit(Op::LoadConst(Value::Boolean(lit.value)));
536 }
537
538 Expression::NullLiteral(_) => {
539 builder.emit(Op::LoadNull(DataType::Null));
540 }
541
542 Expression::BoundValue(value) => {
543 builder.emit(Op::LoadConst((**value).clone()));
544 }
545
546 Expression::Identifier(id) => {
548 match id.value_lower.as_str() {
551 "true" => {
552 builder.emit(Op::LoadConst(Value::Boolean(true)));
553 return Ok(());
554 }
555 "false" => {
556 builder.emit(Op::LoadConst(Value::Boolean(false)));
557 return Ok(());
558 }
559 _ => {}
560 }
561
562 if let Some(dot_idx) = id.value_lower.rfind('.') {
565 let table = &id.value_lower[..dot_idx];
567 let column = &id.value_lower[dot_idx + 1..];
568 if let Some(source) = self.ctx.resolve_qualified(table, column) {
569 match source {
570 ColumnSource::Row1(idx) => builder.emit(Op::LoadColumn(idx)),
571 ColumnSource::Row2(idx) => builder.emit(Op::LoadColumn2(idx)),
572 }
573 } else if let Some(name) = self.ctx.resolve_outer_column(column) {
574 builder.emit(Op::LoadOuterColumn(name));
575 } else {
576 return Err(CompileError::ColumnNotFound(id.value.to_string()));
577 }
578 } else if let Some(source) = self.ctx.resolve_column(&id.value_lower) {
579 match source {
580 ColumnSource::Row1(idx) => builder.emit(Op::LoadColumn(idx)),
581 ColumnSource::Row2(idx) => builder.emit(Op::LoadColumn2(idx)),
582 }
583 } else if let Some(name) = self.ctx.resolve_outer_column(&id.value_lower) {
584 builder.emit(Op::LoadOuterColumn(name));
585 } else {
586 return Err(CompileError::ColumnNotFound(id.value.to_string()));
587 }
588 }
589
590 Expression::QualifiedIdentifier(qid) => {
591 let table = &qid.qualifier.value_lower;
592 let column = &qid.name.value_lower;
593
594 if let Some(source) = self.ctx.resolve_qualified(table, column) {
595 match source {
596 ColumnSource::Row1(idx) => builder.emit(Op::LoadColumn(idx)),
597 ColumnSource::Row2(idx) => builder.emit(Op::LoadColumn2(idx)),
598 }
599 } else {
600 let qualified_name =
605 format!("{}.{}", table.to_lowercase(), column.to_lowercase());
606 if let Some(name) = self
607 .ctx
608 .resolve_outer_column(&qualified_name)
609 .or_else(|| self.ctx.resolve_outer_column(column))
610 {
611 builder.emit(Op::LoadOuterColumn(name));
612 } else {
613 return Err(CompileError::ColumnNotFound(format!(
614 "{}.{}",
615 table, column
616 )));
617 }
618 }
619 }
620
621 Expression::Parameter(param) => {
623 if param.name.starts_with(':') {
624 let name = ¶m.name[1..];
625 builder.emit(Op::LoadNamedParam(CompactArc::from(name)));
626 } else if param.index > 0 {
627 let index = u16::try_from(param.index - 1).map_err(|_| {
628 CompileError::InvalidExpression(
629 "parameter ordinal exceeds the u16 bytecode limit".to_string(),
630 )
631 })?;
632 builder.emit(Op::LoadParam(index));
633 } else {
634 return Err(CompileError::InvalidExpression(
635 "Invalid parameter".to_string(),
636 ));
637 }
638 }
639
640 Expression::Infix(infix) => {
642 self.compile_infix(infix, builder)?;
643 }
644
645 Expression::Prefix(prefix) => {
647 self.compile_prefix(prefix, builder)?;
648 }
649
650 Expression::In(in_expr) => {
652 self.compile_in(in_expr, builder)?;
653 }
654
655 Expression::InHashSet(in_hash) => {
656 self.compile_expr(&in_hash.column, builder)?;
657 let has_null = in_hash.values.iter().any(|v| v.is_null());
658 if in_hash.not {
659 builder.emit(Op::NotInSet(in_hash.values.clone(), has_null));
660 } else {
661 builder.emit(Op::InSet(in_hash.values.clone(), has_null));
662 }
663 }
664
665 Expression::Between(between) => {
667 self.compile_expr(&between.expr, builder)?;
668 self.compile_expr(&between.lower, builder)?;
669 self.compile_expr(&between.upper, builder)?;
670 if between.not {
671 builder.emit(Op::NotBetween);
672 } else {
673 builder.emit(Op::Between);
674 }
675 }
676
677 Expression::Like(like) => {
679 self.compile_like(like, builder)?;
680 }
681
682 Expression::Case(case) => {
684 self.compile_case(case, builder)?;
685 }
686
687 Expression::Cast(cast) => {
689 self.compile_expr(&cast.expr, builder)?;
690 if cast.type_name.contains('.') {
691 builder.emit(Op::CastExternal(CompactArc::from(cast.type_name.as_str())));
692 } else {
693 let dt = string_to_datatype(&cast.type_name);
694 builder.emit(Op::Cast(dt));
695 }
696 }
697
698 Expression::FunctionCall(func) => {
700 self.compile_function(func, builder)?;
701 }
702
703 Expression::Aliased(aliased) => {
705 self.compile_expr(&aliased.expression, builder)?;
706 }
707
708 Expression::Distinct(distinct) => {
710 self.compile_expr(&distinct.expr, builder)?;
711 }
712
713 Expression::List(_) | Expression::ExpressionList(_) => {
715 return Err(CompileError::InvalidExpression(
716 "tuple/list expressions are only valid in an IN predicate".to_string(),
717 ));
718 }
719
720 Expression::IntervalLiteral(interval) => {
722 let s = format!("{} {}", interval.quantity, interval.unit);
723 builder.emit(Op::LoadConst(Value::Text(SmartString::from_string(s))));
724 }
725
726 Expression::ScalarSubquery(_) | Expression::Exists(_) | Expression::AllAny(_) => {
728 return Err(CompileError::UnsupportedExpression(
729 "subqueries must be resolved by the query executor before VM compilation"
730 .to_string(),
731 ));
732 }
733
734 Expression::Window(_) => {
736 return Err(CompileError::UnsupportedExpression(
737 "Window functions require special execution context".to_string(),
738 ));
739 }
740
741 Expression::TableSource(_)
743 | Expression::JoinSource(_)
744 | Expression::SubquerySource(_)
745 | Expression::ValuesSource(_)
746 | Expression::CteReference(_)
747 | Expression::FunctionTableSource(_)
748 | Expression::Star(_)
749 | Expression::QualifiedStar(_)
750 | Expression::Default(_) => {
751 return Err(CompileError::InvalidExpression(
752 "unexpected table reference or '*' in expression context".to_string(),
753 ));
754 }
755 }
756
757 Ok(())
758 }
759
760 fn compile_infix(
762 &self,
763 infix: &InfixExpression,
764 builder: &mut ProgramBuilder,
765 ) -> Result<(), CompileError> {
766 match infix.op_type {
767 InfixOperator::And => {
769 self.compile_expr(&infix.left, builder)?;
771
772 let and_pos = builder.position();
774 builder.emit(Op::And(0)); self.compile_expr(&infix.right, builder)?;
778
779 builder.emit(Op::AndFinalize);
781
782 let end_pos = builder.position();
784 builder.patch_jump(and_pos as usize, end_pos);
785 }
786
787 InfixOperator::Or => {
789 self.compile_expr(&infix.left, builder)?;
791
792 let or_pos = builder.position();
794 builder.emit(Op::Or(0)); self.compile_expr(&infix.right, builder)?;
798
799 builder.emit(Op::OrFinalize);
801
802 let end_pos = builder.position();
804 builder.patch_jump(or_pos as usize, end_pos);
805 }
806
807 InfixOperator::Equal => {
809 self.compile_expr(&infix.left, builder)?;
810 self.compile_expr(&infix.right, builder)?;
811 builder.emit(Op::Eq);
812 }
813
814 InfixOperator::NotEqual => {
815 self.compile_expr(&infix.left, builder)?;
816 self.compile_expr(&infix.right, builder)?;
817 builder.emit(Op::Ne);
818 }
819
820 InfixOperator::LessThan => {
821 self.compile_expr(&infix.left, builder)?;
822 self.compile_expr(&infix.right, builder)?;
823 builder.emit(Op::Lt);
824 }
825
826 InfixOperator::LessEqual => {
827 self.compile_expr(&infix.left, builder)?;
828 self.compile_expr(&infix.right, builder)?;
829 builder.emit(Op::Le);
830 }
831
832 InfixOperator::GreaterThan => {
833 self.compile_expr(&infix.left, builder)?;
834 self.compile_expr(&infix.right, builder)?;
835 builder.emit(Op::Gt);
836 }
837
838 InfixOperator::GreaterEqual => {
839 self.compile_expr(&infix.left, builder)?;
840 self.compile_expr(&infix.right, builder)?;
841 builder.emit(Op::Ge);
842 }
843
844 InfixOperator::Add => {
846 self.compile_expr(&infix.left, builder)?;
847 self.compile_expr(&infix.right, builder)?;
848 builder.emit(Op::Add);
849 }
850
851 InfixOperator::Subtract => {
852 self.compile_expr(&infix.left, builder)?;
853 self.compile_expr(&infix.right, builder)?;
854 builder.emit(Op::Sub);
855 }
856
857 InfixOperator::Multiply => {
858 self.compile_expr(&infix.left, builder)?;
859 self.compile_expr(&infix.right, builder)?;
860 builder.emit(Op::Mul);
861 }
862
863 InfixOperator::Divide => {
864 self.compile_expr(&infix.left, builder)?;
865 self.compile_expr(&infix.right, builder)?;
866 builder.emit(Op::Div);
867 }
868
869 InfixOperator::Modulo => {
870 self.compile_expr(&infix.left, builder)?;
871 self.compile_expr(&infix.right, builder)?;
872 builder.emit(Op::Mod);
873 }
874
875 InfixOperator::Concat => {
877 let mut operands = Vec::new();
879 Self::flatten_concat_chain_infix(infix, &mut operands);
880
881 if operands.len() > 2 && operands.len() <= 255 {
882 for operand in &operands {
884 self.compile_expr(operand, builder)?;
885 }
886 builder.emit(Op::ConcatN(operands.len() as u8));
887 } else {
888 self.compile_expr(&infix.left, builder)?;
890 self.compile_expr(&infix.right, builder)?;
891 builder.emit(Op::Concat);
892 }
893 }
894
895 InfixOperator::BitwiseAnd => {
897 self.compile_expr(&infix.left, builder)?;
898 self.compile_expr(&infix.right, builder)?;
899 builder.emit(Op::BitAnd);
900 }
901
902 InfixOperator::BitwiseOr => {
903 self.compile_expr(&infix.left, builder)?;
904 self.compile_expr(&infix.right, builder)?;
905 builder.emit(Op::BitOr);
906 }
907
908 InfixOperator::BitwiseXor => {
909 self.compile_expr(&infix.left, builder)?;
910 self.compile_expr(&infix.right, builder)?;
911 builder.emit(Op::BitXor);
912 }
913
914 InfixOperator::LeftShift => {
915 self.compile_expr(&infix.left, builder)?;
916 self.compile_expr(&infix.right, builder)?;
917 builder.emit(Op::Shl);
918 }
919
920 InfixOperator::RightShift => {
921 self.compile_expr(&infix.left, builder)?;
922 self.compile_expr(&infix.right, builder)?;
923 builder.emit(Op::Shr);
924 }
925
926 InfixOperator::Xor => {
928 self.compile_expr(&infix.left, builder)?;
929 self.compile_expr(&infix.right, builder)?;
930 builder.emit(Op::Xor);
931 }
932
933 InfixOperator::Is => {
935 self.compile_expr(&infix.left, builder)?;
936 match &*infix.right {
938 Expression::NullLiteral(_) => {
939 builder.emit(Op::IsNull);
940 }
941 Expression::BooleanLiteral(lit) if lit.value => {
942 builder.emit(Op::IsTrue);
943 }
944 Expression::BooleanLiteral(lit) if !lit.value => {
945 builder.emit(Op::IsFalse);
946 }
947 Expression::Identifier(id) if id.value_lower == "true" => {
948 builder.emit(Op::IsTrue);
949 }
950 Expression::Identifier(id) if id.value_lower == "false" => {
951 builder.emit(Op::IsFalse);
952 }
953 _ => {
954 self.compile_expr(&infix.right, builder)?;
955 builder.emit(Op::IsNotDistinctFrom);
956 }
957 }
958 }
959
960 InfixOperator::IsNot => {
961 self.compile_expr(&infix.left, builder)?;
962 match &*infix.right {
963 Expression::NullLiteral(_) => {
964 builder.emit(Op::IsNotNull);
965 }
966 Expression::BooleanLiteral(lit) if lit.value => {
967 builder.emit(Op::IsNotTrue);
968 }
969 Expression::BooleanLiteral(lit) if !lit.value => {
970 builder.emit(Op::IsNotFalse);
971 }
972 Expression::Identifier(id) if id.value_lower == "true" => {
973 builder.emit(Op::IsNotTrue);
974 }
975 Expression::Identifier(id) if id.value_lower == "false" => {
976 builder.emit(Op::IsNotFalse);
977 }
978 _ => {
979 self.compile_expr(&infix.right, builder)?;
980 builder.emit(Op::IsDistinctFrom);
981 }
982 }
983 }
984
985 InfixOperator::IsDistinctFrom => {
986 self.compile_expr(&infix.left, builder)?;
987 self.compile_expr(&infix.right, builder)?;
988 builder.emit(Op::IsDistinctFrom);
989 }
990
991 InfixOperator::IsNotDistinctFrom => {
992 self.compile_expr(&infix.left, builder)?;
993 self.compile_expr(&infix.right, builder)?;
994 builder.emit(Op::IsNotDistinctFrom);
995 }
996
997 InfixOperator::Like => {
999 self.compile_expr(&infix.left, builder)?;
1000 let pattern_str = Self::extract_pattern_string(&infix.right);
1001 if let Some(s) = pattern_str {
1002 let pattern = CompiledPattern::compile(&s, false)
1003 .map_err(|error| CompileError::InvalidExpression(error.to_string()))?;
1004 builder.emit(Op::Like(Arc::new(pattern), false));
1005 } else {
1006 self.compile_expr(&infix.right, builder)?;
1007 builder.emit(Op::LikeDynamic(false));
1008 }
1009 }
1010
1011 InfixOperator::ILike => {
1012 self.compile_expr(&infix.left, builder)?;
1013 let pattern_str = Self::extract_pattern_string(&infix.right);
1014 if let Some(s) = pattern_str {
1015 let pattern = CompiledPattern::compile(&s, true)
1016 .map_err(|error| CompileError::InvalidExpression(error.to_string()))?;
1017 builder.emit(Op::Like(Arc::new(pattern), true));
1018 } else {
1019 self.compile_expr(&infix.right, builder)?;
1020 builder.emit(Op::LikeDynamic(true));
1021 }
1022 }
1023
1024 InfixOperator::NotLike => {
1025 self.compile_expr(&infix.left, builder)?;
1026 let pattern_str = Self::extract_pattern_string(&infix.right);
1027 if let Some(s) = pattern_str {
1028 let pattern = CompiledPattern::compile(&s, false)
1029 .map_err(|error| CompileError::InvalidExpression(error.to_string()))?;
1030 builder.emit(Op::Like(Arc::new(pattern), false));
1031 builder.emit(Op::Not);
1032 } else {
1033 self.compile_expr(&infix.right, builder)?;
1034 builder.emit(Op::LikeDynamic(false));
1035 builder.emit(Op::Not);
1036 }
1037 }
1038
1039 InfixOperator::NotILike => {
1040 self.compile_expr(&infix.left, builder)?;
1041 let pattern_str = Self::extract_pattern_string(&infix.right);
1042 if let Some(s) = pattern_str {
1043 let pattern = CompiledPattern::compile(&s, true)
1044 .map_err(|error| CompileError::InvalidExpression(error.to_string()))?;
1045 builder.emit(Op::Like(Arc::new(pattern), true));
1046 builder.emit(Op::Not);
1047 } else {
1048 self.compile_expr(&infix.right, builder)?;
1049 builder.emit(Op::LikeDynamic(true));
1050 builder.emit(Op::Not);
1051 }
1052 }
1053
1054 InfixOperator::Glob | InfixOperator::NotGlob => {
1055 self.compile_expr(&infix.left, builder)?;
1056 let pattern_str = Self::extract_pattern_string(&infix.right);
1057 if let Some(s) = pattern_str {
1058 let pattern = CompiledPattern::compile_glob(&s)
1059 .map_err(|error| CompileError::InvalidExpression(error.to_string()))?;
1060 builder.emit(Op::Glob(Arc::new(pattern)));
1061 } else {
1062 self.compile_expr(&infix.right, builder)?;
1063 builder.emit(Op::GlobDynamic);
1064 }
1065 if matches!(infix.op_type, InfixOperator::NotGlob) {
1066 builder.emit(Op::Not);
1067 }
1068 }
1069
1070 InfixOperator::Regexp | InfixOperator::NotRegexp => {
1071 self.compile_expr(&infix.left, builder)?;
1072 let pattern_str = Self::extract_pattern_string(&infix.right);
1073 if let Some(s) = pattern_str {
1074 let regex = regex::Regex::new(&s).map_err(|e| {
1075 CompileError::InvalidExpression(format!("Invalid regex: {}", e))
1076 })?;
1077 builder.emit(Op::Regexp(Arc::new(regex)));
1078 } else {
1079 self.compile_expr(&infix.right, builder)?;
1080 builder.emit(Op::RegexpDynamic);
1081 }
1082 if matches!(infix.op_type, InfixOperator::NotRegexp) {
1083 builder.emit(Op::Not);
1084 }
1085 }
1086
1087 InfixOperator::JsonAccess => {
1089 self.compile_expr(&infix.left, builder)?;
1091 self.compile_expr(&infix.right, builder)?;
1092 builder.emit(Op::JsonAccess);
1093 }
1094
1095 InfixOperator::JsonAccessText => {
1096 self.compile_expr(&infix.left, builder)?;
1098 self.compile_expr(&infix.right, builder)?;
1099 builder.emit(Op::JsonAccessText);
1100 }
1101
1102 InfixOperator::Index => {
1103 self.compile_expr(&infix.left, builder)?;
1105 self.compile_expr(&infix.right, builder)?;
1106 builder.emit(Op::JsonAccess);
1107 }
1108
1109 InfixOperator::VectorDistance => {
1111 self.compile_expr(&infix.left, builder)?;
1112 self.compile_expr(&infix.right, builder)?;
1113 builder.emit(Op::VectorDistanceL2);
1114 }
1115
1116 InfixOperator::Other => {
1118 self.compile_expr(&infix.left, builder)?;
1119 self.compile_expr(&infix.right, builder)?;
1120 let name = format!(
1121 "{}{}",
1122 crate::context::STORED_OPERATOR_CALL_PREFIX,
1123 infix.operator
1124 );
1125 builder.emit(Op::CallStored {
1126 name: CompactArc::from(name.as_str()),
1127 arg_count: 2,
1128 });
1129 }
1130 }
1131
1132 Ok(())
1133 }
1134
1135 fn compile_prefix(
1137 &self,
1138 prefix: &PrefixExpression,
1139 builder: &mut ProgramBuilder,
1140 ) -> Result<(), CompileError> {
1141 self.compile_expr(&prefix.right, builder)?;
1142
1143 match prefix.operator.to_uppercase().as_str() {
1144 "NOT" => builder.emit(Op::Not),
1145 "-" => builder.emit(Op::Neg),
1146 "+" => {} "~" => builder.emit(Op::BitNot),
1148 _ => {
1149 return Err(CompileError::InvalidExpression(format!(
1150 "Unknown prefix operator: {}",
1151 prefix.operator
1152 )));
1153 }
1154 }
1155
1156 Ok(())
1157 }
1158
1159 fn compile_in(
1161 &self,
1162 in_expr: &InExpression,
1163 builder: &mut ProgramBuilder,
1164 ) -> Result<(), CompileError> {
1165 let left_columns: Vec<&Expression> = match &*in_expr.left {
1167 Expression::List(list) if list.elements.len() > 1 => list.elements.iter().collect(),
1168 Expression::ExpressionList(list) if list.expressions.len() > 1 => {
1169 list.expressions.iter().collect()
1170 }
1171 _ => Vec::new(),
1172 };
1173
1174 if !left_columns.is_empty() {
1175 return self.compile_multi_column_in(in_expr, &left_columns, builder);
1177 }
1178
1179 let mut values = ValueSet::default();
1182 let mut has_null = false;
1183 let mut all_constant = true;
1184
1185 match &*in_expr.right {
1187 Expression::List(list) => {
1188 for item in &list.elements {
1189 if let Some(value) = try_eval_constant(item) {
1190 if value.is_null() {
1191 has_null = true;
1192 } else {
1193 values.insert(value);
1194 }
1195 } else {
1196 all_constant = false;
1197 break;
1198 }
1199 }
1200 }
1201 Expression::ExpressionList(list) => {
1202 for item in &list.expressions {
1203 if let Some(value) = try_eval_constant(item) {
1204 if value.is_null() {
1205 has_null = true;
1206 } else {
1207 values.insert(value);
1208 }
1209 } else {
1210 all_constant = false;
1211 break;
1212 }
1213 }
1214 }
1215 _ => {
1216 all_constant = false;
1217 }
1218 }
1219
1220 if all_constant {
1221 if values.is_empty() && !has_null {
1222 if in_expr.not {
1226 builder.emit(Op::LoadConst(Value::Boolean(true)));
1227 } else {
1228 builder.emit(Op::LoadConst(Value::Boolean(false)));
1229 }
1230 } else {
1231 self.compile_expr(&in_expr.left, builder)?;
1233 if in_expr.not {
1234 builder.emit(Op::NotInSet(CompactArc::new(values), has_null));
1235 } else {
1236 builder.emit(Op::InSet(CompactArc::new(values), has_null));
1237 }
1238 }
1239 } else {
1240 return Err(CompileError::UnsupportedExpression(
1243 "Dynamic IN list not yet supported in VM".to_string(),
1244 ));
1245 }
1246
1247 Ok(())
1248 }
1249
1250 fn compile_multi_column_in(
1252 &self,
1253 in_expr: &InExpression,
1254 left_columns: &[&Expression],
1255 builder: &mut ProgramBuilder,
1256 ) -> Result<(), CompileError> {
1257 let tuple_size = left_columns.len();
1258
1259 let mut tuple_values: Vec<Vec<Value>> = Vec::new();
1261 let mut all_constant = true;
1262
1263 match &*in_expr.right {
1264 Expression::List(list) => {
1265 for item in &list.elements {
1266 if let Some(tuple) = self.extract_tuple_values(item, tuple_size) {
1267 tuple_values.push(tuple);
1268 } else {
1269 all_constant = false;
1270 break;
1271 }
1272 }
1273 }
1274 Expression::ExpressionList(list) => {
1275 for item in &list.expressions {
1276 if let Some(tuple) = self.extract_tuple_values(item, tuple_size) {
1277 tuple_values.push(tuple);
1278 } else {
1279 all_constant = false;
1280 break;
1281 }
1282 }
1283 }
1284 _ => {
1285 all_constant = false;
1286 }
1287 }
1288
1289 if !all_constant || tuple_values.is_empty() {
1290 return Err(CompileError::UnsupportedExpression(
1291 "Dynamic multi-column IN not yet supported in VM".to_string(),
1292 ));
1293 }
1294
1295 for col in left_columns {
1297 self.compile_expr(col, builder)?;
1298 }
1299
1300 let tuple_size = u8::try_from(tuple_size).map_err(|_| {
1302 CompileError::InvalidExpression("tuple arity exceeds the u8 bytecode limit".to_string())
1303 })?;
1304 builder.emit(Op::InTupleSet {
1305 tuple_size,
1306 values: Arc::new(tuple_values),
1307 negated: in_expr.not,
1308 });
1309
1310 Ok(())
1311 }
1312
1313 fn extract_tuple_values(&self, expr: &Expression, expected_size: usize) -> Option<Vec<Value>> {
1315 let elements: Vec<&Expression> = match expr {
1316 Expression::List(list) => list.elements.iter().collect(),
1317 Expression::ExpressionList(list) => list.expressions.iter().collect(),
1318 _ => return None,
1319 };
1320
1321 if elements.len() != expected_size {
1322 return None;
1323 }
1324
1325 let mut values = Vec::with_capacity(expected_size);
1326 for element in elements {
1327 let value = try_eval_constant(element)?;
1328 values.push(value);
1329 }
1330
1331 Some(values)
1332 }
1333
1334 fn compile_like(
1336 &self,
1337 like: &LikeExpression,
1338 builder: &mut ProgramBuilder,
1339 ) -> Result<(), CompileError> {
1340 self.compile_expr(&like.left, builder)?;
1341
1342 let op_upper = like.operator.to_uppercase();
1344 let case_insensitive = op_upper.contains("ILIKE");
1345 let negated = op_upper.contains("NOT");
1346 let is_glob = op_upper.contains("GLOB");
1347 let is_regexp = op_upper.contains("REGEXP") || op_upper.contains("RLIKE");
1348
1349 let escape_char: Option<char> = if let Some(ref escape_expr) = like.escape {
1351 if let Expression::StringLiteral(lit) = &**escape_expr {
1352 let mut chars = lit.value.chars();
1353 let first = chars.next().ok_or_else(|| {
1354 CompileError::InvalidExpression(
1355 "LIKE ESCAPE must contain exactly one character".to_string(),
1356 )
1357 })?;
1358 if chars.next().is_some() {
1359 return Err(CompileError::InvalidExpression(
1360 "LIKE ESCAPE must contain exactly one character".to_string(),
1361 ));
1362 }
1363 Some(first)
1364 } else {
1365 return Err(CompileError::InvalidExpression(
1366 "LIKE ESCAPE must be a string literal".to_string(),
1367 ));
1368 }
1369 } else {
1370 None
1371 };
1372
1373 let pattern_str = Self::extract_pattern_string(&like.pattern);
1375 if let Some(s) = pattern_str {
1376 if is_regexp {
1377 let regex = regex::Regex::new(&s).map_err(|e| {
1378 CompileError::InvalidExpression(format!("Invalid regex: {}", e))
1379 })?;
1380 builder.emit(Op::Regexp(Arc::new(regex)));
1381 } else if is_glob {
1382 let pattern = CompiledPattern::compile_glob(&s)
1384 .map_err(|error| CompileError::InvalidExpression(error.to_string()))?;
1385 builder.emit(Op::Glob(Arc::new(pattern)));
1386 } else if let Some(esc) = escape_char {
1387 let processed_pattern = self.process_like_escape(&s, esc);
1389 let pattern = CompiledPattern::compile(&processed_pattern, case_insensitive)
1390 .map_err(|error| CompileError::InvalidExpression(error.to_string()))?;
1391 builder.emit(Op::LikeEscape(Arc::new(pattern), case_insensitive, esc));
1392 } else {
1393 let pattern = CompiledPattern::compile(&s, case_insensitive)
1394 .map_err(|error| CompileError::InvalidExpression(error.to_string()))?;
1395 builder.emit(Op::Like(Arc::new(pattern), case_insensitive));
1396 }
1397
1398 if negated {
1399 builder.emit(Op::Not);
1400 }
1401 } else {
1402 self.compile_expr(&like.pattern, builder)?;
1405 if is_regexp {
1406 builder.emit(Op::RegexpDynamic);
1407 } else if is_glob {
1408 builder.emit(Op::GlobDynamic);
1409 } else if let Some(esc) = escape_char {
1410 builder.emit(Op::LikeDynamicEscape(case_insensitive, esc));
1411 } else {
1412 builder.emit(Op::LikeDynamic(case_insensitive));
1413 }
1414 if negated {
1415 builder.emit(Op::Not);
1416 }
1417 }
1418
1419 Ok(())
1420 }
1421
1422 fn extract_pattern_string(expr: &Expression) -> Option<SmartString> {
1425 match expr {
1426 Expression::StringLiteral(lit) => Some(lit.value.clone()),
1427 Expression::Identifier(id) if id.token.quoted => Some(id.value.clone()),
1428 _ => None,
1429 }
1430 }
1431
1432 fn process_like_escape(&self, pattern: &str, escape: char) -> String {
1435 let mut result = String::with_capacity(pattern.len());
1436 let mut chars = pattern.chars().peekable();
1437
1438 while let Some(c) = chars.next() {
1439 if c == escape {
1440 if let Some(&next) = chars.peek() {
1442 if next == '%' || next == '_' || next == escape {
1443 result.push('\\');
1445 result.push(chars.next().unwrap());
1446 } else {
1447 result.push(c);
1449 }
1450 } else {
1451 result.push(c);
1453 }
1454 } else {
1455 result.push(c);
1456 }
1457 }
1458
1459 result
1460 }
1461
1462 fn compile_case(
1464 &self,
1465 case: &CaseExpression,
1466 builder: &mut ProgramBuilder,
1467 ) -> Result<(), CompileError> {
1468 builder.emit(Op::CaseStart);
1469
1470 let is_simple = case.value.is_some();
1471 let mut end_jumps = Vec::new();
1472
1473 if let Some(ref operand) = case.value {
1475 self.compile_expr(operand, builder)?;
1476 }
1477
1478 for when_clause in &case.when_clauses {
1479 if is_simple {
1480 builder.emit(Op::Dup); self.compile_expr(&when_clause.condition, builder)?;
1483 builder.emit(Op::CaseCompare);
1484 } else {
1485 self.compile_expr(&when_clause.condition, builder)?;
1487 }
1488
1489 let when_pos = builder.position();
1491 builder.emit(Op::CaseWhen(0)); if is_simple {
1495 builder.emit(Op::Pop); }
1497 self.compile_expr(&when_clause.then_result, builder)?;
1498
1499 let then_pos = builder.position();
1501 builder.emit(Op::CaseThen(0)); end_jumps.push(then_pos);
1503
1504 let next_pos = builder.position();
1506 builder.patch_jump(when_pos as usize, next_pos);
1507 }
1508
1509 if is_simple {
1511 builder.emit(Op::Pop); }
1513 if let Some(ref else_value) = case.else_value {
1514 builder.emit(Op::CaseElse);
1515 self.compile_expr(else_value, builder)?;
1516 } else {
1517 builder.emit(Op::LoadNull(DataType::Null));
1518 }
1519
1520 let end_pos = builder.position();
1522 builder.emit(Op::CaseEnd);
1523
1524 for pos in end_jumps {
1525 builder.patch_jump(pos as usize, end_pos);
1526 }
1527
1528 Ok(())
1529 }
1530
1531 fn compile_function(
1533 &self,
1534 func: &FunctionCall,
1535 builder: &mut ProgramBuilder,
1536 ) -> Result<(), CompileError> {
1537 let func_name = func.function.to_uppercase();
1538
1539 if func.is_distinct || !func.order_by.is_empty() || func.filter.is_some() {
1540 return Err(CompileError::InvalidExpression(format!(
1541 "DISTINCT, ORDER BY, and FILTER modifiers require an aggregate function; {func_name} is being compiled as a scalar function"
1542 )));
1543 }
1544
1545 if let Some(info) = self.ctx.functions.get_info(&func_name) {
1546 info.signature
1547 .validate_arg_count(func.arguments.len())
1548 .map_err(|error| CompileError::InvalidExpression(error.to_string()))?;
1549 }
1550
1551 match func_name.as_str() {
1553 "NOW" | "CURRENT_TIMESTAMP" => {
1554 builder.emit(Op::LoadNamedParam(CompactArc::from(
1555 "CURRENT_STATEMENT_TIMESTAMP",
1556 )));
1557 return Ok(());
1558 }
1559 "CURRENT_TRANSACTION_ID" => {
1560 builder.emit(Op::LoadTransactionId);
1562 return Ok(());
1563 }
1564
1565 "IIF" => {
1566 if func.arguments.len() != 3 {
1567 return Err(CompileError::InvalidExpression(
1568 "IIF requires exactly 3 arguments".to_string(),
1569 ));
1570 }
1571
1572 self.compile_expr(&func.arguments[0], builder)?;
1573 let false_jump = builder.position();
1574 builder.emit(Op::PopJumpIfFalse(0));
1575 self.compile_expr(&func.arguments[1], builder)?;
1576 let end_jump = builder.position();
1577 builder.emit(Op::Jump(0));
1578
1579 let false_pos = builder.position();
1580 builder.patch_jump(false_jump as usize, false_pos);
1581 self.compile_expr(&func.arguments[2], builder)?;
1582 let end_pos = builder.position();
1583 builder.patch_jump(end_jump as usize, end_pos);
1584 return Ok(());
1585 }
1586
1587 "COALESCE" => {
1588 if func.arguments.is_empty() {
1600 builder.emit(Op::LoadNull(DataType::Null));
1601 return Ok(());
1602 }
1603
1604 let mut jump_positions = Vec::new();
1605 let last_idx = func.arguments.len() - 1;
1606
1607 for (i, arg) in func.arguments.iter().enumerate() {
1608 self.compile_expr(arg, builder)?;
1609
1610 if i < last_idx {
1611 let jump_pos = builder.position();
1613 builder.emit(Op::JumpIfNotNull(0)); jump_positions.push(jump_pos);
1615 builder.emit(Op::Pop); }
1617 }
1619
1620 let end_pos = builder.position();
1622 for pos in jump_positions {
1623 builder.patch_jump(pos as usize, end_pos);
1624 }
1625
1626 return Ok(());
1627 }
1628
1629 "NULLIF" if func.arguments.len() == 2 => {
1630 self.compile_expr(&func.arguments[0], builder)?;
1631 self.compile_expr(&func.arguments[1], builder)?;
1632 builder.emit(Op::NullIf);
1633 return Ok(());
1634 }
1635
1636 "GREATEST" => {
1637 let arg_count = u8::try_from(func.arguments.len()).map_err(|_| {
1638 CompileError::InvalidExpression(
1639 "GREATEST arity exceeds the u8 bytecode limit".to_string(),
1640 )
1641 })?;
1642 for arg in &func.arguments {
1643 self.compile_expr(arg, builder)?;
1644 }
1645 builder.emit(Op::Greatest(arg_count));
1646 return Ok(());
1647 }
1648
1649 "LEAST" => {
1650 let arg_count = u8::try_from(func.arguments.len()).map_err(|_| {
1651 CompileError::InvalidExpression(
1652 "LEAST arity exceeds the u8 bytecode limit".to_string(),
1653 )
1654 })?;
1655 for arg in &func.arguments {
1656 self.compile_expr(arg, builder)?;
1657 }
1658 builder.emit(Op::Least(arg_count));
1659 return Ok(());
1660 }
1661
1662 _ => {}
1663 }
1664
1665 if let Some(scalar_func) = self.ctx.functions.get_scalar(&func_name) {
1667 let arg_count = u8::try_from(func.arguments.len()).map_err(|_| {
1668 CompileError::InvalidExpression(
1669 "function arity exceeds the u8 bytecode limit".to_string(),
1670 )
1671 })?;
1672 for arg in &func.arguments {
1674 self.compile_expr(arg, builder)?;
1675 }
1676
1677 if func.arguments.len() == 1 {
1679 if let Some(native_fn) = scalar_func.native_fn1() {
1680 builder.emit(Op::NativeFn1(native_fn));
1681 return Ok(());
1682 }
1683 }
1684
1685 builder.emit(Op::CallScalar {
1687 func: scalar_func.into(),
1688 arg_count,
1689 });
1690 Ok(())
1691 } else {
1692 let arg_count = u8::try_from(func.arguments.len()).map_err(|_| {
1693 CompileError::InvalidExpression(
1694 "stored function arity exceeds the u8 bytecode limit".to_string(),
1695 )
1696 })?;
1697 for argument in &func.arguments {
1698 self.compile_expr(argument, builder)?;
1699 }
1700 builder.emit(Op::CallStored {
1701 name: CompactArc::from(func.function.as_str()),
1702 arg_count,
1703 });
1704 Ok(())
1705 }
1706 }
1707}
1708
1709pub fn is_non_foldable_function(name: &str) -> bool {
1723 is_non_foldable_function_with_registry(name, radixdb_functions::registry::global_registry())
1724}
1725
1726#[inline]
1727fn is_non_foldable_function_with_registry(
1728 name: &str,
1729 registry: &radixdb_functions::FunctionRegistry,
1730) -> bool {
1731 !registry.is_deterministic(name)
1732}
1733
1734fn is_foldable_expr(expr: &Expression, registry: &radixdb_functions::FunctionRegistry) -> bool {
1739 match expr {
1740 Expression::IntegerLiteral(_)
1742 | Expression::FloatLiteral(_)
1743 | Expression::StringLiteral(_)
1744 | Expression::BooleanLiteral(_)
1745 | Expression::NullLiteral(_)
1746 | Expression::BoundValue(_) => false,
1747
1748 Expression::IntervalLiteral(_) => false,
1750
1751 Expression::Infix(infix) => {
1753 is_column_free(&infix.left, registry) && is_column_free(&infix.right, registry)
1754 }
1755
1756 Expression::Prefix(prefix) => is_column_free(&prefix.right, registry),
1758
1759 Expression::FunctionCall(func) => {
1763 if is_non_foldable_function_with_registry(&func.function, registry) {
1764 return false;
1765 }
1766 func.arguments
1767 .iter()
1768 .all(|argument| is_column_free(argument, registry))
1769 }
1770
1771 Expression::Cast(cast) => {
1773 !cast.type_name.contains('.') && is_column_free(&cast.expr, registry)
1774 }
1775
1776 _ => false,
1778 }
1779}
1780
1781fn is_column_free(expr: &Expression, registry: &radixdb_functions::FunctionRegistry) -> bool {
1783 match expr {
1784 Expression::IntegerLiteral(_)
1786 | Expression::FloatLiteral(_)
1787 | Expression::StringLiteral(_)
1788 | Expression::BooleanLiteral(_)
1789 | Expression::NullLiteral(_)
1790 | Expression::IntervalLiteral(_)
1791 | Expression::BoundValue(_) => true,
1792
1793 Expression::Identifier(_) | Expression::QualifiedIdentifier { .. } => false,
1795
1796 Expression::Parameter(_) => false,
1798
1799 Expression::Infix(infix) => {
1801 is_column_free(&infix.left, registry) && is_column_free(&infix.right, registry)
1802 }
1803
1804 Expression::Prefix(prefix) => is_column_free(&prefix.right, registry),
1806
1807 Expression::FunctionCall(func) => {
1810 if is_non_foldable_function_with_registry(&func.function, registry) {
1811 return false;
1812 }
1813 func.arguments
1814 .iter()
1815 .all(|argument| is_column_free(argument, registry))
1816 }
1817
1818 Expression::Cast(cast) => {
1820 !cast.type_name.contains('.') && is_column_free(&cast.expr, registry)
1821 }
1822
1823 Expression::Case(case) => {
1825 case.value
1826 .as_ref()
1827 .is_none_or(|e| is_column_free(e, registry))
1828 && case.when_clauses.iter().all(|wc| {
1829 is_column_free(&wc.condition, registry)
1830 && is_column_free(&wc.then_result, registry)
1831 })
1832 && case
1833 .else_value
1834 .as_ref()
1835 .is_none_or(|e| is_column_free(e, registry))
1836 }
1837
1838 Expression::ScalarSubquery(_) | Expression::Exists(_) => false,
1840
1841 Expression::Between(between) => {
1843 is_column_free(&between.expr, registry)
1844 && is_column_free(&between.lower, registry)
1845 && is_column_free(&between.upper, registry)
1846 }
1847
1848 _ => false,
1850 }
1851}
1852
1853fn try_eval_constant(expr: &Expression) -> Option<Value> {
1855 match expr {
1856 Expression::IntegerLiteral(lit) => Some(Value::Integer(lit.value)),
1857 Expression::FloatLiteral(lit) => Some(Value::Float(lit.value)),
1858 Expression::StringLiteral(lit) => Some(Value::Text(lit.value.clone())),
1859 Expression::BooleanLiteral(lit) => Some(Value::Boolean(lit.value)),
1860 Expression::NullLiteral(_) => Some(Value::null_unknown()),
1861 Expression::BoundValue(value) => Some((**value).clone()),
1862 _ => None,
1863 }
1864}
1865
1866#[cfg(test)]
1869mod tests {
1870 use super::*;
1871 use radixdb_sql::ast::IntegerLiteral;
1872 use radixdb_sql::token::{Position, Token, TokenType};
1873
1874 fn make_token() -> Token {
1875 Token {
1876 token_type: TokenType::Integer,
1877 literal: "1".into(),
1878 position: Position {
1879 offset: 0,
1880 line: 1,
1881 column: 1,
1882 },
1883 quoted: false,
1884 }
1885 }
1886
1887 #[test]
1888 fn test_compile_simple_comparison() {
1889 let columns = vec!["a".to_string(), "b".to_string()];
1890 let ctx = CompileContext::with_global_registry(&columns);
1891 let compiler = ExprCompiler::new(&ctx);
1892
1893 let expr = Expression::Infix(InfixExpression {
1895 token: make_token(),
1896 left: Box::new(Expression::Identifier(Identifier::new(
1897 make_token(),
1898 "a".to_string(),
1899 ))),
1900 operator: ">".into(),
1901 op_type: InfixOperator::GreaterThan,
1902 right: Box::new(Expression::IntegerLiteral(IntegerLiteral {
1903 token: make_token(),
1904 value: 5,
1905 })),
1906 });
1907
1908 let program = compiler.compile(&expr).unwrap();
1909 assert!(!program.is_empty());
1910 println!("{}", program.disassemble());
1911 }
1912
1913 #[test]
1914 fn test_compile_and_expression() {
1915 let columns = vec!["a".to_string(), "b".to_string()];
1916 let ctx = CompileContext::with_global_registry(&columns);
1917 let compiler = ExprCompiler::new(&ctx);
1918
1919 let expr = Expression::Infix(InfixExpression {
1921 token: make_token(),
1922 left: Box::new(Expression::Infix(InfixExpression {
1923 token: make_token(),
1924 left: Box::new(Expression::Identifier(Identifier::new(
1925 make_token(),
1926 "a".to_string(),
1927 ))),
1928 operator: ">".into(),
1929 op_type: InfixOperator::GreaterThan,
1930 right: Box::new(Expression::IntegerLiteral(IntegerLiteral {
1931 token: make_token(),
1932 value: 5,
1933 })),
1934 })),
1935 operator: "AND".into(),
1936 op_type: InfixOperator::And,
1937 right: Box::new(Expression::Infix(InfixExpression {
1938 token: make_token(),
1939 left: Box::new(Expression::Identifier(Identifier::new(
1940 make_token(),
1941 "b".to_string(),
1942 ))),
1943 operator: "<".into(),
1944 op_type: InfixOperator::LessThan,
1945 right: Box::new(Expression::IntegerLiteral(IntegerLiteral {
1946 token: make_token(),
1947 value: 10,
1948 })),
1949 })),
1950 });
1951
1952 let program = compiler.compile(&expr).unwrap();
1953 assert!(!program.is_empty());
1954 println!("{}", program.disassemble());
1955 }
1956}