iridium_core 0.1.12

SQL Server-compatible Rust engine core for Iridium SQL
Documentation
use std::collections::{HashMap, HashSet};

use crate::executor::context::{FrameState, SessionStateRefs};
use crate::executor::string_norm::{normalize_identifier, strip_dbo_prefix};

impl FrameState {
    pub fn fork(&self) -> Self {
        self.clone()
    }

    pub fn enter_scope<'a>(&mut self, session: &mut SessionStateRefs<'a>) {
        self.scope_vars.push(vec![]);
        self.table_vars.push(HashMap::new());
        self.readonly_table_vars.push(HashSet::new());
        session.identity_stack.push(None);
    }

    pub fn leave_scope_collect_table_vars<'a>(
        &mut self,
        session: &mut SessionStateRefs<'a>,
    ) -> Vec<String> {
        if let Some(vars) = self.scope_vars.pop() {
            for name in vars {
                session.variables.remove(&name);
            }
        }

        let mut dropped_physical = Vec::new();
        if self.table_vars.len() > 1 {
            if let Some(scope) = self.table_vars.pop() {
                for (logical, physical) in scope {
                    dropped_physical.push(physical.clone());
                    if session
                        .var_map
                        .get(&logical)
                        .map(|current| current.eq_ignore_ascii_case(&physical))
                        .unwrap_or(false)
                    {
                        let mut restored: Option<String> = None;
                        for outer in self.table_vars.iter().rev() {
                            if let Some(mapped) = outer.get(&logical) {
                                restored = Some(mapped.clone());
                                break;
                            }
                        }
                        if let Some(mapped) = restored {
                            session.var_map.insert(logical.clone(), mapped);
                        } else {
                            session.var_map.remove(&logical);
                        }
                    }
                }
            }
        }
        if self.readonly_table_vars.len() > 1 {
            let _ = self.readonly_table_vars.pop();
        }
        if let Some(val) = session.identity_stack.pop() {
            if let Some(last) = session.identity_stack.last_mut() {
                if val.is_some() {
                    *last = val;
                }
            }
        }
        dropped_physical
    }

    pub fn register_declared_var(&mut self, name: &str) {
        if let Some(scope) = self.scope_vars.last_mut() {
            scope.push(name.to_string());
        }
    }

    pub fn register_table_var<'a>(
        &mut self,
        session: &mut SessionStateRefs<'a>,
        logical_name: &str,
        physical_name: &str,
    ) {
        if let Some(scope) = self.table_vars.last_mut() {
            scope.insert(
                normalize_identifier(logical_name),
                physical_name.to_string(),
            );
        }
        session.var_map.insert(
            normalize_identifier(logical_name),
            physical_name.to_string(),
        );
    }

    pub fn mark_table_var_readonly(&mut self, logical_name: &str) {
        if let Some(scope) = self.readonly_table_vars.last_mut() {
            scope.insert(normalize_identifier(logical_name));
        }
    }

    pub fn is_readonly_table_var(&self, logical_name: &str) -> bool {
        let upper = normalize_identifier(strip_dbo_prefix(logical_name));
        self.readonly_table_vars
            .iter()
            .rev()
            .any(|scope| scope.contains(&upper))
    }

    pub fn resolve_table_name<'a>(
        &self,
        session: &SessionStateRefs<'a>,
        logical: &str,
    ) -> Option<String> {
        let upper = normalize_identifier(strip_dbo_prefix(logical));

        if let Some(mapped) = session.temp_map.get(&upper) {
            return Some(mapped.clone());
        }

        for scope in self.table_vars.iter().rev() {
            if let Some(name) = scope.get(&upper) {
                return Some(name.clone());
            }
        }
        if let Some(name) = session.var_map.get(&upper) {
            return Some(name.clone());
        }

        None
    }
}