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