Skip to main content

uqa_sql/semantics/
parameters.rs

1//
2// Unified Query Algebra
3//
4// Copyright (c) 2023-2026 Cognica, Inc.
5//
6
7//! SET, SET LOCAL and temporary function configuration over retained parameter values.
8
9use std::collections::BTreeMap;
10
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub enum ParameterAssignment {
13    Session,
14    Local,
15    Save,
16}
17
18#[derive(Clone, Copy, Debug)]
19pub struct ParameterScope(usize);
20
21/// Values remain owned by the host; SQL decides which assignment lifetime restores them.
22#[derive(Clone)]
23pub struct ParameterScopes<T> {
24    transaction: BTreeMap<String, T>,
25    functions: Vec<BTreeMap<String, T>>,
26}
27
28impl<T> Default for ParameterScopes<T> {
29    fn default() -> Self {
30        Self {
31            transaction: BTreeMap::new(),
32            functions: Vec::new(),
33        }
34    }
35}
36
37impl<T> ParameterScopes<T> {
38    /// A session assignment supersedes pending LOCAL and function configuration restoration for this parameter.
39    pub fn session_assignment(&mut self, name: &str) {
40        self.transaction.remove(name);
41        for saved in &mut self.functions {
42            saved.remove(name);
43        }
44    }
45
46    pub fn enter_function(&mut self) -> ParameterScope {
47        self.functions.push(BTreeMap::new());
48        ParameterScope(self.functions.len())
49    }
50
51    pub fn leave_function(&mut self, scope: ParameterScope) -> BTreeMap<String, T> {
52        assert_eq!(scope.0, self.functions.len(), "parameter scope order");
53        self.functions.pop().expect("active parameter scope")
54    }
55
56    /// Record a successful assignment. An out-of-transaction LOCAL returns its immediate restoration value.
57    pub fn assigned(
58        &mut self,
59        name: String,
60        previous: T,
61        action: ParameterAssignment,
62        in_transaction: bool,
63    ) -> Option<T> {
64        match action {
65            ParameterAssignment::Session => {
66                self.session_assignment(&name);
67            }
68            ParameterAssignment::Local => {
69                if self.functions.iter().any(|saved| saved.contains_key(&name)) {
70                    return None;
71                }
72                if !in_transaction {
73                    return Some(previous);
74                }
75                self.transaction.entry(name).or_insert(previous);
76            }
77            ParameterAssignment::Save => {
78                self.functions
79                    .last_mut()
80                    .expect("function configuration requires a parameter scope")
81                    .entry(name)
82                    .or_insert(previous);
83            }
84        }
85        None
86    }
87
88    pub fn finish_transaction(&mut self) -> BTreeMap<String, T> {
89        std::mem::take(&mut self.transaction)
90    }
91
92    /// RESET ALL overrides ordinary settings while leaving both authorization parameters alone.
93    pub fn reset_all(&mut self) {
94        fn authorization(name: &str) -> bool {
95            matches!(name, "role" | "session_authorization")
96        }
97        self.transaction.retain(|name, _| authorization(name));
98        for saved in &mut self.functions {
99            saved.retain(|name, _| authorization(name));
100        }
101    }
102}
103
104#[cfg(test)]
105mod tests;