Skip to main content

reifydb_engine/vm/
executor.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4use std::{iter, ops::Deref, result::Result as StdResult, sync::Arc};
5
6use arrow_array::Array;
7use bumpalo::Bump;
8use reifydb_catalog::{
9	catalog::Catalog, metrics::storage::metrics::MetricsReader, vtable::system::operator_libary::OperatorLibrary,
10};
11use reifydb_core::{
12	error::diagnostic::subscription,
13	execution::ExecutionResult,
14	interface::catalog::{
15		flow::FlowId,
16		policy::SessionOp,
17		subscription::{SubscribeOptions, SubscribeOutcome},
18	},
19	metrics::execution::{ExecutionMetrics, StatementMetrics},
20	value::batch::single_row,
21};
22use reifydb_evaluate::stack::{SymbolTable, Variable};
23use reifydb_flow::compiler::compile_subscription_flow_ephemeral;
24use reifydb_policy::inject_from_policies;
25use reifydb_rql::{
26	ast::parse_str,
27	compiler::{CompilationResult, Compiled, IncrementalCompilation, constrain_policy},
28	fingerprint::request::fingerprint_request,
29	query::QueryPlan,
30};
31use reifydb_runtime::context::clock::Instant;
32use reifydb_store_single::SingleStore;
33use reifydb_transaction::transaction::{
34	RqlExecutor, TestTransaction, Transaction, admin::AdminTransaction, command::CommandTransaction,
35	query::QueryTransaction,
36};
37#[cfg(not(reifydb_single_threaded))]
38use reifydb_value::error::Diagnostic;
39use reifydb_value::{
40	error::Error,
41	params::Params,
42	value::{
43		Value, column_view::ColumnView, duration::Duration, frame::frame::Frame, identity::IdentityKind,
44		system_columns::SystemColumn, value_type::ValueType,
45	},
46};
47use tracing::instrument;
48
49#[cfg(not(reifydb_single_threaded))]
50use crate::remote;
51use crate::{
52	Result,
53	policy::PolicyEvaluator,
54	subscription::{SubscriptionContext, SubscriptionServiceRef},
55	vm::{
56		Admin, Command, Query, Test,
57		exec::ddl::ddl_requires_admin_txn,
58		services::{EngineConfig, Services},
59		vm::Vm,
60		volcano::partition_parameter::scan_partitions,
61	},
62};
63
64pub struct Executor(Arc<Services>);
65
66impl Clone for Executor {
67	fn clone(&self) -> Self {
68		Self(self.0.clone())
69	}
70}
71
72impl Deref for Executor {
73	type Target = Services;
74
75	fn deref(&self) -> &Self::Target {
76		&self.0
77	}
78}
79
80impl Executor {
81	pub fn new(
82		catalog: Catalog,
83		config: EngineConfig,
84		operator_library: OperatorLibrary,
85		metrics_reader: MetricsReader<SingleStore>,
86	) -> Self {
87		Self(Arc::new(Services::new(catalog, config, operator_library, metrics_reader)))
88	}
89
90	pub fn services(&self) -> &Arc<Services> {
91		&self.0
92	}
93
94	pub fn from_services(services: Arc<Services>) -> Self {
95		Self(services)
96	}
97
98	#[cfg(test)]
99	pub fn testing() -> Self {
100		Self(Services::testing())
101	}
102
103	#[cfg(not(reifydb_single_threaded))]
104	fn try_forward_remote_query(
105		&self,
106		tx: &mut Transaction<'_>,
107		err: &Error,
108		rql: &str,
109		params: Params,
110	) -> Result<Option<Vec<Frame>>> {
111		if let Some(ref registry) = self.0.remote_registry
112			&& remote::is_remote_query(err)
113			&& let Some(namespace) = self.compiler.remote_target(tx, rql)?
114			&& let Some(address) = namespace.address()
115		{
116			return registry.forward_query(address, rql, params, namespace.token()).map(Some);
117		}
118		Ok(None)
119	}
120}
121
122impl RqlExecutor for Executor {
123	fn rql(&self, tx: &mut Transaction<'_>, rql: &str, params: Params) -> ExecutionResult {
124		Executor::rql(self, tx, rql, params)
125	}
126}
127
128fn populate_symbols(symbols: &mut SymbolTable, params: &Params) -> Result<()> {
129	match params {
130		Params::Positional(values) => {
131			for (index, value) in values.iter().enumerate() {
132				let param_name = (index + 1).to_string();
133				symbols.set(param_name, Variable::scalar(value.clone()), false)?;
134			}
135		}
136		Params::Named(map) => {
137			for (name, value) in map.iter() {
138				symbols.set(name.clone(), Variable::scalar(value.clone()), false)?;
139			}
140		}
141		Params::None => {}
142	}
143	Ok(())
144}
145
146fn populate_identity(symbols: &mut SymbolTable, catalog: &Catalog, tx: &mut Transaction<'_>) -> Result<()> {
147	let identity = tx.identity();
148	if identity.is_privileged() {
149		return Ok(());
150	}
151	let attributes = catalog.list_identity_attributes(tx)?;
152	if identity.is_anonymous() {
153		let mut fields = vec![
154			("id".to_string(), Value::IdentityId(identity)),
155			("name".to_string(), Value::none_of(ValueType::Utf8)),
156			("roles".to_string(), Value::List(vec![])),
157			("kind".to_string(), Value::Utf8(IdentityKind::Anonymous.as_str().to_string())),
158		];
159		for attribute in &attributes {
160			fields.push((attribute.name.clone(), Value::none_of(attribute.value_type.clone())));
161		}
162		let batch = single_row(fields.iter().map(|(name, value)| (name.as_str(), value.clone())))?;
163		symbols.set("identity".to_string(), Variable::columns(batch), false)?;
164		return Ok(());
165	}
166	if let Some(user) = catalog.find_identity(tx, identity)? {
167		let roles = catalog.find_role_names_for_identity(tx, identity)?;
168		let role_values: Vec<Value> = roles.into_iter().map(Value::Utf8).collect();
169		let values = catalog.find_identity_attribute_values(tx, identity)?;
170		let kind = user.resolved_kind();
171		let mut fields = vec![
172			("id".to_string(), Value::IdentityId(identity)),
173			("name".to_string(), Value::Utf8(user.name)),
174			("roles".to_string(), Value::List(role_values)),
175			("kind".to_string(), Value::Utf8(kind.as_str().to_string())),
176		];
177		for attribute in &attributes {
178			let value = values
179				.iter()
180				.find(|v| v.attribute == attribute.id)
181				.map(|v| v.value.clone())
182				.unwrap_or_else(|| Value::none_of(attribute.value_type.clone()));
183			fields.push((attribute.name.clone(), value));
184		}
185		let batch = single_row(fields.iter().map(|(name, value)| (name.as_str(), value.clone())))?;
186		symbols.set("identity".to_string(), Variable::columns(batch), false)?;
187	}
188	Ok(())
189}
190
191type CompiledUnitsResult = (Emitted, Emitted, bool, SymbolTable, Vec<StatementMetrics>);
192
193#[derive(Default)]
194struct Emitted {
195	frames: Vec<Frame>,
196	named_system_columns: Vec<Vec<SystemColumn>>,
197}
198
199impl Emitted {
200	#[cfg(not(reifydb_single_threaded))]
201	fn forwarded(frames: Vec<Frame>) -> Self {
202		Self {
203			named_system_columns: vec![SystemColumn::ALL.to_vec(); frames.len()],
204			frames,
205		}
206	}
207
208	fn append(&mut self, frames: &mut Vec<Frame>, named: &[SystemColumn]) {
209		self.named_system_columns.extend(iter::repeat_n(named.to_vec(), frames.len()));
210		self.frames.append(frames);
211	}
212
213	fn into_result(self, metrics: ExecutionMetrics) -> ExecutionResult {
214		ExecutionResult {
215			frames: self.frames,
216			named_system_columns: self.named_system_columns,
217			error: None,
218			metrics,
219		}
220	}
221}
222
223struct ExecutionFailure {
224	error: Error,
225	partial_metrics: Vec<StatementMetrics>,
226}
227
228fn build_metrics(statements: Vec<StatementMetrics>) -> ExecutionMetrics {
229	let fps: Vec<_> = statements.iter().map(|m| m.fingerprint).collect();
230	ExecutionMetrics {
231		fingerprint: fingerprint_request(&fps),
232		statements,
233		..Default::default()
234	}
235}
236
237struct RunUnitOutcome {
238	symbols: SymbolTable,
239	run_result: Result<()>,
240	execute_duration: Duration,
241}
242
243#[instrument(
244	name = "vm::run",
245	level = "debug",
246	skip_all,
247	fields(fingerprint = ?compiled.fingerprint, instr_count = compiled.instructions.len()),
248)]
249fn run_compiled_unit(
250	services: &Arc<Services>,
251	tx: &mut Transaction<'_>,
252	compiled: &Compiled,
253	params: &Params,
254	symbols: SymbolTable,
255	result: &mut Vec<Frame>,
256) -> RunUnitOutcome {
257	let mut vm = Vm::from_services(symbols, services, params, tx.identity());
258	let start = services.runtime_context.clock.instant();
259	let run_result = vm.run(services, tx, &compiled.instructions, result);
260	let execute_duration = Duration::from_std(start.elapsed());
261	RunUnitOutcome {
262		symbols: vm.symbols,
263		run_result,
264		execute_duration,
265	}
266}
267
268#[instrument(
269	name = "executor::execute_units",
270	level = "debug",
271	skip_all,
272	fields(unit_count = compiled_list.len()),
273)]
274fn execute_compiled_units(
275	services: &Arc<Services>,
276	tx: &mut Transaction<'_>,
277	compiled_list: &[Compiled],
278	params: &Params,
279	mut symbols: SymbolTable,
280	compile_duration: Duration,
281) -> StdResult<CompiledUnitsResult, ExecutionFailure> {
282	let compile_duration_per_unit = Duration::from_micros_infallible(
283		compile_duration.to_std().as_micros() as u64 / compiled_list.len().max(1) as u64,
284	);
285	let mut result = vec![];
286	let mut output_results = Emitted::default();
287	let mut saw_output = false;
288	let mut metrics = Vec::new();
289
290	for compiled in compiled_list.iter() {
291		result.clear();
292		let outcome = run_compiled_unit(services, tx, compiled, params, symbols, &mut result);
293		symbols = outcome.symbols;
294
295		let rows_affected = match &outcome.run_result {
296			Ok(()) => match extract_rows_affected(&result) {
297				Ok(n) => n,
298				Err(error) => {
299					return Err(ExecutionFailure {
300						error,
301						partial_metrics: metrics,
302					});
303				}
304			},
305			Err(_) => 0,
306		};
307		metrics.push(StatementMetrics {
308			fingerprint: compiled.fingerprint,
309			normalized_rql: compiled.normalized_rql.clone(),
310			compile_duration: compile_duration_per_unit,
311			execute_duration: outcome.execute_duration,
312			rows_affected,
313		});
314
315		if let Err(error) = outcome.run_result {
316			return Err(ExecutionFailure {
317				error,
318				partial_metrics: metrics,
319			});
320		}
321
322		if compiled.is_output {
323			saw_output = true;
324			output_results.append(&mut result, &compiled.named_system_columns);
325		}
326	}
327
328	let mut last = Emitted::default();
329	if let Some(compiled) = compiled_list.last() {
330		last.append(&mut result, &compiled.named_system_columns);
331	}
332	Ok((output_results, last, saw_output, symbols, metrics))
333}
334
335fn select_frames(saw_output: bool, output: Emitted, last: Emitted) -> Emitted {
336	if saw_output {
337		output
338	} else {
339		last
340	}
341}
342
343#[inline]
344fn error_result(error: Error, metrics: ExecutionMetrics) -> ExecutionResult {
345	ExecutionResult {
346		frames: vec![],
347		named_system_columns: vec![],
348		error: Some(error),
349		metrics,
350	}
351}
352
353fn extract_rows_affected(result: &[Frame]) -> Result<u64> {
354	if result.len() == 1 {
355		let batch = &result[0].batch;
356		for (field, array) in batch.schema_ref().fields().iter().zip(batch.columns()) {
357			match field.name().as_str() {
358				"inserted" | "updated" | "deleted" => {
359					if array.len() == 1
360						&& let Value::Uint8(n) =
361							ColumnView::try_from((array, field.as_ref()))?.get_value(0)
362					{
363						return Ok(n);
364					}
365				}
366				_ => {}
367			}
368		}
369	}
370	Ok(result.len() as u64)
371}
372
373impl Executor {
374	#[instrument(name = "executor::setup_symbols", level = "debug", skip_all)]
375	fn setup_symbols(&self, params: &Params, tx: &mut Transaction<'_>) -> Result<SymbolTable> {
376		let mut symbols = SymbolTable::new();
377		populate_symbols(&mut symbols, params)?;
378		populate_identity(&mut symbols, &self.catalog, tx)?;
379		Ok(symbols)
380	}
381
382	#[instrument(name = "executor::compile", level = "debug", skip(self, tx), fields(rql = %rql))]
383	fn compile_query(&self, tx: &mut Transaction<'_>, rql: &str) -> Result<CompilationResult> {
384		self.compiler.compile_with_policy(tx, rql, inject_from_policies)
385	}
386
387	#[instrument(name = "executor::rql", level = "debug", skip(self, tx, params), fields(rql = %rql))]
388	pub fn rql(&self, tx: &mut Transaction<'_>, rql: &str, params: Params) -> ExecutionResult {
389		let symbols = match self.setup_symbols(&params, tx) {
390			Ok(s) => s,
391			Err(e) => return error_result(e, ExecutionMetrics::default()),
392		};
393
394		let start_compile = self.0.runtime_context.clock.instant();
395		let compiled_list = match self.compile_query(tx, rql) {
396			Ok(CompilationResult::Ready(compiled)) => compiled,
397			Ok(CompilationResult::Incremental(state)) => {
398				return match tx {
399					Transaction::Admin(txn) => {
400						self.execute_admin_incremental(txn, state, &params, symbols)
401					}
402					Transaction::Test(txn) => {
403						self.execute_test_incremental(txn, state, &params, symbols)
404					}
405					Transaction::Command(_) | Transaction::Query(_) => {
406						error_result(ddl_requires_admin_txn(), ExecutionMetrics::default())
407					}
408				};
409			}
410			Err(err) => return self.handle_rql_compile_error(tx, err, rql, params),
411		};
412		let compile_duration = Duration::from_std(start_compile.elapsed());
413
414		match execute_compiled_units(&self.0, tx, &compiled_list, &params, symbols, compile_duration) {
415			Ok((output, last, saw_output, _, metrics)) => {
416				select_frames(saw_output, output, last).into_result(build_metrics(metrics))
417			}
418			Err(f) => error_result(f.error, build_metrics(f.partial_metrics)),
419		}
420	}
421
422	#[inline]
423	#[cfg_attr(reifydb_single_threaded, allow(unused_variables))]
424	fn handle_rql_compile_error(
425		&self,
426		tx: &mut Transaction<'_>,
427		err: Error,
428		rql: &str,
429		params: Params,
430	) -> ExecutionResult {
431		#[cfg(not(reifydb_single_threaded))]
432		if let Ok(Some(frames)) = self.try_forward_remote_query(tx, &err, rql, params) {
433			return Emitted::forwarded(frames).into_result(ExecutionMetrics::default());
434		}
435		error_result(err, ExecutionMetrics::default())
436	}
437
438	#[instrument(name = "executor::admin", level = "debug", skip(self, txn, cmd), fields(rql = %cmd.rql))]
439	pub fn admin(&self, txn: &mut AdminTransaction, cmd: Admin<'_>) -> ExecutionResult {
440		let symbols = match self.setup_symbols(&cmd.params, &mut Transaction::Admin(&mut *txn)) {
441			Ok(s) => s,
442			Err(e) => return error_result(e, ExecutionMetrics::default()),
443		};
444		if let Err(e) = self.enforce_admin_policy(&symbols, txn) {
445			return error_result(e, ExecutionMetrics::default());
446		}
447		let start_compile = self.0.runtime_context.clock.instant();
448		match self.compile_query(&mut Transaction::Admin(txn), cmd.rql) {
449			Err(err) => self.handle_admin_compile_error(txn, err, cmd.rql, cmd.params),
450			Ok(CompilationResult::Ready(compiled)) => {
451				self.execute_admin_ready(txn, compiled, &cmd.params, symbols, start_compile)
452			}
453			Ok(CompilationResult::Incremental(state)) => {
454				self.execute_admin_incremental(txn, state, &cmd.params, symbols)
455			}
456		}
457	}
458
459	#[inline]
460	fn enforce_admin_policy(&self, symbols: &SymbolTable, txn: &mut AdminTransaction) -> Result<()> {
461		PolicyEvaluator::new(&self.0, symbols).enforce_session_policy(
462			&mut Transaction::Admin(txn),
463			SessionOp::Admin,
464			true,
465		)
466	}
467
468	#[inline]
469	#[cfg_attr(reifydb_single_threaded, allow(unused_variables))]
470	fn handle_admin_compile_error(
471		&self,
472		txn: &mut AdminTransaction,
473		err: Error,
474		rql: &str,
475		params: Params,
476	) -> ExecutionResult {
477		#[cfg(not(reifydb_single_threaded))]
478		if let Ok(Some(frames)) = self.try_forward_remote_query(&mut Transaction::Admin(txn), &err, rql, params)
479		{
480			return Emitted::forwarded(frames).into_result(ExecutionMetrics::default());
481		}
482		error_result(err, ExecutionMetrics::default())
483	}
484
485	#[inline]
486	fn execute_admin_ready(
487		&self,
488		txn: &mut AdminTransaction,
489		compiled: Arc<Vec<Compiled>>,
490		params: &Params,
491		symbols: SymbolTable,
492		start_compile: Instant,
493	) -> ExecutionResult {
494		let compile_duration = Duration::from_std(start_compile.elapsed());
495		match execute_compiled_units(
496			&self.0,
497			&mut Transaction::Admin(txn),
498			&compiled,
499			params,
500			symbols,
501			compile_duration,
502		) {
503			Ok((output, last, saw_output, _, metrics)) => {
504				select_frames(saw_output, output, last).into_result(build_metrics(metrics))
505			}
506			Err(f) => ExecutionResult {
507				frames: vec![],
508				named_system_columns: vec![],
509				error: Some(f.error),
510				metrics: build_metrics(f.partial_metrics),
511			},
512		}
513	}
514
515	fn execute_admin_incremental(
516		&self,
517		txn: &mut AdminTransaction,
518		mut state: IncrementalCompilation,
519		params: &Params,
520		symbols: SymbolTable,
521	) -> ExecutionResult {
522		let policy = constrain_policy(inject_from_policies);
523		let mut result = vec![];
524		let mut output_results = Emitted::default();
525		let mut last_named: Vec<SystemColumn> = Vec::new();
526		let mut saw_output = false;
527		let mut symbols = symbols;
528		let mut metrics = Vec::new();
529		loop {
530			let start_incr = self.0.runtime_context.clock.instant();
531			let next = match self.compiler.compile_next_with_policy(
532				&mut Transaction::Admin(txn),
533				&mut state,
534				&policy,
535			) {
536				Ok(n) => n,
537				Err(e) => return error_result(e, build_metrics(metrics)),
538			};
539			let compile_duration = Duration::from_std(start_incr.elapsed());
540
541			let Some(compiled) = next else {
542				break;
543			};
544
545			result.clear();
546			let mut tx = Transaction::Admin(txn);
547			let mut vm = Vm::from_services(symbols, &self.0, params, tx.identity());
548			let start_execute = self.0.runtime_context.clock.instant();
549			let run_result = vm.run(&self.0, &mut tx, &compiled.instructions, &mut result);
550			let execute_duration = Duration::from_std(start_execute.elapsed());
551			symbols = vm.symbols;
552
553			let rows_affected = match &run_result {
554				Ok(()) => match extract_rows_affected(&result) {
555					Ok(n) => n,
556					Err(e) => return error_result(e, build_metrics(metrics)),
557				},
558				Err(_) => 0,
559			};
560			metrics.push(StatementMetrics {
561				fingerprint: compiled.fingerprint,
562				normalized_rql: compiled.normalized_rql,
563				compile_duration,
564				execute_duration,
565				rows_affected,
566			});
567
568			if let Err(e) = run_result {
569				return error_result(e, build_metrics(metrics));
570			}
571
572			if compiled.is_output {
573				saw_output = true;
574				output_results.append(&mut result, &compiled.named_system_columns);
575			}
576			last_named = compiled.named_system_columns;
577		}
578		let mut last = Emitted::default();
579		last.append(&mut result, &last_named);
580		select_frames(saw_output, output_results, last).into_result(build_metrics(metrics))
581	}
582
583	#[instrument(name = "executor::test", level = "debug", skip(self, txn, cmd), fields(rql = %cmd.rql))]
584	pub fn test(&self, txn: &mut TestTransaction<'_>, cmd: Test<'_>) -> ExecutionResult {
585		let symbols = match self.setup_symbols(&cmd.params, &mut Transaction::Test(Box::new(txn.reborrow()))) {
586			Ok(s) => s,
587			Err(e) => return error_result(e, ExecutionMetrics::default()),
588		};
589		if let Err(e) = self.enforce_test_policy(&symbols, txn) {
590			return error_result(e, ExecutionMetrics::default());
591		}
592		let start_compile = self.0.runtime_context.clock.instant();
593		match self.compiler.compile_with_policy(
594			&mut Transaction::Test(Box::new(txn.reborrow())),
595			cmd.rql,
596			inject_from_policies,
597		) {
598			Err(err) => self.handle_test_compile_error(txn, err, cmd.rql, cmd.params),
599			Ok(CompilationResult::Ready(compiled)) => {
600				self.execute_test_ready(txn, compiled, &cmd.params, symbols, start_compile)
601			}
602			Ok(CompilationResult::Incremental(state)) => {
603				self.execute_test_incremental(txn, state, &cmd.params, symbols)
604			}
605		}
606	}
607
608	#[inline]
609	fn enforce_test_policy(&self, symbols: &SymbolTable, txn: &mut TestTransaction<'_>) -> Result<()> {
610		let session_type = txn.session_type;
611		let session_default_deny = txn.session_default_deny;
612		PolicyEvaluator::new(&self.0, symbols).enforce_session_policy(
613			&mut Transaction::Test(Box::new(txn.reborrow())),
614			session_type,
615			session_default_deny,
616		)
617	}
618
619	#[inline]
620	#[cfg_attr(reifydb_single_threaded, allow(unused_variables))]
621	fn handle_test_compile_error(
622		&self,
623		txn: &mut TestTransaction<'_>,
624		err: Error,
625		rql: &str,
626		params: Params,
627	) -> ExecutionResult {
628		#[cfg(not(reifydb_single_threaded))]
629		if let Ok(Some(frames)) = self.try_forward_remote_query(
630			&mut Transaction::Test(Box::new(txn.reborrow())),
631			&err,
632			rql,
633			params,
634		) {
635			return Emitted::forwarded(frames).into_result(ExecutionMetrics::default());
636		}
637		error_result(err, ExecutionMetrics::default())
638	}
639
640	#[inline]
641	fn execute_test_ready(
642		&self,
643		txn: &mut TestTransaction<'_>,
644		compiled: Arc<Vec<Compiled>>,
645		params: &Params,
646		symbols: SymbolTable,
647		start_compile: Instant,
648	) -> ExecutionResult {
649		let compile_duration = Duration::from_std(start_compile.elapsed());
650		match execute_compiled_units(
651			&self.0,
652			&mut Transaction::Test(Box::new(txn.reborrow())),
653			&compiled,
654			params,
655			symbols,
656			compile_duration,
657		) {
658			Ok((output, last, saw_output, _, metrics)) => {
659				select_frames(saw_output, output, last).into_result(build_metrics(metrics))
660			}
661			Err(f) => ExecutionResult {
662				frames: vec![],
663				named_system_columns: vec![],
664				error: Some(f.error),
665				metrics: build_metrics(f.partial_metrics),
666			},
667		}
668	}
669
670	fn execute_test_incremental(
671		&self,
672		txn: &mut TestTransaction<'_>,
673		mut state: IncrementalCompilation,
674		params: &Params,
675		symbols: SymbolTable,
676	) -> ExecutionResult {
677		let policy = constrain_policy(inject_from_policies);
678		let mut result = vec![];
679		let mut output_results = Emitted::default();
680		let mut last_named: Vec<SystemColumn> = Vec::new();
681		let mut saw_output = false;
682		let mut symbols = symbols;
683		let mut metrics = Vec::new();
684		loop {
685			let start_incr = self.0.runtime_context.clock.instant();
686			let next = match self.compiler.compile_next_with_policy(
687				&mut Transaction::Test(Box::new(txn.reborrow())),
688				&mut state,
689				&policy,
690			) {
691				Ok(n) => n,
692				Err(e) => return error_result(e, build_metrics(metrics)),
693			};
694			let compile_duration = Duration::from_std(start_incr.elapsed());
695
696			let Some(compiled) = next else {
697				break;
698			};
699
700			result.clear();
701			let mut tx = Transaction::Test(Box::new(txn.reborrow()));
702			let mut vm = Vm::from_services(symbols, &self.0, params, tx.identity());
703			let start_execute = self.0.runtime_context.clock.instant();
704			let run_result = vm.run(&self.0, &mut tx, &compiled.instructions, &mut result);
705			let execute_duration = Duration::from_std(start_execute.elapsed());
706			symbols = vm.symbols;
707
708			let rows_affected = match &run_result {
709				Ok(()) => match extract_rows_affected(&result) {
710					Ok(n) => n,
711					Err(e) => return error_result(e, build_metrics(metrics)),
712				},
713				Err(_) => 0,
714			};
715			metrics.push(StatementMetrics {
716				fingerprint: compiled.fingerprint,
717				normalized_rql: compiled.normalized_rql,
718				compile_duration,
719				execute_duration,
720				rows_affected,
721			});
722
723			if let Err(e) = run_result {
724				return error_result(e, build_metrics(metrics));
725			}
726
727			if compiled.is_output {
728				saw_output = true;
729				output_results.append(&mut result, &compiled.named_system_columns);
730			}
731			last_named = compiled.named_system_columns;
732		}
733		let mut last = Emitted::default();
734		last.append(&mut result, &last_named);
735		select_frames(saw_output, output_results, last).into_result(build_metrics(metrics))
736	}
737
738	#[instrument(name = "executor::subscribe", level = "debug", skip(self, txn, params, options), fields(query = %query))]
739	pub fn subscribe(
740		&self,
741		txn: &mut QueryTransaction,
742		query: &str,
743		params: Params,
744		options: SubscribeOptions,
745	) -> Result<SubscribeOutcome> {
746		if options.hydration.max_rows == Some(0) {
747			return Err(Error(Box::new(subscription::hydration_max_rows_zero())));
748		}
749		if let Some(throttle) = options.throttle.filter(Duration::is_negative) {
750			return Err(Error(Box::new(subscription::negative_throttle(throttle))));
751		}
752		if let Some(linger) = options.linger.filter(Duration::is_negative) {
753			return Err(Error(Box::new(subscription::negative_linger(linger))));
754		}
755		let bump = Bump::new();
756		let mut statements = parse_str(&bump, query)?;
757		if statements.len() != 1 {
758			return Err(Error(Box::new(subscription::single_statement_required(
759				"Subscription endpoint requires exactly one statement",
760			))));
761		}
762
763		let symbols = self.setup_symbols(&params, &mut Transaction::Query(&mut *txn))?;
764		PolicyEvaluator::new(&self.0, &symbols).enforce_session_policy(
765			&mut Transaction::Query(&mut *txn),
766			SessionOp::Subscription,
767			true,
768		)?;
769
770		let mut tx = Transaction::Query(txn);
771		let Some((plan, named_system_columns)) = self.compiler.compile_query_plan_with_policy(
772			&bump,
773			&mut tx,
774			statements.remove(0),
775			inject_from_policies,
776		)?
777		else {
778			return Err(Error(Box::new(subscription::single_statement_required(
779				"Subscription endpoint requires exactly one statement",
780			))));
781		};
782
783		let plan = match plan {
784			QueryPlan::RemoteScan(remote) => {
785				return Ok(SubscribeOutcome::Remote {
786					address: remote.address,
787					body: remote.remote_rql,
788					token: remote.token,
789				});
790			}
791			plan => plan,
792		};
793
794		let partitions = scan_partitions(&plan, tx.layout(), &symbols);
795		let sub_service = self.ioc.resolve::<SubscriptionServiceRef>()?;
796		let id = sub_service.next_id();
797		let flow_dag = compile_subscription_flow_ephemeral(
798			&self.catalog,
799			&self.routines,
800			&mut tx,
801			plan,
802			id,
803			FlowId(id.0),
804		)?;
805		let ctx = SubscriptionContext {
806			id,
807			identity: tx.identity(),
808			symbols,
809			params,
810			named_system_columns,
811			partitions,
812		};
813		sub_service.register_subscription(flow_dag, options.hydration.enabled, ctx, &mut tx)?;
814		Ok(SubscribeOutcome::Local {
815			id,
816		})
817	}
818
819	#[instrument(name = "executor::command", level = "debug", skip(self, txn, cmd), fields(rql = %cmd.rql))]
820	pub fn command(&self, txn: &mut CommandTransaction, cmd: Command<'_>) -> ExecutionResult {
821		let symbols = match self.setup_symbols(&cmd.params, &mut Transaction::Command(&mut *txn)) {
822			Ok(s) => s,
823			Err(e) => {
824				return ExecutionResult {
825					frames: vec![],
826					named_system_columns: vec![],
827					error: Some(e),
828					metrics: ExecutionMetrics::default(),
829				};
830			}
831		};
832
833		if let Err(e) = PolicyEvaluator::new(&self.0, &symbols).enforce_session_policy(
834			&mut Transaction::Command(&mut *txn),
835			SessionOp::Command,
836			false,
837		) {
838			return ExecutionResult {
839				frames: vec![],
840				named_system_columns: vec![],
841				error: Some(e),
842				metrics: ExecutionMetrics::default(),
843			};
844		}
845
846		let start_compile = self.0.runtime_context.clock.instant();
847		let compiled = match self.compile_query(&mut Transaction::Command(txn), cmd.rql) {
848			Ok(CompilationResult::Ready(compiled)) => compiled,
849			Ok(CompilationResult::Incremental(_)) => {
850				return error_result(ddl_requires_admin_txn(), ExecutionMetrics::default());
851			}
852			Err(err) => {
853				#[cfg(not(reifydb_single_threaded))]
854				if self.0.remote_registry.is_some() && remote::is_remote_query(&err) {
855					return ExecutionResult {
856						frames: vec![],
857						named_system_columns: vec![],
858						error: Some(Error(Box::new(Diagnostic {
859							code: "REMOTE_002".to_string(),
860							message: "Write operations on remote namespaces are not supported"
861								.to_string(),
862							help: Some("Use the remote instance directly for write operations"
863								.to_string()),
864							..Default::default()
865						}))),
866						metrics: ExecutionMetrics::default(),
867					};
868				}
869				return ExecutionResult {
870					frames: vec![],
871					named_system_columns: vec![],
872					error: Some(err),
873					metrics: ExecutionMetrics::default(),
874				};
875			}
876		};
877		let compile_duration = Duration::from_std(start_compile.elapsed());
878
879		match execute_compiled_units(
880			&self.0,
881			&mut Transaction::Command(txn),
882			&compiled,
883			&cmd.params,
884			symbols,
885			compile_duration,
886		) {
887			Ok((output, last, saw_output, _, metrics)) => {
888				select_frames(saw_output, output, last).into_result(build_metrics(metrics))
889			}
890			Err(f) => ExecutionResult {
891				frames: vec![],
892				named_system_columns: vec![],
893				error: Some(f.error),
894				metrics: build_metrics(f.partial_metrics),
895			},
896		}
897	}
898
899	#[instrument(name = "executor::query", level = "debug", skip(self, txn, qry), fields(rql = %qry.rql))]
900	pub fn query(&self, txn: &mut QueryTransaction, qry: Query<'_>) -> ExecutionResult {
901		let symbols = match self.setup_symbols(&qry.params, &mut Transaction::Query(&mut *txn)) {
902			Ok(s) => s,
903			Err(e) => {
904				return ExecutionResult {
905					frames: vec![],
906					named_system_columns: vec![],
907					error: Some(e),
908					metrics: ExecutionMetrics::default(),
909				};
910			}
911		};
912
913		if let Err(e) = PolicyEvaluator::new(&self.0, &symbols).enforce_session_policy(
914			&mut Transaction::Query(&mut *txn),
915			SessionOp::Query,
916			false,
917		) {
918			return ExecutionResult {
919				frames: vec![],
920				named_system_columns: vec![],
921				error: Some(e),
922				metrics: ExecutionMetrics::default(),
923			};
924		}
925
926		let start_compile = self.0.runtime_context.clock.instant();
927		let compiled = match self.compile_query(&mut Transaction::Query(txn), qry.rql) {
928			Ok(CompilationResult::Ready(compiled)) => compiled,
929			Ok(CompilationResult::Incremental(_)) => {
930				return error_result(ddl_requires_admin_txn(), ExecutionMetrics::default());
931			}
932			Err(err) => {
933				#[cfg(not(reifydb_single_threaded))]
934				if let Ok(Some(frames)) = self.try_forward_remote_query(
935					&mut Transaction::Query(txn),
936					&err,
937					qry.rql,
938					qry.params,
939				) {
940					return Emitted::forwarded(frames).into_result(ExecutionMetrics::default());
941				}
942				return ExecutionResult {
943					frames: vec![],
944					named_system_columns: vec![],
945					error: Some(err),
946					metrics: ExecutionMetrics::default(),
947				};
948			}
949		};
950		let compile_duration = Duration::from_std(start_compile.elapsed());
951
952		let exec_result = execute_compiled_units(
953			&self.0,
954			&mut Transaction::Query(txn),
955			&compiled,
956			&qry.params,
957			symbols,
958			compile_duration,
959		);
960
961		match exec_result {
962			Ok((output, last, saw_output, _, metrics)) => {
963				select_frames(saw_output, output, last).into_result(build_metrics(metrics))
964			}
965			Err(f) => ExecutionResult {
966				frames: vec![],
967				named_system_columns: vec![],
968				error: Some(f.error),
969				metrics: build_metrics(f.partial_metrics),
970			},
971		}
972	}
973}