Skip to main content

reifydb_engine/vm/
vm.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::sync::{Arc, LazyLock};
5
6use reifydb_core::{internal_error, value::column::columns::Columns};
7use reifydb_routine::routine::registry::Routines;
8use reifydb_rql::instruction::{Instruction, ScopeType};
9use reifydb_runtime::context::RuntimeContext;
10use reifydb_transaction::transaction::Transaction;
11use reifydb_value::{
12	params::Params,
13	util::bitvec::BitVec,
14	value::{Value, frame::frame::Frame, identity::IdentityId},
15};
16
17use super::{
18	exec::{
19		mask::{LoopMaskState, MaskFrame, extract_bool_bitvec},
20		stack::strip_dollar_prefix,
21	},
22	instruction::{
23		ddl::{
24			alter::{
25				identity::alter_identity, remote_namespace::alter_remote_namespace,
26				sequence::alter_table_sequence, table::execute_alter_table,
27			},
28			create::{
29				binding::create_binding, deferred::create_deferred_view, dictionary::create_dictionary,
30				migration::create_migration, namespace::create_namespace,
31				primary_key::create_primary_key, procedure::create_procedure,
32				property::create_column_property, remote_namespace::create_remote_namespace,
33				ringbuffer::create_ringbuffer, series::create_series, sink::create_sink,
34				source::create_source, subscription::create_subscription, sumtype::create_sumtype,
35				table::create_table, tag::create_tag, test::create_test,
36				transactional::create_transactional_view,
37			},
38			drop::{
39				binding::drop_binding, dictionary::drop_dictionary, namespace::drop_namespace,
40				procedure::drop_procedure, ringbuffer::drop_ringbuffer, series::drop_series,
41				sink::drop_sink, source::drop_source, subscription::drop_subscription,
42				sumtype::drop_sumtype, table::drop_table, view::drop_view,
43			},
44		},
45		dml::{
46			dictionary_insert::insert_dictionary, ringbuffer_delete::delete_ringbuffer,
47			ringbuffer_insert::insert_ringbuffer, ringbuffer_update::update_ringbuffer,
48			series_delete::delete_series, series_insert::insert_series, series_update::update_series,
49			table_delete::delete, table_insert::insert_table, table_update::update_table,
50		},
51	},
52	services::Services,
53	stack::{ControlFlow, Stack, SymbolTable, Variable},
54};
55use crate::{
56	Result,
57	expression::context::EvalContext,
58	vm::instruction::ddl::{
59		alter::policy::alter_policy,
60		create::{
61			authentication::create_authentication, event::create_event, identity::create_identity,
62			identity_attribute::create_identity_attribute, policy::create_policy, role::create_role,
63		},
64		drop::{
65			authentication::drop_authentication, handler::drop_handler, identity::drop_identity,
66			identity_attribute::drop_identity_attribute, policy::drop_policy, role::drop_role,
67			test::drop_test,
68		},
69		grant::grant,
70		revoke::revoke,
71	},
72};
73
74pub static EMPTY_PARAMS: LazyLock<Params> = LazyLock::new(|| Params::None);
75
76pub struct Vm<'a> {
77	pub(crate) ip: usize,
78	pub(crate) iteration_count: usize,
79	pub(crate) stack: Stack,
80	pub symbols: SymbolTable,
81	pub control_flow: ControlFlow,
82	pub(crate) dispatch_depth: u8,
83
84	pub(crate) batch_size: usize,
85
86	pub(crate) active_mask: Option<BitVec>,
87
88	pub(crate) mask_stack: Vec<MaskFrame>,
89
90	pub(crate) loop_mask_stack: Vec<LoopMaskState>,
91
92	pub(crate) params: &'a Params,
93	pub(crate) routines: &'a Routines,
94	pub(crate) runtime_context: &'a RuntimeContext,
95	pub(crate) identity: IdentityId,
96}
97
98impl<'a> Vm<'a> {
99	pub fn from_services(
100		symbols: SymbolTable,
101		services: &'a Services,
102		params: &'a Params,
103		identity: IdentityId,
104	) -> Self {
105		Self::build(symbols, 1, params, &services.routines, &services.runtime_context, identity)
106	}
107
108	pub fn with_batch_size_from_services(
109		symbols: SymbolTable,
110		batch_size: usize,
111		services: &'a Services,
112		params: &'a Params,
113		identity: IdentityId,
114	) -> Self {
115		Self::build(symbols, batch_size, params, &services.routines, &services.runtime_context, identity)
116	}
117
118	fn build(
119		symbols: SymbolTable,
120		batch_size: usize,
121		params: &'a Params,
122		routines: &'a Routines,
123		runtime_context: &'a RuntimeContext,
124		identity: IdentityId,
125	) -> Self {
126		Self {
127			ip: 0,
128			iteration_count: 0,
129			stack: Stack::new(),
130			symbols,
131			control_flow: ControlFlow::Normal,
132			dispatch_depth: 0,
133			batch_size,
134			active_mask: None,
135			mask_stack: Vec::new(),
136			loop_mask_stack: Vec::new(),
137			params,
138			routines,
139			runtime_context,
140			identity,
141		}
142	}
143
144	pub(crate) fn eval_ctx(&self) -> EvalContext<'_> {
145		EvalContext {
146			params: self.params,
147			symbols: &self.symbols,
148			routines: self.routines,
149			runtime_context: self.runtime_context,
150			arena: None,
151			identity: self.identity,
152			is_aggregate_context: false,
153			columns: Columns::empty(),
154			row_count: self.batch_size,
155			target: None,
156			take: None,
157		}
158	}
159
160	pub(crate) fn run_isolated_body(
161		&mut self,
162		services: &Arc<Services>,
163		tx: &mut Transaction<'_>,
164		instructions: &[Instruction],
165		result: &mut Vec<Frame>,
166	) -> Result<()> {
167		let saved = self.params;
168		self.params = &EMPTY_PARAMS;
169		let run_result = self.run(services, tx, instructions, result);
170		self.params = saved;
171		run_result
172	}
173
174	pub(crate) fn pop_value(&mut self) -> Result<Value> {
175		match self.stack.pop()? {
176			Variable::Columns {
177				columns: c,
178			} if c.is_scalar() => Ok(c.scalar_value()),
179			_ => Err(internal_error!("Expected scalar value on stack")),
180		}
181	}
182
183	pub(crate) fn pop_as_columns(&mut self) -> Result<Columns> {
184		match self.stack.pop()? {
185			Variable::Columns {
186				columns: c,
187				..
188			}
189			| Variable::ForIterator {
190				columns: c,
191				..
192			} => Ok(c),
193			Variable::Closure(_) => Ok(Columns::single_row([("value", Value::none())])),
194		}
195	}
196
197	pub(crate) fn run(
198		&mut self,
199		services: &Arc<Services>,
200		tx: &mut Transaction<'_>,
201		instructions: &[Instruction],
202		result: &mut Vec<Frame>,
203	) -> Result<()> {
204		let params = self.params;
205		while self.ip < instructions.len() {
206			let _ = self.batch_size > 1 && self.check_mask_merge_point()?;
207
208			match &instructions[self.ip] {
209				Instruction::Halt => return Ok(()),
210				Instruction::Nop => {}
211
212				Instruction::PushConst(v) => self.exec_push_const(v),
213				Instruction::PushNone => self.exec_push_none(),
214				Instruction::Pop => self.exec_pop()?,
215				Instruction::Dup => self.exec_dup()?,
216
217				Instruction::LoadVar(f) => self.exec_load_var(f)?,
218				Instruction::StoreVar(f) => {
219					if self.batch_size > 1 && self.is_masked() {
220						let name = strip_dollar_prefix(f.text());
221						let value = self.stack.pop()?;
222						self.exec_store_var_masked(name, value)?;
223					} else if self.batch_size > 1 {
224						let name = strip_dollar_prefix(f.text());
225						let value = self.stack.pop()?;
226						self.symbols.reassign(name.to_string(), value)?;
227					} else {
228						self.exec_store_var(f)?;
229					}
230				}
231				Instruction::DeclareVar(f) => self.exec_declare_var(f)?,
232				Instruction::FieldAccess {
233					object,
234					field,
235				} => self.exec_field_access(object, field)?,
236
237				Instruction::Add => self.exec_add()?,
238				Instruction::Sub => self.exec_sub()?,
239				Instruction::Mul => self.exec_mul()?,
240				Instruction::Div => self.exec_div()?,
241				Instruction::Rem => self.exec_rem()?,
242				Instruction::Negate => self.exec_negate()?,
243				Instruction::LogicNot => self.exec_logic_not()?,
244
245				Instruction::CmpEq => self.exec_cmp_eq()?,
246				Instruction::CmpNe => self.exec_cmp_ne()?,
247				Instruction::CmpLt => self.exec_cmp_lt()?,
248				Instruction::CmpLe => self.exec_cmp_le()?,
249				Instruction::CmpGt => self.exec_cmp_gt()?,
250				Instruction::CmpGe => self.exec_cmp_ge()?,
251
252				Instruction::LogicAnd => self.exec_logic_and()?,
253				Instruction::LogicOr => self.exec_logic_or()?,
254				Instruction::LogicXor => self.exec_logic_xor()?,
255				Instruction::Between => self.exec_between()?,
256				Instruction::InList {
257					count,
258					negated,
259				} => self.exec_in_list(*count, *negated)?,
260				Instruction::Cast(target) => self.exec_cast(target)?,
261
262				Instruction::Jump(addr) => {
263					if self.batch_size > 1
264						&& (!self.mask_stack.is_empty() || !self.loop_mask_stack.is_empty())
265					{
266						if self.exec_jump_masked(*addr)? {
267							continue;
268						}
269					} else {
270						self.exec_jump(*addr)?;
271						continue;
272					}
273				}
274				Instruction::JumpIfFalsePop(addr) => {
275					if self.batch_size > 1 {
276						let is_while_loop = instructions.get(self.ip + 1).is_some_and(|next| {
277							matches!(next, Instruction::EnterScope(ScopeType::Loop))
278						});
279
280						if is_while_loop
281							&& self.loop_mask_stack
282								.last()
283								.is_none_or(|s| s.loop_end_addr != *addr)
284						{
285							let var = self.stack.pop()?;
286							let bool_bv = extract_bool_bitvec(&var)?;
287							let parent = self.effective_mask();
288							let candidate = self.intersect_condition(&bool_bv);
289
290							if candidate == parent {
291							} else if candidate.none() {
292								self.ip = *addr;
293								continue;
294							} else {
295								self.enter_loop_mask(*addr, candidate);
296							}
297						} else if self.exec_jump_if_false_pop_columnar(*addr)? {
298							continue;
299						}
300					} else if self.exec_jump_if_false_pop(*addr)? {
301						continue;
302					}
303				}
304				Instruction::JumpIfTruePop(addr) => {
305					if self.batch_size > 1 {
306						if self.exec_jump_if_true_pop_columnar(*addr)? {
307							continue;
308						}
309					} else if self.exec_jump_if_true_pop(*addr)? {
310						continue;
311					}
312				}
313				Instruction::EnterScope(scope_type) => self.exec_enter_scope(scope_type),
314				Instruction::ExitScope => self.exec_exit_scope()?,
315				Instruction::Break {
316					exit_scopes,
317					addr,
318				} => {
319					if self.batch_size > 1 && !self.loop_mask_stack.is_empty() {
320						self.exec_break_masked(*exit_scopes, *addr)?;
321					} else {
322						self.exec_break(*exit_scopes, *addr)?;
323					}
324					continue;
325				}
326				Instruction::Continue {
327					exit_scopes,
328					addr,
329				} => {
330					if self.batch_size > 1 && !self.loop_mask_stack.is_empty() {
331						self.exec_continue_masked(*exit_scopes, *addr)?;
332					} else {
333						self.exec_continue(*exit_scopes, *addr)?;
334					}
335					continue;
336				}
337
338				Instruction::ForInit {
339					variable_name,
340				} => self.exec_for_init(variable_name)?,
341				Instruction::ForNext {
342					variable_name,
343					addr,
344				} => {
345					if self.exec_for_next(variable_name, *addr)? {
346						continue;
347					}
348				}
349
350				Instruction::DefineFunction(node) => self.exec_define_function(node),
351				Instruction::Call {
352					name,
353					arity,
354					is_procedure_call,
355				} => {
356					self.exec_call(services, tx, name, *arity, *is_procedure_call)?;
357				}
358				Instruction::ReturnValue => {
359					self.exec_return_value()?;
360					return Ok(());
361				}
362				Instruction::ReturnVoid => {
363					self.exec_return_void();
364					return Ok(());
365				}
366				Instruction::DefineClosure(def) => self.exec_define_closure(def),
367
368				Instruction::Emit => self.exec_emit(result),
369				Instruction::Append {
370					target,
371				} => self.exec_append(target)?,
372
373				Instruction::Query(plan) => self.exec_query(services, tx, plan, params)?,
374
375				Instruction::CreateNamespace(n) => {
376					self.exec_ddl(services, tx, |s, t| create_namespace(s, t, n.clone()))?
377				}
378				Instruction::CreateRemoteNamespace(n) => {
379					self.exec_ddl(services, tx, |s, t| create_remote_namespace(s, t, n.clone()))?
380				}
381				Instruction::CreateTable(n) => {
382					self.exec_ddl(services, tx, |s, t| create_table(s, t, n.clone()))?
383				}
384				Instruction::CreateRingBuffer(n) => {
385					self.exec_ddl(services, tx, |s, t| create_ringbuffer(s, t, n.clone()))?
386				}
387				Instruction::CreateDeferredView(n) => {
388					self.exec_ddl(services, tx, |s, t| create_deferred_view(s, t, n.clone()))?
389				}
390				Instruction::CreateTransactionalView(n) => {
391					self.exec_ddl(services, tx, |s, t| create_transactional_view(s, t, n.clone()))?
392				}
393				Instruction::CreateDictionary(n) => {
394					self.exec_ddl(services, tx, |s, t| create_dictionary(s, t, n.clone()))?
395				}
396				Instruction::CreateSumType(n) => {
397					self.exec_ddl(services, tx, |s, t| create_sumtype(s, t, n.clone()))?
398				}
399				Instruction::CreatePrimaryKey(n) => {
400					self.exec_ddl(services, tx, |s, t| create_primary_key(s, t, n.clone()))?
401				}
402				Instruction::CreateColumnProperty(n) => {
403					self.exec_ddl(services, tx, |s, t| create_column_property(s, t, n.clone()))?
404				}
405				Instruction::CreateProcedure(n) => {
406					self.exec_ddl(services, tx, |s, t| create_procedure(s, t, n.clone()))?
407				}
408				Instruction::CreateSeries(n) => {
409					self.exec_ddl(services, tx, |s, t| create_series(s, t, n.clone()))?
410				}
411				Instruction::CreateEvent(n) => {
412					self.exec_ddl(services, tx, |s, t| create_event(s, t, n.clone()))?
413				}
414				Instruction::CreateTag(n) => {
415					self.exec_ddl(services, tx, |s, t| create_tag(s, t, n.clone()))?
416				}
417				Instruction::CreateSource(n) => {
418					self.exec_ddl(services, tx, |s, t| create_source(s, t, n.clone()))?
419				}
420				Instruction::CreateSink(n) => {
421					self.exec_ddl(services, tx, |s, t| create_sink(s, t, n.clone()))?
422				}
423				Instruction::CreateBinding(n) => {
424					self.exec_ddl(services, tx, |s, t| create_binding(s, t, n.clone()))?
425				}
426				Instruction::CreateTest(n) => {
427					self.exec_ddl(services, tx, |s, t| create_test(s, t, n.clone()))?
428				}
429				Instruction::CreateMigration(n) => {
430					self.exec_ddl(services, tx, |s, t| create_migration(s, t, n.clone()))?
431				}
432				Instruction::CreateIdentity(n) => {
433					let params = self.params;
434					self.exec_ddl(services, tx, |s, t| create_identity(s, t, n.clone(), params))?
435				}
436				Instruction::CreateIdentityAttribute(n) => {
437					self.exec_ddl(services, tx, |s, t| create_identity_attribute(s, t, n.clone()))?
438				}
439				Instruction::CreateRole(n) => {
440					self.exec_ddl(services, tx, |s, t| create_role(s, t, n.clone()))?
441				}
442				Instruction::CreatePolicy(n) => {
443					self.exec_ddl(services, tx, |s, t| create_policy(s, t, n.clone()))?
444				}
445				Instruction::CreateAuthentication(n) => {
446					self.exec_ddl(services, tx, |s, t| create_authentication(s, t, n.clone()))?
447				}
448				Instruction::Grant(n) => self.exec_ddl(services, tx, |s, t| grant(s, t, n.clone()))?,
449				Instruction::Revoke(n) => {
450					self.exec_ddl(services, tx, |s, t| revoke(s, t, n.clone()))?
451				}
452
453				Instruction::CreateSubscription(n) => {
454					self.exec_ddl_sub(services, tx, |s, t| create_subscription(s, t, n.clone()))?
455				}
456
457				Instruction::AlterTable(n) => {
458					self.exec_ddl(services, tx, |s, t| execute_alter_table(s, t, n.clone()))?
459				}
460				Instruction::AlterRemoteNamespace(n) => {
461					self.exec_ddl(services, tx, |s, t| alter_remote_namespace(s, t, n.clone()))?
462				}
463				Instruction::AlterSequence(n) => {
464					self.exec_ddl(services, tx, |s, t| alter_table_sequence(s, t, n.clone()))?
465				}
466				Instruction::AlterIdentity(n) => {
467					let params = self.params;
468					self.exec_ddl(services, tx, |s, t| alter_identity(s, t, n.clone(), params))?
469				}
470				Instruction::AlterPolicy(n) => {
471					self.exec_ddl(services, tx, |s, t| alter_policy(s, t, n.clone()))?
472				}
473
474				Instruction::DropNamespace(n) => {
475					self.exec_ddl(services, tx, |s, t| drop_namespace(s, t, n.clone()))?
476				}
477				Instruction::DropTable(n) => {
478					self.exec_ddl(services, tx, |s, t| drop_table(s, t, n.clone()))?
479				}
480				Instruction::DropView(n) => {
481					self.exec_ddl(services, tx, |s, t| drop_view(s, t, n.clone()))?
482				}
483				Instruction::DropRingBuffer(n) => {
484					self.exec_ddl(services, tx, |s, t| drop_ringbuffer(s, t, n.clone()))?
485				}
486				Instruction::DropSeries(n) => {
487					self.exec_ddl(services, tx, |s, t| drop_series(s, t, n.clone()))?
488				}
489				Instruction::DropDictionary(n) => {
490					self.exec_ddl(services, tx, |s, t| drop_dictionary(s, t, n.clone()))?
491				}
492				Instruction::DropSumType(n) => {
493					self.exec_ddl(services, tx, |s, t| drop_sumtype(s, t, n.clone()))?
494				}
495				Instruction::DropSource(n) => {
496					self.exec_ddl(services, tx, |s, t| drop_source(s, t, n.clone()))?
497				}
498				Instruction::DropSink(n) => {
499					self.exec_ddl(services, tx, |s, t| drop_sink(s, t, n.clone()))?
500				}
501				Instruction::DropProcedure(n) => {
502					self.exec_ddl(services, tx, |s, t| drop_procedure(s, t, n.clone()))?
503				}
504				Instruction::DropHandler(n) => {
505					self.exec_ddl(services, tx, |s, t| drop_handler(s, t, n.clone()))?
506				}
507				Instruction::DropTest(n) => {
508					self.exec_ddl(services, tx, |s, t| drop_test(s, t, n.clone()))?
509				}
510				Instruction::DropBinding(n) => {
511					self.exec_ddl(services, tx, |s, t| drop_binding(s, t, n.clone()))?
512				}
513				Instruction::DropIdentity(n) => {
514					self.exec_ddl(services, tx, |s, t| drop_identity(s, t, n.clone()))?
515				}
516				Instruction::DropIdentityAttribute(n) => {
517					self.exec_ddl(services, tx, |s, t| drop_identity_attribute(s, t, n.clone()))?
518				}
519				Instruction::DropRole(n) => {
520					self.exec_ddl(services, tx, |s, t| drop_role(s, t, n.clone()))?
521				}
522				Instruction::DropPolicy(n) => {
523					self.exec_ddl(services, tx, |s, t| drop_policy(s, t, n.clone()))?
524				}
525				Instruction::DropAuthentication(n) => {
526					self.exec_ddl(services, tx, |s, t| drop_authentication(s, t, n.clone()))?
527				}
528
529				Instruction::DropSubscription(n) => {
530					self.exec_ddl_sub(services, tx, |s, t| drop_subscription(s, t, n.clone()))?
531				}
532
533				Instruction::Delete(n) => {
534					self.exec_dml_with_params(services, tx, params, |s, t, p, sym| {
535						delete(s, t, n.clone(), p, sym)
536					})?
537				}
538				Instruction::DeleteRingBuffer(n) => {
539					self.exec_dml_with_params(services, tx, params, |s, t, p, sym| {
540						delete_ringbuffer(s, t, n.clone(), p, sym)
541					})?
542				}
543				Instruction::DeleteSeries(n) => {
544					self.exec_dml_with_params(services, tx, params, |s, t, p, sym| {
545						delete_series(s, t, n.clone(), p, sym)
546					})?
547				}
548				Instruction::Update(n) => {
549					self.exec_dml_with_params(services, tx, params, |s, t, p, sym| {
550						update_table(s, t, n.clone(), p, sym)
551					})?
552				}
553				Instruction::UpdateRingBuffer(n) => {
554					self.exec_dml_with_params(services, tx, params, |s, t, p, sym| {
555						update_ringbuffer(s, t, n.clone(), p, sym)
556					})?
557				}
558				Instruction::UpdateSeries(n) => {
559					self.exec_dml_with_params(services, tx, params, |s, t, p, sym| {
560						update_series(s, t, n.clone(), p, sym)
561					})?
562				}
563				Instruction::InsertTable(n) => {
564					self.exec_dml_with_mut_symbols(services, tx, |s, t, sym| {
565						insert_table(s, t, n.clone(), sym)
566					})?
567				}
568				Instruction::InsertDictionary(n) => {
569					self.exec_dml_with_mut_symbols(services, tx, |s, t, sym| {
570						insert_dictionary(s, t, n.clone(), sym)
571					})?
572				}
573				Instruction::InsertRingBuffer(n) => {
574					self.exec_dml_with_params(services, tx, params, |s, t, p, sym| {
575						insert_ringbuffer(s, t, n.clone(), p, sym)
576					})?
577				}
578				Instruction::InsertSeries(n) => {
579					self.exec_dml_with_params(services, tx, params, |s, t, p, sym| {
580						insert_series(s, t, n.clone(), p, sym)
581					})?
582				}
583
584				Instruction::Dispatch(n) => self.exec_dispatch(services, tx, n, params)?,
585				Instruction::Migrate(n) => self.exec_migrate(services, tx, n)?,
586				Instruction::RollbackMigration(n) => self.exec_rollback_migration(services, tx, n)?,
587				Instruction::AssertBlock(n) => self.exec_assert_block(services, tx, n)?,
588			}
589
590			self.ip += 1;
591
592			if !self.control_flow.is_normal() {
593				return Ok(());
594			}
595		}
596		Ok(())
597	}
598}