Skip to main content

reifydb_engine/vm/volcano/
variable.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4use std::sync::Arc;
5
6use reifydb_core::value::column::{columns::Columns, headers::ColumnHeaders};
7use reifydb_rql::expression::VariableExpression;
8use reifydb_transaction::transaction::Transaction;
9
10use crate::{
11	Result,
12	error::EngineError,
13	vm::{
14		stack::Variable,
15		volcano::query::{QueryContext, QueryNode},
16	},
17};
18
19pub(crate) struct VariableNode {
20	variable_expr: VariableExpression,
21	context: Option<Arc<QueryContext>>,
22	executed: bool,
23}
24
25impl VariableNode {
26	pub fn new(variable_expr: VariableExpression) -> Self {
27		Self {
28			variable_expr,
29			context: None,
30			executed: false,
31		}
32	}
33}
34
35impl QueryNode for VariableNode {
36	fn initialize<'a>(&mut self, _rx: &mut Transaction<'a>, ctx: &QueryContext) -> Result<()> {
37		self.context = Some(Arc::new(ctx.clone()));
38		Ok(())
39	}
40
41	fn next<'a>(&mut self, _rx: &mut Transaction<'a>, ctx: &mut QueryContext) -> Result<Option<Columns>> {
42		debug_assert!(self.context.is_some(), "VariableNode::next() called before initialize()");
43
44		// Variables execute once and return their data
45		if self.executed {
46			return Ok(None);
47		}
48
49		let variable_name = self.variable_expr.name();
50
51		// Look up the variable in the stack
52		match ctx.symbols.get(variable_name) {
53			Some(Variable::Columns {
54				columns,
55			}) => {
56				self.executed = true;
57				Ok(Some(columns.clone()))
58			}
59			Some(Variable::ForIterator {
60				columns,
61				..
62			}) => {
63				// Return the iterator's columns
64				self.executed = true;
65
66				Ok(Some(columns.clone()))
67			}
68			Some(Variable::Closure(_)) => {
69				// Closures cannot be used as data sources in queries
70				Err(EngineError::VariableNotFound {
71					name: variable_name.to_string(),
72				}
73				.into())
74			}
75			None => {
76				// Variable not found - return error
77				Err(EngineError::VariableNotFound {
78					name: variable_name.to_string(),
79				}
80				.into())
81			}
82		}
83	}
84
85	fn headers(&self) -> Option<ColumnHeaders> {
86		// Variable headers depend on the variable type, can't determine ahead of time
87		None
88	}
89}