use std::{cell::RefCell, rc::Rc};
use lru::LruCache;
use crate::errors::ExecutorError;
pub struct ExpressionEvaluator<'a> {
pub(super) schema: &'a vibesql_catalog::TableSchema,
pub(super) outer_row: Option<&'a vibesql_storage::Row>,
pub(super) outer_schema: Option<&'a vibesql_catalog::TableSchema>,
pub(super) database: Option<&'a vibesql_storage::Database>,
pub(super) trigger_context: Option<&'a crate::trigger_execution::TriggerContext<'a>>,
pub(super) procedural_context: Option<&'a crate::procedural::ExecutionContext>,
pub(super) cte_context:
Option<&'a std::collections::HashMap<String, crate::select::cte::CteResult>>,
pub(super) depth: usize,
pub(super) cse_cache: Rc<RefCell<LruCache<u64, vibesql_types::SqlValue>>>,
pub(super) enable_cse: bool,
pub(super) subquery_cache: Rc<RefCell<LruCache<u64, Vec<vibesql_storage::Row>>>>,
pub(super) row_index: Option<u64>,
pub(super) table_alias: Option<String>,
pub(super) schema_context: super::SchemaExprContext,
}
impl<'a> ExpressionEvaluator<'a> {
pub fn new(schema: &'a vibesql_catalog::TableSchema) -> Self {
ExpressionEvaluator {
schema,
outer_row: None,
outer_schema: None,
database: None,
trigger_context: None,
procedural_context: None,
cte_context: None,
depth: 0,
cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
enable_cse: super::caching::is_cse_enabled(),
subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
row_index: None,
table_alias: None,
schema_context: super::SchemaExprContext::None,
}
}
pub fn with_outer_context(
schema: &'a vibesql_catalog::TableSchema,
outer_row: &'a vibesql_storage::Row,
outer_schema: &'a vibesql_catalog::TableSchema,
) -> Self {
ExpressionEvaluator {
schema,
outer_row: Some(outer_row),
outer_schema: Some(outer_schema),
database: None,
trigger_context: None,
procedural_context: None,
cte_context: None,
depth: 0,
cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
enable_cse: super::caching::is_cse_enabled(),
subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
row_index: None,
table_alias: None,
schema_context: super::SchemaExprContext::None,
}
}
pub fn with_database(
schema: &'a vibesql_catalog::TableSchema,
database: &'a vibesql_storage::Database,
) -> Self {
ExpressionEvaluator {
schema,
outer_row: None,
outer_schema: None,
database: Some(database),
trigger_context: None,
procedural_context: None,
cte_context: None,
depth: 0,
cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
enable_cse: super::caching::is_cse_enabled(),
subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
row_index: None,
table_alias: None,
schema_context: super::SchemaExprContext::None,
}
}
pub fn with_trigger_context(
schema: &'a vibesql_catalog::TableSchema,
database: &'a vibesql_storage::Database,
trigger_context: &'a crate::trigger_execution::TriggerContext<'a>,
) -> Self {
ExpressionEvaluator {
schema,
outer_row: None,
outer_schema: None,
database: Some(database),
trigger_context: Some(trigger_context),
procedural_context: None,
cte_context: None,
depth: 0,
cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
enable_cse: super::caching::is_cse_enabled(),
subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
row_index: None,
table_alias: None,
schema_context: super::SchemaExprContext::None,
}
}
pub fn with_database_and_outer_context(
schema: &'a vibesql_catalog::TableSchema,
database: &'a vibesql_storage::Database,
outer_row: &'a vibesql_storage::Row,
outer_schema: &'a vibesql_catalog::TableSchema,
) -> Self {
ExpressionEvaluator {
schema,
outer_row: Some(outer_row),
outer_schema: Some(outer_schema),
database: Some(database),
trigger_context: None,
procedural_context: None,
cte_context: None,
depth: 0,
cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
enable_cse: super::caching::is_cse_enabled(),
subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
row_index: None,
table_alias: None,
schema_context: super::SchemaExprContext::None,
}
}
pub fn with_procedural_context(
schema: &'a vibesql_catalog::TableSchema,
database: &'a vibesql_storage::Database,
procedural_context: &'a crate::procedural::ExecutionContext,
) -> Self {
ExpressionEvaluator {
schema,
outer_row: None,
outer_schema: None,
database: Some(database),
trigger_context: None,
procedural_context: Some(procedural_context),
cte_context: None,
depth: 0,
cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
enable_cse: super::caching::is_cse_enabled(),
subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
row_index: None,
table_alias: None,
schema_context: super::SchemaExprContext::None,
}
}
pub fn with_database_and_cte(
schema: &'a vibesql_catalog::TableSchema,
database: &'a vibesql_storage::Database,
cte_context: &'a std::collections::HashMap<String, crate::select::cte::CteResult>,
) -> Self {
ExpressionEvaluator {
schema,
outer_row: None,
outer_schema: None,
database: Some(database),
trigger_context: None,
procedural_context: None,
cte_context: Some(cte_context),
depth: 0,
cse_cache: Rc::new(RefCell::new(super::caching::create_cse_cache())),
enable_cse: super::caching::is_cse_enabled(),
subquery_cache: Rc::new(RefCell::new(super::caching::create_subquery_cache())),
row_index: None,
table_alias: None,
schema_context: super::SchemaExprContext::None,
}
}
pub fn with_cte_context(
mut self,
cte_context: &'a std::collections::HashMap<String, crate::select::cte::CteResult>,
) -> Self {
self.cte_context = Some(cte_context);
self
}
pub fn set_row_index(&mut self, index: u64) {
self.row_index = Some(index);
}
pub fn clear_row_index(&mut self) {
self.row_index = None;
}
pub fn set_table_alias(&mut self, alias: String) {
self.table_alias = Some(alias);
}
pub fn with_schema_context(mut self, schema_context: super::SchemaExprContext) -> Self {
self.schema_context = schema_context;
self
}
pub(crate) fn eval_binary_op(
&self,
left: &vibesql_types::SqlValue,
op: &vibesql_ast::BinaryOperator,
right: &vibesql_types::SqlValue,
) -> Result<vibesql_types::SqlValue, ExecutorError> {
let sql_mode = self.database.map(|db| db.sql_mode()).unwrap_or_default();
super::core::eval_binary_op_static(left, op, right, sql_mode)
}
pub fn clear_cse_cache(&self) {
self.cse_cache.borrow_mut().clear();
}
pub(crate) fn eval_binary_op_static(
left: &vibesql_types::SqlValue,
op: &vibesql_ast::BinaryOperator,
right: &vibesql_types::SqlValue,
sql_mode: vibesql_types::SqlMode,
) -> Result<vibesql_types::SqlValue, ExecutorError> {
super::core::eval_binary_op_static(left, op, right, sql_mode)
}
pub(crate) fn eval_between_static(
expr_val: &vibesql_types::SqlValue,
low_val: &vibesql_types::SqlValue,
high_val: &vibesql_types::SqlValue,
negated: bool,
symmetric: bool,
sql_mode: vibesql_types::SqlMode,
) -> Result<vibesql_types::SqlValue, ExecutorError> {
super::core::eval_between_static(expr_val, low_val, high_val, negated, symmetric, sql_mode)
}
pub(crate) fn values_are_equal(
left: &vibesql_types::SqlValue,
right: &vibesql_types::SqlValue,
) -> bool {
super::core::values_are_equal(left, right)
}
pub(crate) fn values_are_distinct(
left: &vibesql_types::SqlValue,
right: &vibesql_types::SqlValue,
) -> bool {
super::core::values_are_distinct(left, right)
}
pub(super) fn with_incremented_depth<F, T>(&self, f: F) -> Result<T, ExecutorError>
where
F: FnOnce(&Self) -> Result<T, ExecutorError>,
{
let evaluator = ExpressionEvaluator {
schema: self.schema,
outer_row: self.outer_row,
outer_schema: self.outer_schema,
database: self.database,
trigger_context: self.trigger_context,
procedural_context: self.procedural_context,
cte_context: self.cte_context,
depth: self.depth + 1,
cse_cache: self.cse_cache.clone(),
enable_cse: self.enable_cse,
subquery_cache: self.subquery_cache.clone(),
row_index: self.row_index,
table_alias: self.table_alias.clone(),
schema_context: self.schema_context,
};
f(&evaluator)
}
}