1use 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(¶ms, 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, ¶ms, symbols)
401 }
402 Transaction::Test(txn) => {
403 self.execute_test_incremental(txn, state, ¶ms, 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, ¶ms, 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(¶ms, &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}