1use std::{cell::RefCell, rc::Rc};
7
8use lru::LruCache;
9
10use crate::errors::ExecutorError;
11
12pub struct ExpressionEvaluator<'a> {
14 pub(super) schema: &'a vibesql_catalog::TableSchema,
15 pub(super) outer_row: Option<&'a vibesql_storage::Row>,
16 pub(super) outer_schema: Option<&'a vibesql_catalog::TableSchema>,
17 pub(super) database: Option<&'a vibesql_storage::Database>,
18 pub(super) trigger_context: Option<&'a crate::trigger_execution::TriggerContext<'a>>,
20 pub(super) procedural_context: Option<&'a crate::procedural::ExecutionContext>,
22 pub(super) cte_context:
24 Option<&'a std::collections::HashMap<String, crate::select::cte::CteResult>>,
25 pub(super) depth: usize,
27 pub(super) cse_cache: Rc<RefCell<LruCache<u64, vibesql_types::SqlValue>>>,
30 pub(super) enable_cse: bool,
32 pub(super) subquery_cache: Rc<RefCell<LruCache<u64, Vec<vibesql_storage::Row>>>>,
35 pub(super) row_index: Option<u64>,
38 pub(super) table_alias: Option<String>,
41 pub(super) schema_context: super::SchemaExprContext,
45}
46
47impl<'a> ExpressionEvaluator<'a> {
48 pub fn new(schema: &'a vibesql_catalog::TableSchema) -> Self {
50 ExpressionEvaluator {
51 schema,
52 outer_row: None,
53 outer_schema: None,
54 database: None,
55 trigger_context: None,
56 procedural_context: None,
57 cte_context: None,
58 depth: 0,
59 cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
60 enable_cse: super::caching::is_cse_enabled(),
61 subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
62 row_index: None,
63 table_alias: None,
64 schema_context: super::SchemaExprContext::None,
65 }
66 }
67
68 pub fn with_outer_context(
70 schema: &'a vibesql_catalog::TableSchema,
71 outer_row: &'a vibesql_storage::Row,
72 outer_schema: &'a vibesql_catalog::TableSchema,
73 ) -> Self {
74 ExpressionEvaluator {
75 schema,
76 outer_row: Some(outer_row),
77 outer_schema: Some(outer_schema),
78 database: None,
79 trigger_context: None,
80 procedural_context: None,
81 cte_context: None,
82 depth: 0,
83 cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
84 enable_cse: super::caching::is_cse_enabled(),
85 subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
86 row_index: None,
87 table_alias: None,
88 schema_context: super::SchemaExprContext::None,
89 }
90 }
91
92 pub fn with_database(
94 schema: &'a vibesql_catalog::TableSchema,
95 database: &'a vibesql_storage::Database,
96 ) -> Self {
97 ExpressionEvaluator {
98 schema,
99 outer_row: None,
100 outer_schema: None,
101 database: Some(database),
102 trigger_context: None,
103 procedural_context: None,
104 cte_context: None,
105 depth: 0,
106 cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
107 enable_cse: super::caching::is_cse_enabled(),
108 subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
109 row_index: None,
110 table_alias: None,
111 schema_context: super::SchemaExprContext::None,
112 }
113 }
114
115 pub fn with_trigger_context(
117 schema: &'a vibesql_catalog::TableSchema,
118 database: &'a vibesql_storage::Database,
119 trigger_context: &'a crate::trigger_execution::TriggerContext<'a>,
120 ) -> Self {
121 ExpressionEvaluator {
122 schema,
123 outer_row: None,
124 outer_schema: None,
125 database: Some(database),
126 trigger_context: Some(trigger_context),
127 procedural_context: None,
128 cte_context: None,
129 depth: 0,
130 cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
131 enable_cse: super::caching::is_cse_enabled(),
132 subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
133 row_index: None,
134 table_alias: None,
135 schema_context: super::SchemaExprContext::None,
136 }
137 }
138
139 pub fn with_database_and_outer_context(
142 schema: &'a vibesql_catalog::TableSchema,
143 database: &'a vibesql_storage::Database,
144 outer_row: &'a vibesql_storage::Row,
145 outer_schema: &'a vibesql_catalog::TableSchema,
146 ) -> Self {
147 ExpressionEvaluator {
148 schema,
149 outer_row: Some(outer_row),
150 outer_schema: Some(outer_schema),
151 database: Some(database),
152 trigger_context: None,
153 procedural_context: None,
154 cte_context: None,
155 depth: 0,
156 cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
157 enable_cse: super::caching::is_cse_enabled(),
158 subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
159 row_index: None,
160 table_alias: None,
161 schema_context: super::SchemaExprContext::None,
162 }
163 }
164
165 pub fn with_procedural_context(
168 schema: &'a vibesql_catalog::TableSchema,
169 database: &'a vibesql_storage::Database,
170 procedural_context: &'a crate::procedural::ExecutionContext,
171 ) -> Self {
172 ExpressionEvaluator {
173 schema,
174 outer_row: None,
175 outer_schema: None,
176 database: Some(database),
177 trigger_context: None,
178 procedural_context: Some(procedural_context),
179 cte_context: None,
180 depth: 0,
181 cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
182 enable_cse: super::caching::is_cse_enabled(),
183 subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
184 row_index: None,
185 table_alias: None,
186 schema_context: super::SchemaExprContext::None,
187 }
188 }
189
190 pub fn with_database_and_cte(
193 schema: &'a vibesql_catalog::TableSchema,
194 database: &'a vibesql_storage::Database,
195 cte_context: &'a std::collections::HashMap<String, crate::select::cte::CteResult>,
196 ) -> Self {
197 ExpressionEvaluator {
198 schema,
199 outer_row: None,
200 outer_schema: None,
201 database: Some(database),
202 trigger_context: None,
203 procedural_context: None,
204 cte_context: Some(cte_context),
205 depth: 0,
206 cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
207 enable_cse: super::caching::is_cse_enabled(),
208 subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
209 row_index: None,
210 table_alias: None,
211 schema_context: super::SchemaExprContext::None,
212 }
213 }
214
215 pub fn with_cte_context(
221 mut self,
222 cte_context: &'a std::collections::HashMap<String, crate::select::cte::CteResult>,
223 ) -> Self {
224 self.cte_context = Some(cte_context);
225 self
226 }
227
228 pub fn set_row_index(&mut self, index: u64) {
233 self.row_index = Some(index);
234 }
235
236 pub fn clear_row_index(&mut self) {
238 self.row_index = None;
239 }
240
241 pub fn set_table_alias(&mut self, alias: String) {
246 self.table_alias = Some(alias);
247 }
248
249 pub fn with_schema_context(mut self, schema_context: super::SchemaExprContext) -> Self {
257 self.schema_context = schema_context;
258 self
259 }
260
261 pub(crate) fn eval_binary_op(
263 &self,
264 left: &vibesql_types::SqlValue,
265 op: &vibesql_ast::BinaryOperator,
266 right: &vibesql_types::SqlValue,
267 ) -> Result<vibesql_types::SqlValue, ExecutorError> {
268 let sql_mode = self.database.map(|db| db.sql_mode()).unwrap_or_default();
270
271 super::core::eval_binary_op_static(left, op, right, sql_mode)
272 }
273
274 pub fn clear_cse_cache(&self) {
277 self.cse_cache.borrow_mut().clear();
278 }
279
280 pub(crate) fn eval_binary_op_static(
284 left: &vibesql_types::SqlValue,
285 op: &vibesql_ast::BinaryOperator,
286 right: &vibesql_types::SqlValue,
287 sql_mode: vibesql_types::SqlMode,
288 ) -> Result<vibesql_types::SqlValue, ExecutorError> {
289 super::core::eval_binary_op_static(left, op, right, sql_mode)
290 }
291
292 pub(crate) fn eval_between_static(
296 expr_val: &vibesql_types::SqlValue,
297 low_val: &vibesql_types::SqlValue,
298 high_val: &vibesql_types::SqlValue,
299 negated: bool,
300 symmetric: bool,
301 sql_mode: vibesql_types::SqlMode,
302 ) -> Result<vibesql_types::SqlValue, ExecutorError> {
303 super::core::eval_between_static(expr_val, low_val, high_val, negated, symmetric, sql_mode)
304 }
305
306 pub(crate) fn values_are_equal(
310 left: &vibesql_types::SqlValue,
311 right: &vibesql_types::SqlValue,
312 ) -> bool {
313 super::core::values_are_equal(left, right)
314 }
315
316 pub(crate) fn values_are_distinct(
320 left: &vibesql_types::SqlValue,
321 right: &vibesql_types::SqlValue,
322 ) -> bool {
323 super::core::values_are_distinct(left, right)
324 }
325
326 pub(super) fn with_incremented_depth<F, T>(&self, f: F) -> Result<T, ExecutorError>
328 where
329 F: FnOnce(&Self) -> Result<T, ExecutorError>,
330 {
331 let evaluator = ExpressionEvaluator {
334 schema: self.schema,
335 outer_row: self.outer_row,
336 outer_schema: self.outer_schema,
337 database: self.database,
338 trigger_context: self.trigger_context,
339 procedural_context: self.procedural_context,
340 cte_context: self.cte_context,
341 depth: self.depth + 1,
342 cse_cache: self.cse_cache.clone(),
343 enable_cse: self.enable_cse,
344 subquery_cache: self.subquery_cache.clone(),
345 row_index: self.row_index,
346 table_alias: self.table_alias.clone(),
347 schema_context: self.schema_context,
348 };
349 f(&evaluator)
350 }
351}