1use std::hash::{Hash, Hasher};
31use std::num::NonZeroUsize;
32use std::sync::Arc;
33
34use lru::LruCache;
35use parking_lot::Mutex;
36use radixdb_core::ParamVec;
37use radixdb_core::{CompactArc, StringMap};
38use rustc_hash::{FxHashMap, FxHasher};
39
40use super::compiler::{CompileContext, ExprCompiler};
41use super::execution_context::ExecuteContext;
42use super::program::Program;
43use super::vm::ExprVM;
44use radixdb_core::{Error, Result, Row, Value};
45use radixdb_functions::{global_registry, FunctionRegistry};
46use radixdb_sql::ast::Expression;
47
48use crate::context::{ExecutionContext, StoredFunctionInvoker};
49
50const PROGRAM_CACHE_SIZE: usize = 256;
56
57#[derive(Clone)]
60struct ProgramCacheEntry {
61 expression: Expression,
62 columns: Vec<String>,
63 registry_generation: u64,
64 program: SharedProgram,
65}
66
67#[derive(Clone)]
68struct LocalProgramCacheEntry {
69 expression: Expression,
70 registry_generation: u64,
71 program: SharedProgram,
72}
73
74static PROGRAM_CACHE: Mutex<Option<LruCache<u64, ProgramCacheEntry>>> = Mutex::new(None);
75
76pub fn clear_program_cache() {
78 let mut guard = PROGRAM_CACHE.lock();
79 *guard = None;
80}
81
82fn checked_alias_map(aliases: &[(String, usize)]) -> Result<StringMap<u16>> {
83 aliases
84 .iter()
85 .map(|(name, index)| {
86 let index = u16::try_from(*index).map_err(|_| {
87 Error::invalid_argument(format!(
88 "expression alias '{}' index {} exceeds the u16 bytecode limit",
89 name, index
90 ))
91 })?;
92 Ok((name.to_lowercase(), index))
93 })
94 .collect()
95}
96
97fn compute_cache_key(expr: &Expression, columns: &[String], registry_generation: u64) -> u64 {
101 let mut hasher = FxHasher::default();
102 hash_expression(expr, &mut hasher);
104 columns.hash(&mut hasher);
106 registry_generation.hash(&mut hasher);
107 hasher.finish()
108}
109
110#[inline]
115pub fn compute_expression_hash(expr: &Expression) -> u64 {
116 let mut hasher = FxHasher::default();
117 hash_expression(expr, &mut hasher);
118 hasher.finish()
119}
120
121fn hash_expression(expr: &Expression, hasher: &mut FxHasher) {
124 std::mem::discriminant(expr).hash(hasher);
126
127 match expr {
128 Expression::Identifier(id) => {
129 id.value_lower.hash(hasher);
130 }
131 Expression::QualifiedIdentifier(qid) => {
132 qid.qualifier.value_lower.hash(hasher);
133 qid.name.value_lower.hash(hasher);
134 }
135 Expression::IntegerLiteral(lit) => {
136 lit.value.hash(hasher);
137 }
138 Expression::FloatLiteral(lit) => {
139 lit.value.to_bits().hash(hasher);
140 }
141 Expression::StringLiteral(lit) => {
142 lit.value.hash(hasher);
143 lit.type_hint.hash(hasher);
144 }
145 Expression::BooleanLiteral(lit) => {
146 lit.value.hash(hasher);
147 }
148 Expression::NullLiteral(_) => {
149 }
151 Expression::BoundValue(value) => {
152 value.hash(hasher);
153 }
154 Expression::IntervalLiteral(lit) => {
155 lit.value.hash(hasher);
156 lit.unit.hash(hasher);
157 }
158 Expression::Parameter(param) => {
159 param.index.hash(hasher);
160 param.name.hash(hasher);
161 }
162 Expression::Prefix(prefix) => {
163 std::mem::discriminant(&prefix.op_type).hash(hasher);
164 hash_expression(&prefix.right, hasher);
165 }
166 Expression::Infix(infix) => {
167 std::mem::discriminant(&infix.op_type).hash(hasher);
168 hash_expression(&infix.left, hasher);
169 hash_expression(&infix.right, hasher);
170 }
171 Expression::List(list) => {
172 list.elements.len().hash(hasher);
173 for val in &list.elements {
174 hash_expression(val, hasher);
175 }
176 }
177 Expression::Distinct(dist) => {
178 hash_expression(&dist.expr, hasher);
179 }
180 Expression::Exists(exists) => {
181 (exists.subquery.as_ref() as *const _ as usize).hash(hasher);
184 }
185 Expression::AllAny(aa) => {
186 aa.operator.hash(hasher);
187 std::mem::discriminant(&aa.all_any_type).hash(hasher);
188 hash_expression(&aa.left, hasher);
189 (aa.subquery.as_ref() as *const _ as usize).hash(hasher);
191 }
192 Expression::In(in_expr) => {
193 in_expr.not.hash(hasher);
194 hash_expression(&in_expr.left, hasher);
195 hash_expression(&in_expr.right, hasher);
196 }
197 Expression::InHashSet(in_hash) => {
198 in_hash.not.hash(hasher);
199 hash_expression(&in_hash.column, hasher);
200 let mut values: Vec<&Value> = in_hash.values.iter().collect();
201 values.sort_unstable();
202 values.hash(hasher);
203 }
204 Expression::Between(between) => {
205 between.not.hash(hasher);
206 hash_expression(&between.expr, hasher);
207 hash_expression(&between.lower, hasher);
208 hash_expression(&between.upper, hasher);
209 }
210 Expression::Like(like) => {
211 like.operator.hash(hasher);
212 hash_expression(&like.left, hasher);
213 hash_expression(&like.pattern, hasher);
214 if let Some(ref escape) = like.escape {
215 true.hash(hasher);
216 hash_expression(escape, hasher);
217 } else {
218 false.hash(hasher);
219 }
220 }
221 Expression::ScalarSubquery(sq) => {
222 (sq.subquery.as_ref() as *const _ as usize).hash(hasher);
224 }
225 Expression::ExpressionList(list) => {
226 list.expressions.len().hash(hasher);
227 for e in &list.expressions {
228 hash_expression(e, hasher);
229 }
230 }
231 Expression::Case(case) => {
232 if let Some(ref val) = case.value {
233 true.hash(hasher);
234 hash_expression(val, hasher);
235 } else {
236 false.hash(hasher);
237 }
238 case.when_clauses.len().hash(hasher);
239 for when_clause in &case.when_clauses {
240 hash_expression(&when_clause.condition, hasher);
241 hash_expression(&when_clause.then_result, hasher);
242 }
243 if let Some(ref else_val) = case.else_value {
244 true.hash(hasher);
245 hash_expression(else_val, hasher);
246 } else {
247 false.hash(hasher);
248 }
249 }
250 Expression::Cast(cast) => {
251 hash_expression(&cast.expr, hasher);
252 cast.type_name.hash(hasher);
253 }
254 Expression::FunctionCall(func) => {
255 func.function.hash(hasher);
256 func.is_distinct.hash(hasher);
257 func.arguments.len().hash(hasher);
258 for arg in &func.arguments {
259 hash_expression(arg, hasher);
260 }
261 if let Some(ref filter) = func.filter {
262 true.hash(hasher);
263 hash_expression(filter, hasher);
264 } else {
265 false.hash(hasher);
266 }
267 }
268 Expression::Aliased(aliased) => {
269 aliased.alias.value_lower.hash(hasher);
270 hash_expression(&aliased.expression, hasher);
271 }
272 Expression::Window(window) => {
273 window.function.function.hash(hasher);
274 window.function.is_distinct.hash(hasher);
275 window.function.arguments.len().hash(hasher);
276 for arg in &window.function.arguments {
277 hash_expression(arg, hasher);
278 }
279 window.partition_by.len().hash(hasher);
280 for e in &window.partition_by {
281 hash_expression(e, hasher);
282 }
283 window.order_by.len().hash(hasher);
284 for order in &window.order_by {
285 hash_expression(&order.expression, hasher);
286 order.ascending.hash(hasher);
287 order.nulls_first.hash(hasher);
288 }
289 }
290 Expression::TableSource(ts) => {
291 ts.name.value_lower.hash(hasher);
292 if let Some(ref alias) = ts.alias {
293 true.hash(hasher);
294 alias.value_lower.hash(hasher);
295 } else {
296 false.hash(hasher);
297 }
298 }
299 Expression::JoinSource(js) => {
300 (js.as_ref() as *const _ as usize).hash(hasher);
302 }
303 Expression::SubquerySource(sq) => {
304 if let Some(ref alias) = sq.alias {
305 true.hash(hasher);
306 alias.value_lower.hash(hasher);
307 } else {
308 false.hash(hasher);
309 }
310 (sq.subquery.as_ref() as *const _ as usize).hash(hasher);
312 }
313 Expression::ValuesSource(vs) => {
314 if let Some(ref alias) = vs.alias {
315 true.hash(hasher);
316 alias.value_lower.hash(hasher);
317 } else {
318 false.hash(hasher);
319 }
320 vs.rows.len().hash(hasher);
321 }
322 Expression::CteReference(cte) => {
323 cte.name.value_lower.hash(hasher);
324 }
325 Expression::FunctionTableSource(fts) => {
326 fts.function.value_lower.hash(hasher);
327 for arg in &fts.arguments {
328 hash_expression(arg, hasher);
329 }
330 }
331 Expression::Star(_) => {
332 }
334 Expression::QualifiedStar(qs) => {
335 qs.qualifier.hash(hasher);
336 }
337 Expression::Default(_) => {
338 }
340 }
341}
342
343fn compile_expression_cached(expr: &Expression, columns: &[String]) -> Result<SharedProgram> {
346 let registry = global_registry();
347 let registry_generation = registry.generation();
348 let cache_key = compute_cache_key(expr, columns, registry_generation);
349
350 {
352 let mut guard = PROGRAM_CACHE.lock();
353 let cache = guard.get_or_insert_with(|| {
354 LruCache::new(NonZeroUsize::new(PROGRAM_CACHE_SIZE).unwrap())
356 });
357 if let Some(entry) = cache.get(&cache_key) {
358 if entry.registry_generation == registry_generation
359 && entry.expression == *expr
360 && entry.columns == columns
361 {
362 return Ok(entry.program.clone());
363 }
364 }
365 }
366
367 let ctx = CompileContext::new(columns, registry);
369 let compiler = ExprCompiler::new(&ctx);
370 let program: SharedProgram = compiler
371 .compile(expr)
372 .map(CompactArc::new)
373 .map_err(|e| Error::internal(format!("Compile error: {}", e)))?;
374
375 {
377 let mut guard = PROGRAM_CACHE.lock();
378 let cache = guard
379 .get_or_insert_with(|| LruCache::new(NonZeroUsize::new(PROGRAM_CACHE_SIZE).unwrap()));
380 cache.put(
381 cache_key,
382 ProgramCacheEntry {
383 expression: expr.clone(),
384 columns: columns.to_vec(),
385 registry_generation,
386 program: program.clone(),
387 },
388 );
389 }
390
391 Ok(program)
392}
393
394pub fn compile_expression(expr: &Expression, columns: &[String]) -> Result<SharedProgram> {
414 compile_expression_cached(expr, columns)
415}
416
417pub fn try_eval_constant_expr(expr: &Expression) -> Option<Value> {
434 use std::cell::RefCell;
435
436 if contains_context_dependent_function(expr) {
440 return None;
441 }
442
443 thread_local! {
444 static EVAL_VM: RefCell<ExprVM> = RefCell::new(ExprVM::new());
445 static EVAL_ROW: Row = Row::new();
446 }
447
448 let empty_cols: &[String] = &[];
449 let ctx = CompileContext::with_global_registry(empty_cols);
450 let compiler = ExprCompiler::new(&ctx);
451 let program = compiler.compile(expr).ok()?;
452
453 EVAL_ROW.with(|empty_row| {
454 let exec_ctx = ExecuteContext::new(empty_row);
455 EVAL_VM.with(|vm_cell| {
456 let mut vm = vm_cell.borrow_mut();
457 vm.execute(&program, &exec_ctx).ok()
458 })
459 })
460}
461
462fn contains_context_dependent_function(expr: &Expression) -> bool {
466 match expr {
467 Expression::FunctionCall(func) => {
468 func.function.eq_ignore_ascii_case("CURRENT_TRANSACTION_ID")
469 || func
470 .arguments
471 .iter()
472 .any(contains_context_dependent_function)
473 }
474 Expression::Infix(infix) => {
475 contains_context_dependent_function(&infix.left)
476 || contains_context_dependent_function(&infix.right)
477 }
478 Expression::Prefix(prefix) => contains_context_dependent_function(&prefix.right),
479 Expression::Cast(cast) => contains_context_dependent_function(&cast.expr),
480 Expression::Case(case) => {
481 case.value
482 .as_ref()
483 .is_some_and(|v| contains_context_dependent_function(v))
484 || case.when_clauses.iter().any(|w| {
485 contains_context_dependent_function(&w.condition)
486 || contains_context_dependent_function(&w.then_result)
487 })
488 || case
489 .else_value
490 .as_ref()
491 .is_some_and(|v| contains_context_dependent_function(v))
492 }
493 Expression::Between(between) => {
494 contains_context_dependent_function(&between.expr)
495 || contains_context_dependent_function(&between.lower)
496 || contains_context_dependent_function(&between.upper)
497 }
498 Expression::In(in_expr) => {
499 contains_context_dependent_function(&in_expr.left)
500 || contains_context_dependent_function(&in_expr.right)
501 }
502 Expression::Like(like) => {
503 contains_context_dependent_function(&like.left)
504 || contains_context_dependent_function(&like.pattern)
505 || like
506 .escape
507 .as_ref()
508 .is_some_and(|e| contains_context_dependent_function(e))
509 }
510 Expression::List(list) => list
511 .elements
512 .iter()
513 .any(contains_context_dependent_function),
514 Expression::ExpressionList(list) => list
515 .expressions
516 .iter()
517 .any(contains_context_dependent_function),
518 Expression::Aliased(aliased) => contains_context_dependent_function(&aliased.expression),
519 Expression::Distinct(distinct) => contains_context_dependent_function(&distinct.expr),
520 Expression::AllAny(all_any) => contains_context_dependent_function(&all_any.left),
521 Expression::InHashSet(in_hash) => contains_context_dependent_function(&in_hash.column),
522 _ => false,
523 }
524}
525
526pub fn compile_expression_with_context(
530 expr: &Expression,
531 columns: &[String],
532 outer_columns: Option<&[String]>,
533 function_registry: &FunctionRegistry,
534) -> Result<SharedProgram> {
535 let mut ctx = CompileContext::new(columns, function_registry);
536 if let Some(outer_cols) = outer_columns {
537 ctx = ctx.with_outer_columns(outer_cols);
538 }
539 let compiler = ExprCompiler::new(&ctx);
540 compiler
541 .compile(expr)
542 .map(CompactArc::new)
543 .map_err(|e| Error::internal(format!("Compile error: {}", e)))
544}
545
546#[derive(Clone)]
568pub struct RowFilter {
569 program: SharedProgram,
571 params: CompactArc<ParamVec>,
573 named_params: Arc<FxHashMap<String, Value>>,
575 transaction_id: Option<u64>,
577 stored_function_invoker: Option<Arc<dyn StoredFunctionInvoker>>,
578 outer_row: Option<Arc<FxHashMap<CompactArc<str>, Value>>>,
580}
581
582impl RowFilter {
583 pub fn new(expr: &Expression, columns: &[String]) -> Result<Self> {
589 let program = compile_expression(expr, columns)?;
590 Ok(Self {
591 program,
592 params: CompactArc::new(ParamVec::new()),
593 named_params: Arc::new(FxHashMap::default()),
594 transaction_id: None,
595 stored_function_invoker: None,
596 outer_row: None,
597 })
598 }
599
600 pub fn with_aliases(
625 expr: &Expression,
626 columns: &[String],
627 aliases: &[(String, usize)],
628 ) -> Result<Self> {
629 let alias_map = checked_alias_map(aliases)?;
630
631 let ctx = CompileContext::with_global_registry(columns).with_expression_aliases(alias_map);
632 let compiler = ExprCompiler::new(&ctx);
633 let program = compiler
634 .compile(expr)
635 .map(CompactArc::new)
636 .map_err(|e| Error::internal(format!("Compile error: {}", e)))?;
637
638 Ok(Self {
639 program,
640 params: CompactArc::new(ParamVec::new()),
641 named_params: Arc::new(FxHashMap::default()),
642 transaction_id: None,
643 stored_function_invoker: None,
644 outer_row: None,
645 })
646 }
647
648 pub fn with_aliases_and_context(
652 expr: &Expression,
653 columns: &[String],
654 aliases: &[(String, usize)],
655 execution: &ExecutionContext,
656 ) -> Result<Self> {
657 let alias_map = checked_alias_map(aliases)?;
658 let mut context =
659 CompileContext::with_global_registry(columns).with_expression_aliases(alias_map);
660 if let Some(outer) = execution.outer_row() {
661 let outer_columns: Vec<String> = outer.keys().map(ToString::to_string).collect();
662 context = context.with_outer_columns(&outer_columns);
663 }
664 let compiler = ExprCompiler::new(&context);
665 let program = compiler
666 .compile(expr)
667 .map(CompactArc::new)
668 .map_err(|error| Error::internal(format!("Compile error: {error}")))?;
669
670 Ok(Self {
671 program,
672 params: CompactArc::clone(execution.params_arc()),
673 named_params: Arc::clone(execution.named_params_arc()),
674 transaction_id: execution.transaction_id(),
675 stored_function_invoker: execution.stored_function_invoker().cloned(),
676 outer_row: execution.outer_row().cloned().map(Arc::new),
677 })
678 }
679
680 pub fn with_params(mut self, params: ParamVec) -> Self {
682 self.params = CompactArc::new(params);
683 self
684 }
685
686 pub fn with_named_params(mut self, named_params: FxHashMap<String, Value>) -> Self {
688 self.named_params = Arc::new(named_params);
689 self
690 }
691
692 pub fn with_context(mut self, ctx: &ExecutionContext) -> Self {
696 self.params = CompactArc::clone(ctx.params_arc());
698 self.named_params = Arc::clone(ctx.named_params_arc());
700 self.transaction_id = ctx.transaction_id();
701 self.stored_function_invoker = ctx.stored_function_invoker().cloned();
702 self.outer_row = ctx.outer_row().cloned().map(Arc::new);
703 self
704 }
705
706 pub fn from_program(program: SharedProgram) -> Self {
708 Self {
709 program,
710 params: CompactArc::new(ParamVec::new()),
711 named_params: Arc::new(FxHashMap::default()),
712 transaction_id: None,
713 stored_function_invoker: None,
714 outer_row: None,
715 }
716 }
717
718 #[inline]
723 pub fn matches(&self, row: &Row) -> Result<bool> {
724 thread_local! {
726 static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
727 }
728
729 VM.with(|vm| {
730 let mut ctx = ExecuteContext::new(row);
731
732 if !self.params.is_empty() {
733 ctx = ctx.with_params(&self.params);
734 }
735 if !self.named_params.is_empty() {
736 ctx = ctx.with_named_params(&self.named_params);
737 }
738 if let Some(outer_row) = self.outer_row.as_deref() {
739 ctx = ctx.with_outer_row(outer_row);
740 }
741 ctx = ctx
742 .with_transaction_id(self.transaction_id)
743 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
744
745 if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
748 borrowed_vm.execute_bool(&self.program, &ctx)
749 } else {
750 let mut temp_vm = ExprVM::new();
752 temp_vm.execute_bool(&self.program, &ctx)
753 }
754 })
755 }
756
757 #[inline]
760 pub fn matches_checked(&self, row: &Row) -> Result<bool> {
761 thread_local! {
762 static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
763 }
764
765 VM.with(|vm| {
766 let mut ctx = ExecuteContext::new(row);
767
768 if !self.params.is_empty() {
769 ctx = ctx.with_params(&self.params);
770 }
771 if !self.named_params.is_empty() {
772 ctx = ctx.with_named_params(&self.named_params);
773 }
774 if let Some(outer_row) = self.outer_row.as_deref() {
775 ctx = ctx.with_outer_row(outer_row);
776 }
777 ctx = ctx
778 .with_transaction_id(self.transaction_id)
779 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
780
781 if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
782 borrowed_vm.execute_bool_checked(&self.program, &ctx)
783 } else {
784 let mut temp_vm = ExprVM::new();
785 temp_vm.execute_bool_checked(&self.program, &ctx)
786 }
787 })
788 }
789
790 #[inline]
792 pub fn matches_deferred_checked(&self, row: &radixdb_storage::DeferredRow) -> Result<bool> {
793 thread_local! {
794 static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
795 }
796
797 VM.with(|vm| {
798 let mut ctx = ExecuteContext::for_deferred(row);
799
800 if !self.params.is_empty() {
801 ctx = ctx.with_params(&self.params);
802 }
803 if !self.named_params.is_empty() {
804 ctx = ctx.with_named_params(&self.named_params);
805 }
806 if let Some(outer_row) = self.outer_row.as_deref() {
807 ctx = ctx.with_outer_row(outer_row);
808 }
809 ctx = ctx
810 .with_transaction_id(self.transaction_id)
811 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
812
813 if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
814 borrowed_vm.execute_bool_checked(&self.program, &ctx)
815 } else {
816 let mut temp_vm = ExprVM::new();
817 temp_vm.execute_bool_checked(&self.program, &ctx)
818 }
819 })
820 }
821
822 #[inline]
824 pub fn matches_row_ref_checked(&self, row: &crate::operator::RowRef) -> Result<bool> {
825 thread_local! {
826 static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
827 }
828
829 VM.with(|vm| {
830 let mut ctx = ExecuteContext::for_row_ref(row);
831
832 if !self.params.is_empty() {
833 ctx = ctx.with_params(&self.params);
834 }
835 if !self.named_params.is_empty() {
836 ctx = ctx.with_named_params(&self.named_params);
837 }
838 if let Some(outer_row) = self.outer_row.as_deref() {
839 ctx = ctx.with_outer_row(outer_row);
840 }
841 ctx = ctx
842 .with_transaction_id(self.transaction_id)
843 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
844
845 if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
846 borrowed_vm.execute_bool_checked(&self.program, &ctx)
847 } else {
848 ExprVM::new().execute_bool_checked(&self.program, &ctx)
849 }
850 })
851 }
852
853 pub fn retain_checked(&self, rows: &mut radixdb_core::RowVec) -> Result<()> {
857 let mut error: Option<radixdb_core::Error> = None;
858 rows.retain(|(_, row)| {
859 if error.is_some() {
860 return false;
861 }
862 match self.matches_checked(row) {
863 Ok(b) => b,
864 Err(e) => {
865 error = Some(e);
866 false
867 }
868 }
869 });
870 match error {
871 Some(e) => Err(e),
872 None => Ok(()),
873 }
874 }
875
876 #[inline]
878 pub fn evaluate(&self, row: &Row) -> Result<Value> {
879 thread_local! {
880 static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
881 }
882
883 VM.with(|vm| {
884 let mut ctx = ExecuteContext::new(row);
885
886 if !self.params.is_empty() {
887 ctx = ctx.with_params(&self.params);
888 }
889 if !self.named_params.is_empty() {
890 ctx = ctx.with_named_params(&self.named_params);
891 }
892 ctx = ctx
893 .with_transaction_id(self.transaction_id)
894 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
895
896 if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
899 borrowed_vm.execute_cow(&self.program, &ctx)
900 } else {
901 let mut temp_vm = ExprVM::new();
903 temp_vm.execute_cow(&self.program, &ctx)
904 }
905 })
906 }
907
908 pub fn program(&self) -> &SharedProgram {
910 &self.program
911 }
912}
913
914const _: () = {
922 const fn assert_send_sync<T: Send + Sync>() {}
923 let _ = assert_send_sync::<RowFilter>;
924};
925
926#[derive(Clone)]
932pub struct JoinFilter {
933 program: SharedProgram,
935 params: CompactArc<ParamVec>,
937 named_params: Arc<FxHashMap<String, Value>>,
939 transaction_id: Option<u64>,
941 stored_function_invoker: Option<Arc<dyn StoredFunctionInvoker>>,
942}
943
944impl JoinFilter {
945 pub fn new(
952 expr: &Expression,
953 left_columns: &[String],
954 right_columns: &[String],
955 function_registry: &FunctionRegistry,
956 ) -> Result<Self> {
957 let ctx =
958 CompileContext::new(left_columns, function_registry).with_second_row(right_columns);
959 let compiler = ExprCompiler::new(&ctx);
960 let program = compiler
961 .compile(expr)
962 .map_err(|e| Error::internal(format!("Compile error: {}", e)))?;
963 Ok(Self {
964 program: CompactArc::new(program),
965 params: CompactArc::new(ParamVec::new()),
966 named_params: Arc::new(FxHashMap::default()),
967 transaction_id: None,
968 stored_function_invoker: None,
969 })
970 }
971
972 #[inline]
975 pub fn with_context(mut self, ctx: &ExecutionContext) -> Self {
976 self.params = CompactArc::clone(ctx.params_arc());
977 self.named_params = Arc::clone(ctx.named_params_arc());
978 self.transaction_id = ctx.transaction_id();
979 self.stored_function_invoker = ctx.stored_function_invoker().cloned();
980 self
981 }
982
983 #[inline]
985 pub fn matches(&self, left_row: &Row, right_row: &Row) -> Result<bool> {
986 thread_local! {
987 static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
988 }
989
990 VM.with(|vm| {
991 let mut ctx = ExecuteContext::for_join(left_row, right_row)
992 .with_transaction_id(self.transaction_id)
993 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
994
995 if !self.params.is_empty() {
997 ctx = ctx.with_params(&self.params);
998 }
999 if !self.named_params.is_empty() {
1000 ctx = ctx.with_named_params(&self.named_params);
1001 }
1002
1003 if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
1006 borrowed_vm.execute_bool(&self.program, &ctx)
1007 } else {
1008 let mut temp_vm = ExprVM::new();
1010 temp_vm.execute_bool(&self.program, &ctx)
1011 }
1012 })
1013 }
1014
1015 #[inline]
1018 pub fn matches_checked(&self, left_row: &Row, right_row: &Row) -> Result<bool> {
1019 thread_local! {
1020 static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
1021 }
1022
1023 VM.with(|vm| {
1024 let mut ctx = ExecuteContext::for_join(left_row, right_row)
1025 .with_transaction_id(self.transaction_id)
1026 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1027 if !self.params.is_empty() {
1028 ctx = ctx.with_params(&self.params);
1029 }
1030 if !self.named_params.is_empty() {
1031 ctx = ctx.with_named_params(&self.named_params);
1032 }
1033
1034 if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
1035 borrowed_vm.execute_bool_checked(&self.program, &ctx)
1036 } else {
1037 ExprVM::new().execute_bool_checked(&self.program, &ctx)
1038 }
1039 })
1040 }
1041
1042 #[inline]
1048 pub fn matches_row_ref_checked(
1049 &self,
1050 left_row: &crate::operator::RowRef,
1051 right_row: &Row,
1052 ) -> Result<bool> {
1053 thread_local! {
1054 static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
1055 }
1056
1057 VM.with(|vm| {
1058 let mut ctx = ExecuteContext::for_join_ref(left_row, right_row)
1059 .with_transaction_id(self.transaction_id)
1060 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1061 if !self.params.is_empty() {
1062 ctx = ctx.with_params(&self.params);
1063 }
1064 if !self.named_params.is_empty() {
1065 ctx = ctx.with_named_params(&self.named_params);
1066 }
1067
1068 if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
1069 borrowed_vm.execute_bool_checked(&self.program, &ctx)
1070 } else {
1071 ExprVM::new().execute_bool_checked(&self.program, &ctx)
1072 }
1073 })
1074 }
1075
1076 #[inline]
1081 pub fn matches_row_refs_checked(
1082 &self,
1083 left_row: &crate::operator::RowRef,
1084 right_row: &crate::operator::RowRef,
1085 ) -> Result<bool> {
1086 thread_local! {
1087 static VM: std::cell::RefCell<ExprVM> = std::cell::RefCell::new(ExprVM::new());
1088 }
1089
1090 VM.with(|vm| {
1091 let mut ctx = ExecuteContext::for_join_refs(left_row, right_row)
1092 .with_transaction_id(self.transaction_id)
1093 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1094 if !self.params.is_empty() {
1095 ctx = ctx.with_params(&self.params);
1096 }
1097 if !self.named_params.is_empty() {
1098 ctx = ctx.with_named_params(&self.named_params);
1099 }
1100
1101 if let Ok(mut borrowed_vm) = vm.try_borrow_mut() {
1102 borrowed_vm.execute_bool_checked(&self.program, &ctx)
1103 } else {
1104 ExprVM::new().execute_bool_checked(&self.program, &ctx)
1105 }
1106 })
1107 }
1108
1109 pub fn program(&self) -> &SharedProgram {
1111 &self.program
1112 }
1113}
1114
1115const _: () = {
1119 const fn assert_send_sync<T: Send + Sync>() {}
1120 let _ = assert_send_sync::<JoinFilter>;
1121};
1122
1123pub struct ExpressionEval {
1148 program: SharedProgram,
1150 vm: ExprVM,
1152 params: CompactArc<ParamVec>,
1154 named_params: Arc<FxHashMap<String, Value>>,
1156 outer_row: Option<FxHashMap<CompactArc<str>, Value>>,
1158 transaction_id: Option<u64>,
1160 stored_function_invoker: Option<Arc<dyn StoredFunctionInvoker>>,
1161}
1162
1163impl ExpressionEval {
1164 pub fn compile(expr: &Expression, columns: &[String]) -> Result<Self> {
1166 let program = compile_expression(expr, columns)?;
1167 Ok(Self {
1168 program,
1169 vm: ExprVM::new(),
1170 params: CompactArc::new(ParamVec::new()),
1171 named_params: Arc::new(FxHashMap::default()),
1172 outer_row: None,
1173 transaction_id: None,
1174 stored_function_invoker: None,
1175 })
1176 }
1177
1178 pub fn compile_with_aliases(
1196 expr: &Expression,
1197 columns: &[String],
1198 aliases: &[(String, usize)],
1199 ) -> Result<Self> {
1200 let alias_map = checked_alias_map(aliases)?;
1201
1202 Self::compile_with_options(
1203 expr,
1204 columns,
1205 None,
1206 None,
1207 Some(alias_map),
1208 global_registry(),
1209 )
1210 }
1211
1212 pub fn compile_with_options(
1214 expr: &Expression,
1215 columns: &[String],
1216 columns2: Option<&[String]>,
1217 outer_columns: Option<&[String]>,
1218 expression_aliases: Option<StringMap<u16>>,
1219 function_registry: &FunctionRegistry,
1220 ) -> Result<Self> {
1221 let mut ctx = CompileContext::new(columns, function_registry);
1222 if let Some(cols2) = columns2 {
1223 ctx = ctx.with_second_row(cols2);
1224 }
1225 if let Some(outer) = outer_columns {
1226 ctx = ctx.with_outer_columns(outer);
1227 }
1228 if let Some(aliases) = expression_aliases {
1229 ctx = ctx.with_expression_aliases(aliases);
1230 }
1231 let compiler = ExprCompiler::new(&ctx);
1232 let program = compiler
1233 .compile(expr)
1234 .map(CompactArc::new)
1235 .map_err(|e| Error::internal(format!("Compile error: {}", e)))?;
1236 Ok(Self {
1237 program,
1238 vm: ExprVM::new(),
1239 params: CompactArc::new(ParamVec::new()),
1240 named_params: Arc::new(FxHashMap::default()),
1241 outer_row: None,
1242 transaction_id: None,
1243 stored_function_invoker: None,
1244 })
1245 }
1246
1247 pub fn from_program(program: SharedProgram) -> Self {
1249 Self {
1250 program,
1251 vm: ExprVM::new(),
1252 params: CompactArc::new(ParamVec::new()),
1253 named_params: Arc::new(FxHashMap::default()),
1254 outer_row: None,
1255 transaction_id: None,
1256 stored_function_invoker: None,
1257 }
1258 }
1259
1260 pub fn with_params(mut self, params: ParamVec) -> Self {
1262 self.params = CompactArc::new(params);
1263 self
1264 }
1265
1266 pub fn with_named_params(mut self, named_params: FxHashMap<String, Value>) -> Self {
1268 self.named_params = Arc::new(named_params);
1269 self
1270 }
1271
1272 pub fn with_context(mut self, ctx: &ExecutionContext) -> Self {
1276 self.params = CompactArc::clone(ctx.params_arc());
1278 self.named_params = Arc::clone(ctx.named_params_arc());
1280 if let Some(outer) = ctx.outer_row() {
1281 let arc_map = outer.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
1283 self.outer_row = Some(arc_map);
1284 }
1285 self.transaction_id = ctx.transaction_id();
1286 self.stored_function_invoker = ctx.stored_function_invoker().cloned();
1287 self
1288 }
1289
1290 pub fn with_transaction_id(mut self, txn_id: Option<u64>) -> Self {
1292 self.transaction_id = txn_id;
1293 self
1294 }
1295
1296 pub fn set_outer_row(&mut self, outer: &FxHashMap<CompactArc<str>, Value>) {
1299 let map = outer.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
1301 self.outer_row = Some(map);
1302 }
1303
1304 pub fn clear_outer_row(&mut self) {
1306 self.outer_row = None;
1307 }
1308
1309 #[inline]
1311 pub fn eval(&mut self, row: &Row) -> Result<Value> {
1312 let mut ctx = ExecuteContext::new(row);
1313
1314 if !self.params.is_empty() {
1315 ctx = ctx.with_params(&self.params);
1316 }
1317 if !self.named_params.is_empty() {
1318 ctx = ctx.with_named_params(&self.named_params);
1319 }
1320 if let Some(ref outer) = self.outer_row {
1321 ctx = ctx.with_outer_row(outer);
1322 }
1323 ctx = ctx
1324 .with_transaction_id(self.transaction_id)
1325 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1326
1327 self.vm.execute_cow(&self.program, &ctx)
1328 }
1329
1330 #[inline]
1332 pub fn eval_bool(&mut self, row: &Row) -> Result<bool> {
1333 let mut ctx = ExecuteContext::new(row);
1334
1335 if !self.params.is_empty() {
1336 ctx = ctx.with_params(&self.params);
1337 }
1338 if !self.named_params.is_empty() {
1339 ctx = ctx.with_named_params(&self.named_params);
1340 }
1341 if let Some(ref outer) = self.outer_row {
1342 ctx = ctx.with_outer_row(outer);
1343 }
1344 ctx = ctx
1345 .with_transaction_id(self.transaction_id)
1346 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1347
1348 self.vm.execute_bool(&self.program, &ctx)
1349 }
1350
1351 #[inline]
1353 pub fn eval_bool_checked(&mut self, row: &Row) -> Result<bool> {
1354 let mut ctx = ExecuteContext::new(row);
1355
1356 if !self.params.is_empty() {
1357 ctx = ctx.with_params(&self.params);
1358 }
1359 if !self.named_params.is_empty() {
1360 ctx = ctx.with_named_params(&self.named_params);
1361 }
1362 if let Some(ref outer) = self.outer_row {
1363 ctx = ctx.with_outer_row(outer);
1364 }
1365 ctx = ctx
1366 .with_transaction_id(self.transaction_id)
1367 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1368
1369 self.vm.execute_bool_checked(&self.program, &ctx)
1370 }
1371
1372 #[inline]
1374 pub fn eval_join(&mut self, left: &Row, right: &Row) -> Result<Value> {
1375 let ctx = ExecuteContext::for_join(left, right)
1376 .with_transaction_id(self.transaction_id)
1377 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1378 self.vm.execute_cow(&self.program, &ctx)
1379 }
1380
1381 #[inline]
1383 pub fn eval_join_bool(&mut self, left: &Row, right: &Row) -> Result<bool> {
1384 let ctx = ExecuteContext::for_join(left, right)
1385 .with_transaction_id(self.transaction_id)
1386 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1387 self.vm.execute_bool(&self.program, &ctx)
1388 }
1389
1390 #[inline]
1392 pub fn eval_slice(&mut self, row: &Row) -> Result<Value> {
1393 let mut ctx = ExecuteContext::new(row);
1394
1395 if !self.params.is_empty() {
1396 ctx = ctx.with_params(&self.params);
1397 }
1398 if !self.named_params.is_empty() {
1399 ctx = ctx.with_named_params(&self.named_params);
1400 }
1401 if let Some(ref outer) = self.outer_row {
1402 ctx = ctx.with_outer_row(outer);
1403 }
1404 ctx = ctx
1405 .with_transaction_id(self.transaction_id)
1406 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1407
1408 self.vm.execute_cow(&self.program, &ctx)
1409 }
1410
1411 #[inline]
1413 pub fn eval_slice_bool(&mut self, row: &Row) -> Result<bool> {
1414 let mut ctx = ExecuteContext::new(row);
1415
1416 if !self.params.is_empty() {
1417 ctx = ctx.with_params(&self.params);
1418 }
1419 if !self.named_params.is_empty() {
1420 ctx = ctx.with_named_params(&self.named_params);
1421 }
1422 if let Some(ref outer) = self.outer_row {
1423 ctx = ctx.with_outer_row(outer);
1424 }
1425 ctx = ctx
1426 .with_transaction_id(self.transaction_id)
1427 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1428
1429 self.vm.execute_bool(&self.program, &ctx)
1430 }
1431
1432 pub fn program(&self) -> &SharedProgram {
1434 &self.program
1435 }
1436}
1437
1438pub struct MultiExpressionEval {
1446 programs: Vec<SharedProgram>,
1448 vm: ExprVM,
1450 params: CompactArc<ParamVec>,
1452 named_params: Arc<FxHashMap<String, Value>>,
1454 transaction_id: Option<u64>,
1456 stored_function_invoker: Option<Arc<dyn StoredFunctionInvoker>>,
1457}
1458
1459impl MultiExpressionEval {
1460 pub fn compile(exprs: &[Expression], columns: &[String]) -> Result<Self> {
1462 let ctx = CompileContext::with_global_registry(columns);
1463 let compiler = ExprCompiler::new(&ctx);
1464
1465 let programs = exprs
1466 .iter()
1467 .map(|expr| {
1468 compiler
1469 .compile(expr)
1470 .map(CompactArc::new)
1471 .map_err(|e| Error::internal(format!("Compile error: {}", e)))
1472 })
1473 .collect::<Result<Vec<_>>>()?;
1474
1475 Ok(Self {
1476 programs,
1477 vm: ExprVM::new(),
1478 params: CompactArc::new(ParamVec::new()),
1479 named_params: Arc::new(FxHashMap::default()),
1480 transaction_id: None,
1481 stored_function_invoker: None,
1482 })
1483 }
1484
1485 pub fn compile_with_aliases(
1496 exprs: &[Expression],
1497 columns: &[String],
1498 aliases: &[(String, usize)],
1499 ) -> Result<Self> {
1500 let alias_map = checked_alias_map(aliases)?;
1501
1502 let ctx = CompileContext::with_global_registry(columns).with_expression_aliases(alias_map);
1503 let compiler = ExprCompiler::new(&ctx);
1504
1505 let programs = exprs
1506 .iter()
1507 .map(|expr| {
1508 compiler
1509 .compile(expr)
1510 .map(CompactArc::new)
1511 .map_err(|e| Error::internal(format!("Compile error: {}", e)))
1512 })
1513 .collect::<Result<Vec<_>>>()?;
1514
1515 Ok(Self {
1516 programs,
1517 vm: ExprVM::new(),
1518 params: CompactArc::new(ParamVec::new()),
1519 named_params: Arc::new(FxHashMap::default()),
1520 transaction_id: None,
1521 stored_function_invoker: None,
1522 })
1523 }
1524
1525 pub fn with_params(mut self, params: ParamVec) -> Self {
1527 self.params = CompactArc::new(params);
1528 self
1529 }
1530
1531 pub fn with_context(mut self, ctx: &ExecutionContext) -> Self {
1535 self.params = CompactArc::clone(ctx.params_arc());
1537 self.named_params = Arc::clone(ctx.named_params_arc());
1539 self.transaction_id = ctx.transaction_id();
1540 self.stored_function_invoker = ctx.stored_function_invoker().cloned();
1541 self
1542 }
1543
1544 #[inline]
1546 pub fn eval_all(&mut self, row: &Row) -> Result<Vec<Value>> {
1547 let mut ctx = ExecuteContext::new(row);
1548
1549 if !self.params.is_empty() {
1550 ctx = ctx.with_params(&self.params);
1551 }
1552 if !self.named_params.is_empty() {
1553 ctx = ctx.with_named_params(&self.named_params);
1554 }
1555 ctx = ctx
1556 .with_transaction_id(self.transaction_id)
1557 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1558
1559 self.programs
1560 .iter()
1561 .map(|prog| self.vm.execute_cow(prog, &ctx))
1562 .collect()
1563 }
1564
1565 #[inline]
1567 pub fn eval_into(&mut self, row: &Row, output: &mut Vec<Value>) -> Result<()> {
1568 let mut ctx = ExecuteContext::new(row);
1569
1570 if !self.params.is_empty() {
1571 ctx = ctx.with_params(&self.params);
1572 }
1573 if !self.named_params.is_empty() {
1574 ctx = ctx.with_named_params(&self.named_params);
1575 }
1576 ctx = ctx
1577 .with_transaction_id(self.transaction_id)
1578 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
1579
1580 output.clear();
1581 for prog in &self.programs {
1582 output.push(self.vm.execute_cow(prog, &ctx)?);
1583 }
1584 Ok(())
1585 }
1586
1587 pub fn len(&self) -> usize {
1589 self.programs.len()
1590 }
1591
1592 pub fn is_empty(&self) -> bool {
1594 self.programs.is_empty()
1595 }
1596}
1597
1598pub type SharedProgram = CompactArc<Program>;
1600
1601pub struct CompiledEvaluator<'a> {
1651 function_registry: &'a FunctionRegistry,
1653
1654 columns: CompactArc<Vec<String>>,
1656
1657 columns2: Option<Vec<String>>,
1659
1660 outer_columns: Option<Vec<String>>,
1662
1663 params: CompactArc<ParamVec>,
1665
1666 named_params: Arc<FxHashMap<String, Value>>,
1668
1669 outer_row: Option<FxHashMap<CompactArc<str>, Value>>,
1671
1672 transaction_id: Option<u64>,
1674 stored_function_invoker: Option<Arc<dyn StoredFunctionInvoker>>,
1675
1676 expression_aliases: StringMap<u16>,
1678
1679 column_aliases: StringMap<String>,
1681
1682 vm: ExprVM,
1684
1685 local_cache: FxHashMap<u64, LocalProgramCacheEntry>,
1687
1688 context_errors: Vec<String>,
1690
1691 current_row: Option<Row>,
1693
1694 current_row2: Option<Row>,
1696}
1697
1698impl<'a> CompiledEvaluator<'a> {
1703 pub fn new(function_registry: &'a FunctionRegistry) -> Self {
1705 Self {
1706 function_registry,
1707 columns: CompactArc::new(Vec::new()),
1708 columns2: None,
1709 outer_columns: None,
1710 params: CompactArc::new(ParamVec::new()),
1711 named_params: Arc::new(FxHashMap::default()),
1712 outer_row: None,
1713 transaction_id: None,
1714 stored_function_invoker: None,
1715 expression_aliases: StringMap::new(),
1716 column_aliases: StringMap::new(),
1717 vm: ExprVM::new(),
1718 local_cache: FxHashMap::default(),
1719 context_errors: Vec::new(),
1720 current_row: None,
1721 current_row2: None,
1722 }
1723 }
1724
1725 pub fn with_defaults() -> CompiledEvaluator<'static> {
1727 CompiledEvaluator::new(global_registry())
1728 }
1729
1730 fn column_limit_error(label: &str, len: usize) -> Option<String> {
1731 (len > (u16::MAX as usize + 1)).then(|| {
1732 format!(
1733 "{label} has {len} columns; expression bytecode supports at most {}",
1734 u16::MAX as usize + 1
1735 )
1736 })
1737 }
1738
1739 pub fn clear(&mut self) {
1741 self.columns = CompactArc::new(Vec::new());
1742 self.columns2 = None;
1743 self.outer_columns = None;
1744 self.params = CompactArc::new(ParamVec::new());
1745 self.named_params = Arc::new(FxHashMap::default());
1746 self.outer_row = None;
1747 self.transaction_id = None;
1748 self.stored_function_invoker = None;
1749 self.expression_aliases.clear();
1750 self.column_aliases.clear();
1751 self.local_cache.clear();
1752 self.context_errors.clear();
1753 self.current_row = None;
1754 self.current_row2 = None;
1755 }
1756
1757 fn replace_context_error(&mut self, label: &str, error: Option<String>) {
1758 self.context_errors
1759 .retain(|existing| !existing.starts_with(label));
1760 if let Some(error) = error {
1761 self.context_errors.push(error);
1762 }
1763 }
1764
1765 fn context_error(&self) -> Option<String> {
1766 (!self.context_errors.is_empty()).then(|| self.context_errors.join("; "))
1767 }
1768
1769 pub fn set_transaction_id(&mut self, txn_id: u64) {
1771 self.transaction_id = Some(txn_id);
1772 }
1773
1774 pub fn with_params(mut self, params: ParamVec) -> Self {
1776 self.params = CompactArc::new(params);
1777 self
1778 }
1779
1780 pub fn with_named_params(mut self, named_params: FxHashMap<String, Value>) -> Self {
1782 self.named_params = Arc::new(named_params);
1783 self
1784 }
1785
1786 pub fn with_context(mut self, ctx: &ExecutionContext) -> Self {
1790 self.params = CompactArc::clone(ctx.params_arc());
1792 self.named_params = Arc::clone(ctx.named_params_arc());
1794
1795 if let Some(outer) = ctx.outer_row() {
1797 let arc_map = outer.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
1799 let outer_cols: Vec<String> = outer.keys().map(|k| k.to_string()).collect();
1801 self.outer_row = Some(arc_map);
1802 if !outer_cols.is_empty() {
1804 self.outer_columns = Some(outer_cols);
1805 let error = Self::column_limit_error(
1806 "outer row",
1807 self.outer_columns.as_ref().map_or(0, Vec::len),
1808 );
1809 self.replace_context_error("outer row", error);
1810 self.local_cache.clear();
1812 }
1813 }
1814
1815 self.transaction_id = ctx.transaction_id();
1816 self.stored_function_invoker = ctx.stored_function_invoker().cloned();
1817 self
1818 }
1819
1820 pub fn with_row(mut self, row: Row, columns: &[String]) -> Self {
1822 self.init_columns(columns);
1823 self.current_row = Some(row);
1824 self.current_row2 = None;
1825 self
1826 }
1827
1828 pub fn init_columns(&mut self, columns: &[String]) {
1833 if self.columns.as_ref() == columns {
1834 return;
1835 }
1836
1837 self.columns = CompactArc::new(columns.to_vec());
1838 let error = Self::column_limit_error("primary row", columns.len());
1839 self.replace_context_error("primary row", error);
1840 self.local_cache.clear();
1842 }
1843
1844 #[inline]
1849 pub fn init_columns_arc(&mut self, columns: CompactArc<Vec<String>>) {
1850 if self.columns.as_ref() == columns.as_ref() {
1851 return;
1852 }
1853
1854 let error = Self::column_limit_error("primary row", columns.len());
1855 self.replace_context_error("primary row", error);
1856 self.columns = columns;
1857 self.local_cache.clear();
1859 }
1860
1861 pub fn add_aggregate_aliases(&mut self, aliases: &[(String, usize)]) {
1863 for (expr_name, idx) in aliases {
1864 let lower = expr_name.to_lowercase();
1865 match u16::try_from(*idx) {
1866 Ok(index) => {
1867 self.expression_aliases.insert(lower, index);
1868 }
1869 Err(_) => {
1870 self.context_errors.push(format!(
1871 "expression alias '{}' index {} exceeds the u16 bytecode limit",
1872 expr_name, idx
1873 ));
1874 }
1875 }
1876 }
1877 self.local_cache.clear();
1879 }
1880
1881 pub fn add_expression_aliases(&mut self, aliases: &[(String, usize)]) {
1883 for (expr_str, idx) in aliases {
1884 let lower = expr_str.to_lowercase();
1885 match u16::try_from(*idx) {
1886 Ok(index) => {
1887 self.expression_aliases.insert(lower, index);
1888 }
1889 Err(_) => {
1890 self.context_errors.push(format!(
1891 "expression alias '{}' index {} exceeds the u16 bytecode limit",
1892 expr_str, idx
1893 ));
1894 }
1895 }
1896 }
1897 self.local_cache.clear();
1899 }
1900
1901 #[inline]
1904 pub fn set_row_array(&mut self, row: &Row) {
1905 self.current_row = Some(row.clone());
1906 self.current_row2 = None;
1908 }
1909
1910 #[inline]
1913 pub fn set_outer_row(&mut self, outer_row: Option<&FxHashMap<CompactArc<str>, Value>>) {
1914 if let Some(outer) = outer_row {
1915 let map = outer.iter().map(|(k, v)| (k.clone(), v.clone())).collect();
1917 self.outer_row = Some(map);
1918 } else {
1919 self.outer_row = None;
1920 }
1921 }
1922
1923 #[inline]
1926 pub fn set_outer_row_owned(&mut self, outer_row: FxHashMap<CompactArc<str>, Value>) {
1927 let outer_cols: Vec<String> = outer_row.keys().map(|k| k.to_string()).collect();
1929 self.outer_row = Some(outer_row);
1930 if !outer_cols.is_empty() {
1932 let mut sorted_cols = outer_cols;
1934 sorted_cols.sort();
1935 self.outer_columns = Some(sorted_cols);
1936 let error = Self::column_limit_error(
1937 "outer row",
1938 self.outer_columns.as_ref().map_or(0, Vec::len),
1939 );
1940 self.replace_context_error("outer row", error);
1941 self.local_cache.clear();
1943 }
1944 }
1945
1946 #[inline]
1949 pub fn take_outer_row(&mut self) -> FxHashMap<CompactArc<str>, Value> {
1950 self.outer_row.take().unwrap_or_default()
1951 }
1952
1953 #[inline]
1955 pub fn clear_outer_row(&mut self) {
1956 self.outer_row = None;
1957 }
1958
1959 #[inline]
1963 fn expr_hash(&self, expr: &Expression) -> u64 {
1964 let mut hasher = FxHasher::default();
1965 Self::hash_expression(expr, &mut hasher);
1966 hasher.finish()
1967 }
1968
1969 fn hash_expression(expr: &Expression, hasher: &mut FxHasher) {
1971 std::mem::discriminant(expr).hash(hasher);
1973
1974 match expr {
1975 Expression::Identifier(id) => {
1976 id.value_lower.hash(hasher);
1977 }
1978 Expression::QualifiedIdentifier(qid) => {
1979 qid.qualifier.value_lower.hash(hasher);
1980 qid.name.value_lower.hash(hasher);
1981 }
1982 Expression::IntegerLiteral(lit) => {
1983 lit.value.hash(hasher);
1984 }
1985 Expression::FloatLiteral(lit) => {
1986 lit.value.to_bits().hash(hasher);
1987 }
1988 Expression::StringLiteral(lit) => {
1989 lit.value.hash(hasher);
1990 lit.type_hint.hash(hasher);
1991 }
1992 Expression::BooleanLiteral(lit) => {
1993 lit.value.hash(hasher);
1994 }
1995 Expression::NullLiteral(_) => {
1996 }
1998 Expression::BoundValue(value) => {
1999 value.hash(hasher);
2000 }
2001 Expression::IntervalLiteral(lit) => {
2002 lit.value.hash(hasher);
2003 lit.unit.hash(hasher);
2004 }
2005 Expression::Parameter(param) => {
2006 param.index.hash(hasher);
2007 param.name.hash(hasher);
2008 }
2009 Expression::Prefix(prefix) => {
2010 std::mem::discriminant(&prefix.op_type).hash(hasher);
2011 Self::hash_expression(&prefix.right, hasher);
2012 }
2013 Expression::Infix(infix) => {
2014 std::mem::discriminant(&infix.op_type).hash(hasher);
2015 Self::hash_expression(&infix.left, hasher);
2016 Self::hash_expression(&infix.right, hasher);
2017 }
2018 Expression::List(list) => {
2019 list.elements.len().hash(hasher);
2020 for val in &list.elements {
2021 Self::hash_expression(val, hasher);
2022 }
2023 }
2024 Expression::Distinct(dist) => {
2025 Self::hash_expression(&dist.expr, hasher);
2026 }
2027 Expression::Exists(exists) => {
2028 (exists.subquery.as_ref() as *const _ as usize).hash(hasher);
2030 }
2031 Expression::AllAny(aa) => {
2032 aa.operator.hash(hasher);
2033 std::mem::discriminant(&aa.all_any_type).hash(hasher);
2034 Self::hash_expression(&aa.left, hasher);
2035 (aa.subquery.as_ref() as *const _ as usize).hash(hasher);
2037 }
2038 Expression::In(in_expr) => {
2039 in_expr.not.hash(hasher);
2040 Self::hash_expression(&in_expr.left, hasher);
2041 Self::hash_expression(&in_expr.right, hasher);
2042 }
2043 Expression::InHashSet(in_hash) => {
2044 in_hash.not.hash(hasher);
2045 Self::hash_expression(&in_hash.column, hasher);
2046 let mut values: Vec<&Value> = in_hash.values.iter().collect();
2047 values.sort_unstable();
2048 values.hash(hasher);
2049 }
2050 Expression::Between(between) => {
2051 between.not.hash(hasher);
2052 Self::hash_expression(&between.expr, hasher);
2053 Self::hash_expression(&between.lower, hasher);
2054 Self::hash_expression(&between.upper, hasher);
2055 }
2056 Expression::Like(like) => {
2057 like.operator.hash(hasher);
2058 Self::hash_expression(&like.left, hasher);
2059 Self::hash_expression(&like.pattern, hasher);
2060 if let Some(ref escape) = like.escape {
2061 true.hash(hasher);
2062 Self::hash_expression(escape, hasher);
2063 } else {
2064 false.hash(hasher);
2065 }
2066 }
2067 Expression::ScalarSubquery(sq) => {
2068 (sq.subquery.as_ref() as *const _ as usize).hash(hasher);
2070 }
2071 Expression::ExpressionList(list) => {
2072 list.expressions.len().hash(hasher);
2073 for expr in &list.expressions {
2074 Self::hash_expression(expr, hasher);
2075 }
2076 }
2077 Expression::Case(case) => {
2078 if let Some(ref val) = case.value {
2079 true.hash(hasher);
2080 Self::hash_expression(val, hasher);
2081 } else {
2082 false.hash(hasher);
2083 }
2084 case.when_clauses.len().hash(hasher);
2085 for when_clause in &case.when_clauses {
2086 Self::hash_expression(&when_clause.condition, hasher);
2087 Self::hash_expression(&when_clause.then_result, hasher);
2088 }
2089 if let Some(ref else_val) = case.else_value {
2090 true.hash(hasher);
2091 Self::hash_expression(else_val, hasher);
2092 } else {
2093 false.hash(hasher);
2094 }
2095 }
2096 Expression::Cast(cast) => {
2097 Self::hash_expression(&cast.expr, hasher);
2098 cast.type_name.hash(hasher);
2099 }
2100 Expression::FunctionCall(func) => {
2101 func.function.hash(hasher);
2102 func.is_distinct.hash(hasher);
2103 func.arguments.len().hash(hasher);
2104 for arg in &func.arguments {
2105 Self::hash_expression(arg, hasher);
2106 }
2107 if let Some(ref filter) = func.filter {
2108 true.hash(hasher);
2109 Self::hash_expression(filter, hasher);
2110 } else {
2111 false.hash(hasher);
2112 }
2113 }
2114 Expression::Aliased(aliased) => {
2115 aliased.alias.value_lower.hash(hasher);
2116 Self::hash_expression(&aliased.expression, hasher);
2117 }
2118 Expression::Window(window) => {
2119 window.function.function.hash(hasher);
2121 window.function.is_distinct.hash(hasher);
2122 window.function.arguments.len().hash(hasher);
2123 for arg in &window.function.arguments {
2124 Self::hash_expression(arg, hasher);
2125 }
2126 window.partition_by.len().hash(hasher);
2127 for expr in &window.partition_by {
2128 Self::hash_expression(expr, hasher);
2129 }
2130 window.order_by.len().hash(hasher);
2131 for order in &window.order_by {
2132 Self::hash_expression(&order.expression, hasher);
2133 order.ascending.hash(hasher);
2134 order.nulls_first.hash(hasher);
2135 }
2136 }
2137 Expression::TableSource(ts) => {
2138 ts.name.value_lower.hash(hasher);
2139 if let Some(ref alias) = ts.alias {
2140 true.hash(hasher);
2141 alias.value_lower.hash(hasher);
2142 } else {
2143 false.hash(hasher);
2144 }
2145 }
2146 Expression::JoinSource(js) => {
2147 (js.as_ref() as *const _ as usize).hash(hasher);
2149 }
2150 Expression::SubquerySource(sq) => {
2151 if let Some(ref alias) = sq.alias {
2152 true.hash(hasher);
2153 alias.value_lower.hash(hasher);
2154 } else {
2155 false.hash(hasher);
2156 }
2157 (sq.subquery.as_ref() as *const _ as usize).hash(hasher);
2159 }
2160 Expression::ValuesSource(vs) => {
2161 if let Some(ref alias) = vs.alias {
2162 true.hash(hasher);
2163 alias.value_lower.hash(hasher);
2164 } else {
2165 false.hash(hasher);
2166 }
2167 vs.rows.len().hash(hasher);
2168 }
2169 Expression::CteReference(cte) => {
2170 cte.name.value_lower.hash(hasher);
2171 }
2172 Expression::FunctionTableSource(fts) => {
2173 fts.function.value_lower.hash(hasher);
2174 for arg in &fts.arguments {
2175 Self::hash_expression(arg, hasher);
2176 }
2177 }
2178 Expression::Star(_) => {
2179 }
2181 Expression::QualifiedStar(qs) => {
2182 qs.qualifier.hash(hasher);
2183 }
2184 Expression::Default(_) => {
2185 }
2187 }
2188 }
2189
2190 fn get_or_compile(&mut self, expr: &Expression) -> Result<SharedProgram> {
2193 if let Some(error) = self.context_error() {
2194 return Err(Error::invalid_argument(error));
2195 }
2196 let registry_generation = self.function_registry.generation();
2197 let mut expr_key = self.expr_hash(expr);
2198 expr_key ^= registry_generation.rotate_left(17);
2199
2200 if let Some(entry) = self.local_cache.get(&expr_key) {
2202 if entry.registry_generation == registry_generation && entry.expression == *expr {
2203 return Ok(CompactArc::clone(&entry.program));
2204 }
2205 }
2206
2207 let program = CompactArc::new(self.compile_expression(expr)?);
2209 self.local_cache.insert(
2210 expr_key,
2211 LocalProgramCacheEntry {
2212 expression: expr.clone(),
2213 registry_generation,
2214 program: CompactArc::clone(&program),
2215 },
2216 );
2217
2218 Ok(program)
2219 }
2220
2221 fn compile_expression(&self, expr: &Expression) -> Result<Program> {
2223 if let Some(error) = self.context_error() {
2224 return Err(Error::invalid_argument(error));
2225 }
2226 let mut ctx = CompileContext::new(&self.columns, self.function_registry);
2227
2228 if let Some(ref cols2) = self.columns2 {
2230 ctx = ctx.with_second_row(cols2);
2231 }
2232
2233 if let Some(ref outer_cols) = self.outer_columns {
2235 ctx = ctx.with_outer_columns(outer_cols);
2236 }
2237
2238 if !self.expression_aliases.is_empty() {
2240 ctx = ctx.with_expression_aliases(self.expression_aliases.clone());
2241 }
2242
2243 if !self.column_aliases.is_empty() {
2245 ctx = ctx.with_column_aliases(self.column_aliases.clone());
2246 }
2247
2248 let compiler = ExprCompiler::new(&ctx);
2249 compiler
2250 .compile(expr)
2251 .map_err(|e| Error::internal(format!("Compile error: {}", e)))
2252 }
2253
2254 pub fn evaluate(&mut self, expr: &Expression) -> Result<Value> {
2256 let program = self.get_or_compile(expr)?;
2258
2259 static EMPTY_ROW: std::sync::LazyLock<Row> = std::sync::LazyLock::new(Row::new);
2261
2262 let row = self.current_row.as_ref().unwrap_or(&EMPTY_ROW);
2264
2265 let row2 = self.current_row2.as_ref();
2267
2268 let mut ctx = if let Some(r2) = row2 {
2270 ExecuteContext::for_join(row, r2)
2271 } else {
2272 ExecuteContext::new(row)
2273 };
2274
2275 if !self.params.is_empty() {
2277 ctx = ctx.with_params(&self.params);
2278 }
2279
2280 if !self.named_params.is_empty() {
2282 ctx = ctx.with_named_params(&self.named_params);
2283 }
2284
2285 if let Some(ref outer) = self.outer_row {
2287 ctx = ctx.with_outer_row(outer);
2288 }
2289
2290 ctx = ctx
2292 .with_transaction_id(self.transaction_id)
2293 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
2294
2295 self.vm.execute_cow(&program, &ctx)
2297 }
2298
2299 pub fn evaluate_bool(&mut self, expr: &Expression) -> Result<bool> {
2303 let program = self.get_or_compile(expr)?;
2305
2306 static EMPTY_ROW: std::sync::LazyLock<Row> = std::sync::LazyLock::new(Row::new);
2308
2309 let row = self.current_row.as_ref().unwrap_or(&EMPTY_ROW);
2311
2312 let row2 = self.current_row2.as_ref();
2314
2315 let mut ctx = if let Some(r2) = row2 {
2317 ExecuteContext::for_join(row, r2)
2318 } else {
2319 ExecuteContext::new(row)
2320 };
2321
2322 if !self.params.is_empty() {
2324 ctx = ctx.with_params(&self.params);
2325 }
2326
2327 if !self.named_params.is_empty() {
2329 ctx = ctx.with_named_params(&self.named_params);
2330 }
2331
2332 if let Some(ref outer) = self.outer_row {
2334 ctx = ctx.with_outer_row(outer);
2335 }
2336
2337 ctx = ctx
2339 .with_transaction_id(self.transaction_id)
2340 .with_stored_function_invoker(self.stored_function_invoker.as_ref());
2341
2342 self.vm.execute_bool_checked(&program, &ctx)
2346 }
2347}
2348
2349impl Default for CompiledEvaluator<'static> {
2350 fn default() -> Self {
2351 Self::with_defaults()
2352 }
2353}
2354
2355#[cfg(test)]
2356mod tests {
2357 use super::*;
2358 use radixdb_sql::ast::{
2359 Expression, FunctionCall, Identifier, InfixExpression, InfixOperator, IntegerLiteral,
2360 };
2361 use radixdb_sql::token::{Position, Token, TokenType};
2362
2363 #[derive(Default)]
2364 struct MutableScalarOne;
2365
2366 #[derive(Default)]
2367 struct MutableScalarTwo;
2368
2369 macro_rules! mutable_scalar {
2370 ($type:ty, $value:expr) => {
2371 impl radixdb_functions::ScalarFunction for $type {
2372 fn name(&self) -> &str {
2373 "MUTABLE_TEST"
2374 }
2375
2376 fn info(&self) -> radixdb_functions::FunctionInfo {
2377 radixdb_functions::FunctionInfo::new(
2378 "MUTABLE_TEST",
2379 radixdb_functions::FunctionType::Scalar,
2380 "cache generation test",
2381 radixdb_functions::FunctionSignature::new(
2382 radixdb_functions::FunctionDataType::Integer,
2383 vec![],
2384 0,
2385 0,
2386 ),
2387 )
2388 }
2389
2390 fn evaluate(&self, _args: &[Value]) -> Result<Value> {
2391 Ok(Value::Integer($value))
2392 }
2393 }
2394 };
2395 }
2396
2397 mutable_scalar!(MutableScalarOne, 1);
2398 mutable_scalar!(MutableScalarTwo, 2);
2399
2400 fn dummy_token() -> Token {
2401 Token::new(TokenType::Eof, "", Position::default())
2402 }
2403
2404 fn make_identifier(name: &str) -> Expression {
2405 Expression::Identifier(Identifier {
2406 token: dummy_token(),
2407 value: name.into(),
2408 value_lower: name.to_lowercase().into(),
2409 })
2410 }
2411
2412 fn make_int_literal(value: i64) -> Expression {
2413 Expression::IntegerLiteral(IntegerLiteral {
2414 token: dummy_token(),
2415 value,
2416 })
2417 }
2418
2419 fn make_infix(left: Expression, op: InfixOperator, right: Expression) -> Expression {
2420 let op_str = match op {
2421 InfixOperator::GreaterThan => ">",
2422 InfixOperator::LessThan => "<",
2423 InfixOperator::Equal => "=",
2424 InfixOperator::Add => "+",
2425 InfixOperator::Multiply => "*",
2426 _ => "?",
2427 };
2428 Expression::Infix(InfixExpression {
2429 token: dummy_token(),
2430 left: Box::new(left),
2431 operator: op_str.into(),
2432 op_type: op,
2433 right: Box::new(right),
2434 })
2435 }
2436
2437 fn make_function(name: &str) -> Expression {
2438 Expression::FunctionCall(Box::new(FunctionCall {
2439 token: dummy_token(),
2440 function: name.into(),
2441 arguments: Vec::new(),
2442 is_distinct: false,
2443 order_by: Vec::new(),
2444 filter: None,
2445 }))
2446 }
2447
2448 #[test]
2453 fn test_compute_expression_hash_same_expr() {
2454 let expr1 = make_int_literal(42);
2455 let expr2 = make_int_literal(42);
2456 assert_eq!(
2457 compute_expression_hash(&expr1),
2458 compute_expression_hash(&expr2)
2459 );
2460 }
2461
2462 #[test]
2463 fn test_compute_expression_hash_different_expr() {
2464 let expr1 = make_int_literal(42);
2465 let expr2 = make_int_literal(43);
2466 assert_ne!(
2467 compute_expression_hash(&expr1),
2468 compute_expression_hash(&expr2)
2469 );
2470 }
2471
2472 #[test]
2473 fn test_compute_expression_hash_complex() {
2474 let expr1 = make_infix(
2476 make_identifier("col"),
2477 InfixOperator::GreaterThan,
2478 make_int_literal(5),
2479 );
2480 let expr2 = make_infix(
2482 make_identifier("col"),
2483 InfixOperator::GreaterThan,
2484 make_int_literal(5),
2485 );
2486 assert_eq!(
2487 compute_expression_hash(&expr1),
2488 compute_expression_hash(&expr2)
2489 );
2490 }
2491
2492 #[test]
2497 fn test_compile_expression_basic() {
2498 let expr = make_infix(
2500 make_identifier("col"),
2501 InfixOperator::GreaterThan,
2502 make_int_literal(5),
2503 );
2504 let columns = vec!["col".to_string()];
2505 let program = compile_expression(&expr, &columns);
2506 assert!(program.is_ok());
2507 }
2508
2509 #[test]
2510 fn test_compile_expression_unknown_column() {
2511 let expr = make_infix(
2513 make_identifier("unknown_col"),
2514 InfixOperator::GreaterThan,
2515 make_int_literal(5),
2516 );
2517 let columns = vec!["col".to_string()];
2518 let program = compile_expression(&expr, &columns);
2520 assert!(program.is_err());
2521 }
2522
2523 #[test]
2528 fn test_row_filter_new() {
2529 let expr = make_infix(
2531 make_identifier("col"),
2532 InfixOperator::GreaterThan,
2533 make_int_literal(5),
2534 );
2535 let columns = vec!["col".to_string()];
2536 let filter = RowFilter::new(&expr, &columns);
2537 assert!(filter.is_ok());
2538 }
2539
2540 #[test]
2541 fn test_row_filter_matches_true() {
2542 let expr = make_infix(
2544 make_identifier("col"),
2545 InfixOperator::GreaterThan,
2546 make_int_literal(5),
2547 );
2548 let columns = vec!["col".to_string()];
2549 let filter = RowFilter::new(&expr, &columns).unwrap();
2550
2551 let row = Row::from(vec![Value::Integer(10)]);
2553 assert!(filter.matches(&row).unwrap());
2554 }
2555
2556 #[test]
2557 fn test_row_filter_matches_false() {
2558 let expr = make_infix(
2560 make_identifier("col"),
2561 InfixOperator::GreaterThan,
2562 make_int_literal(5),
2563 );
2564 let columns = vec!["col".to_string()];
2565 let filter = RowFilter::new(&expr, &columns).unwrap();
2566
2567 let row = Row::from(vec![Value::Integer(3)]);
2569 assert!(!filter.matches(&row).unwrap());
2570 }
2571
2572 #[test]
2573 fn test_row_filter_evaluate() {
2574 let expr = make_infix(
2576 make_identifier("col"),
2577 InfixOperator::Add,
2578 make_int_literal(10),
2579 );
2580 let columns = vec!["col".to_string()];
2581 let filter = RowFilter::new(&expr, &columns).unwrap();
2582
2583 let row = Row::from(vec![Value::Integer(5)]);
2584 let result = filter.evaluate(&row).unwrap();
2585 assert_eq!(result, Value::Integer(15));
2586 }
2587
2588 #[test]
2589 fn test_row_filter_clone() {
2590 let expr = make_infix(
2591 make_identifier("col"),
2592 InfixOperator::GreaterThan,
2593 make_int_literal(5),
2594 );
2595 let columns = vec!["col".to_string()];
2596 let filter = RowFilter::new(&expr, &columns).unwrap();
2597 let cloned = filter.clone();
2598
2599 let row = Row::from(vec![Value::Integer(10)]);
2600 assert!(filter.matches(&row).unwrap());
2601 assert!(cloned.matches(&row).unwrap());
2602 }
2603
2604 #[test]
2609 fn test_expression_eval_compile() {
2610 let expr = make_infix(
2611 make_identifier("col"),
2612 InfixOperator::GreaterThan,
2613 make_int_literal(5),
2614 );
2615 let columns = vec!["col".to_string()];
2616 let eval = ExpressionEval::compile(&expr, &columns);
2617 assert!(eval.is_ok());
2618 }
2619
2620 #[test]
2621 fn test_expression_eval_eval() {
2622 let expr = make_infix(
2624 make_identifier("col"),
2625 InfixOperator::Add,
2626 make_int_literal(10),
2627 );
2628 let columns = vec!["col".to_string()];
2629 let mut eval = ExpressionEval::compile(&expr, &columns).unwrap();
2630
2631 let row = Row::from(vec![Value::Integer(5)]);
2632 let result = eval.eval(&row).unwrap();
2633 assert_eq!(result, Value::Integer(15));
2634 }
2635
2636 #[test]
2637 fn test_expression_eval_eval_bool() {
2638 let expr = make_infix(
2640 make_identifier("col"),
2641 InfixOperator::GreaterThan,
2642 make_int_literal(5),
2643 );
2644 let columns = vec!["col".to_string()];
2645 let mut eval = ExpressionEval::compile(&expr, &columns).unwrap();
2646
2647 let row = Row::from(vec![Value::Integer(10)]);
2648 assert!(eval.eval_bool(&row).unwrap());
2649
2650 let row = Row::from(vec![Value::Integer(3)]);
2651 assert!(!eval.eval_bool(&row).unwrap());
2652 }
2653
2654 #[test]
2659 fn test_multi_expression_eval_compile() {
2660 let expr1 = make_infix(
2661 make_identifier("col"),
2662 InfixOperator::Add,
2663 make_int_literal(10),
2664 );
2665 let expr2 = make_infix(
2666 make_identifier("col"),
2667 InfixOperator::Multiply,
2668 make_int_literal(2),
2669 );
2670 let columns = vec!["col".to_string()];
2671
2672 let eval = MultiExpressionEval::compile(&[expr1, expr2], &columns);
2673 assert!(eval.is_ok());
2674 assert_eq!(eval.unwrap().len(), 2);
2675 }
2676
2677 #[test]
2678 fn test_multi_expression_eval_all() {
2679 let expr1 = make_infix(
2680 make_identifier("col"),
2681 InfixOperator::Add,
2682 make_int_literal(10),
2683 );
2684 let expr2 = make_infix(
2685 make_identifier("col"),
2686 InfixOperator::Multiply,
2687 make_int_literal(2),
2688 );
2689 let columns = vec!["col".to_string()];
2690 let mut eval = MultiExpressionEval::compile(&[expr1, expr2], &columns).unwrap();
2691
2692 let row = Row::from(vec![Value::Integer(5)]);
2693 let results = eval.eval_all(&row).unwrap();
2694 assert_eq!(results.len(), 2);
2695 assert_eq!(results[0], Value::Integer(15)); assert_eq!(results[1], Value::Integer(10)); }
2698
2699 #[test]
2704 fn test_compiled_evaluator_with_defaults() {
2705 let eval = CompiledEvaluator::with_defaults();
2706 assert!(eval.columns.is_empty());
2707 }
2708
2709 #[test]
2710 fn test_compiled_evaluator_init_columns() {
2711 let mut eval = CompiledEvaluator::with_defaults();
2712 eval.init_columns(&["col1".to_string(), "col2".to_string()]);
2713 assert_eq!(eval.columns.len(), 2);
2714 }
2715
2716 #[test]
2717 fn compiled_evaluator_with_row_binds_owned_row_for_value_and_bool_evaluation() {
2718 let columns = vec!["col".to_string()];
2719 let mut eval = CompiledEvaluator::with_defaults()
2720 .with_row(Row::from(vec![Value::Integer(10)]), &columns);
2721
2722 assert_eq!(
2723 eval.evaluate(&make_identifier("col")).unwrap(),
2724 Value::Integer(10)
2725 );
2726 assert!(eval
2727 .evaluate_bool(&make_infix(
2728 make_identifier("col"),
2729 InfixOperator::GreaterThan,
2730 make_int_literal(5),
2731 ))
2732 .unwrap());
2733 }
2734
2735 #[test]
2736 fn test_compiled_evaluator_evaluate_bool() {
2737 let mut eval = CompiledEvaluator::with_defaults();
2738 eval.init_columns(&["col".to_string()]);
2739 let row = Row::from(vec![Value::Integer(10)]);
2740 eval.set_row_array(&row);
2741
2742 let expr = make_infix(
2744 make_identifier("col"),
2745 InfixOperator::GreaterThan,
2746 make_int_literal(5),
2747 );
2748
2749 let result = eval.evaluate_bool(&expr);
2750 assert!(result.is_ok());
2751 assert!(result.unwrap());
2752 }
2753
2754 #[test]
2755 fn test_compiled_evaluator_evaluate() {
2756 let mut eval = CompiledEvaluator::with_defaults();
2757 eval.init_columns(&["col".to_string()]);
2758 let row = Row::from(vec![Value::Integer(5)]);
2759 eval.set_row_array(&row);
2760
2761 let expr = make_infix(
2763 make_identifier("col"),
2764 InfixOperator::Add,
2765 make_int_literal(10),
2766 );
2767
2768 let result = eval.evaluate(&expr);
2769 assert!(result.is_ok());
2770 assert_eq!(result.unwrap(), Value::Integer(15));
2771 }
2772
2773 #[test]
2774 fn test_compiled_evaluator_default() {
2775 let eval = CompiledEvaluator::default();
2776 assert!(eval.columns.is_empty());
2777 }
2778
2779 #[test]
2780 fn compiled_evaluator_rebinds_semantically_changed_schemas() {
2781 let mut eval = CompiledEvaluator::with_defaults();
2782 let expr = make_identifier("a");
2783
2784 eval.init_columns(&["a".to_string(), "b".to_string()]);
2785 eval.set_row_array(&Row::from(vec![Value::Integer(1), Value::Integer(2)]));
2786 assert_eq!(eval.evaluate(&expr).unwrap(), Value::Integer(1));
2787
2788 eval.init_columns(&["b".to_string(), "a".to_string()]);
2789 eval.set_row_array(&Row::from(vec![Value::Integer(1), Value::Integer(2)]));
2790 assert_eq!(eval.evaluate(&expr).unwrap(), Value::Integer(2));
2791 }
2792
2793 #[test]
2794 fn compiled_evaluator_rejects_wide_schema_without_losing_other_errors() {
2795 let mut eval = CompiledEvaluator::with_defaults();
2796 let columns = (0..=u16::MAX as usize + 1)
2797 .map(|index| format!("c{index}"))
2798 .collect::<Vec<_>>();
2799 eval.init_columns(&columns);
2800 assert!(eval.evaluate(&make_int_literal(1)).is_err());
2801
2802 eval.init_columns(&["c".to_string()]);
2803 eval.set_row_array(&Row::from(vec![Value::Integer(1)]));
2804 assert_eq!(
2805 eval.evaluate(&make_int_literal(1)).unwrap(),
2806 Value::Integer(1)
2807 );
2808 }
2809
2810 #[test]
2811 fn join_filter_reads_deferred_projection_without_materializing_it() {
2812 let expression = make_infix(
2813 make_identifier("left_id"),
2814 InfixOperator::Equal,
2815 make_identifier("right_id"),
2816 );
2817 let filter = JoinFilter::new(
2818 &expression,
2819 &["left_id".to_string()],
2820 &["right_id".to_string()],
2821 global_registry(),
2822 )
2823 .unwrap();
2824 let left = crate::operator::RowRef::projected(
2825 crate::operator::RowRef::owned(Row::from_values(vec![
2826 Value::Integer(99),
2827 Value::Integer(7),
2828 ])),
2829 crate::operator::RowRef::owned(Row::new()),
2830 CompactArc::from(vec![crate::operator::ColumnSource::Outer(1)]),
2831 );
2832
2833 assert!(left.is_deferred());
2834 assert!(filter
2835 .matches_row_ref_checked(&left, &Row::from_values(vec![Value::Integer(7)]))
2836 .unwrap());
2837 assert!(left.is_deferred());
2838 }
2839
2840 #[test]
2841 fn row_filter_reads_portable_deferred_projection_without_materializing_it() {
2842 let expression = make_infix(
2843 make_identifier("status"),
2844 InfixOperator::Equal,
2845 make_int_literal(7),
2846 );
2847 let filter = RowFilter::new(&expression, &["status".to_string()]).unwrap();
2848 let row = radixdb_storage::DeferredRow::projected(
2849 radixdb_storage::DeferredRow::owned(Row::from_values(vec![
2850 Value::Integer(99),
2851 Value::Integer(7),
2852 ])),
2853 radixdb_storage::DeferredRow::owned(Row::new()),
2854 CompactArc::from(vec![radixdb_storage::DeferredColumnSource::Left(1)]),
2855 );
2856
2857 assert!(row.is_deferred());
2858 assert!(filter.matches_deferred_checked(&row).unwrap());
2859 assert!(row.is_deferred());
2860 }
2861
2862 #[test]
2863 fn row_filter_reads_executor_projection_without_materializing_it() {
2864 let expression = make_infix(
2865 make_identifier("status"),
2866 InfixOperator::Equal,
2867 make_int_literal(7),
2868 );
2869 let filter = RowFilter::new(&expression, &["status".to_string()]).unwrap();
2870 let row = crate::operator::RowRef::projected(
2871 crate::operator::RowRef::owned(Row::from_values(vec![
2872 Value::Integer(99),
2873 Value::Integer(7),
2874 ])),
2875 crate::operator::RowRef::owned(Row::new()),
2876 CompactArc::from(vec![crate::operator::ColumnSource::Outer(1)]),
2877 );
2878
2879 assert!(row.is_deferred());
2880 assert!(filter.matches_row_ref_checked(&row).unwrap());
2881 assert!(row.is_deferred());
2882 }
2883
2884 #[test]
2885 fn registry_generation_invalidates_embedded_function_programs() {
2886 let registry = FunctionRegistry::new();
2887 registry.register_scalar::<MutableScalarOne>();
2888 let mut eval = CompiledEvaluator::new(®istry);
2889 eval.set_row_array(&Row::new());
2890 let expr = make_function("MUTABLE_TEST");
2891 assert_eq!(eval.evaluate(&expr).unwrap(), Value::Integer(1));
2892
2893 registry.register_scalar::<MutableScalarTwo>();
2894 assert_eq!(eval.evaluate(&expr).unwrap(), Value::Integer(2));
2895 }
2896}