uqa_sql/semantics/privileges/
context.rs1use crate::{
10 catalog::resolution::RelationNameResolution,
11 plan::{CtePlan, QueryPlan},
12 SQLError,
13};
14use std::collections::BTreeMap;
15
16#[derive(Clone, Copy)]
17pub enum PrivilegeRelationKind {
18 Table,
19 View,
20 MaterializedView,
21 ForeignTable,
22}
23impl PrivilegeRelationKind {
24 pub const fn has_system_columns(self) -> bool {
25 matches!(self, Self::Table | Self::ForeignTable)
26 }
27 pub const fn description(self) -> &'static str {
28 match self {
29 Self::Table => "table",
30 Self::View => "view",
31 Self::MaterializedView => "materialized view",
32 Self::ForeignTable => "foreign table",
33 }
34 }
35}
36pub struct PrivilegeRelation {
37 pub canonical: String,
38 pub columns: Vec<String>,
39 pub kind: PrivilegeRelationKind,
40}
41pub trait PrivilegeCatalog {
42 fn relation(
43 &self,
44 resolution: &RelationNameResolution,
45 name: &str,
46 ) -> Result<Option<PrivilegeRelation>, SQLError>;
47 fn has_select_privilege(
48 &self,
49 resolution: &RelationNameResolution,
50 relation: &PrivilegeRelation,
51 column: Option<&str>,
52 subject: &str,
53 ) -> Result<bool, SQLError>;
54}
55pub trait PrivilegeCteCatalog {
56 fn is_visible_cte(&self, name: &str) -> bool;
57 fn materialized_columns(&self, name: &str) -> Option<Vec<String>>;
58 fn deferred_reference(&self, name: &str) -> Option<&CtePlan>;
59 fn privilege_subject(&self) -> Result<&str, SQLError>;
60}
61#[derive(Clone)]
62pub struct PrivilegeScope<'a> {
63 pub catalog: &'a dyn PrivilegeCatalog,
64 pub resolution: RelationNameResolution,
65 pub inherited: &'a dyn PrivilegeCteCatalog,
66 pub scalar_subqueries: Vec<QueryPlan>,
67 local_ctes: BTreeMap<String, CtePlan>,
68}
69impl<'a> PrivilegeScope<'a> {
70 pub fn new(
71 catalog: &'a dyn PrivilegeCatalog,
72 resolution: RelationNameResolution,
73 inherited: &'a dyn PrivilegeCteCatalog,
74 scalar_subqueries: Vec<QueryPlan>,
75 ) -> Self {
76 Self {
77 catalog,
78 resolution,
79 inherited,
80 scalar_subqueries,
81 local_ctes: BTreeMap::new(),
82 }
83 }
84 pub fn insert_deferred(&mut self, plan: CtePlan) {
85 self.local_ctes.insert(plan.name.clone(), plan);
86 }
87 pub fn is_visible_cte(&self, name: &str) -> bool {
88 crate::semantics::cte_reference_name(name)
89 .is_some_and(|name| self.local_ctes.contains_key(&name))
90 || self.inherited.is_visible_cte(name)
91 }
92 pub fn materialized_for_scan(&self, name: &str) -> Option<Vec<String>> {
93 let canonical = crate::semantics::cte_reference_name(name)?;
94 if self.local_ctes.contains_key(&canonical) {
95 None
96 } else {
97 self.inherited.materialized_columns(name)
98 }
99 }
100 pub fn deferred_reference(&self, name: &str) -> Option<&CtePlan> {
101 self.local_ctes
102 .get(&crate::semantics::cte_reference_name(name)?)
103 .or_else(|| self.inherited.deferred_reference(name))
104 }
105
106 pub fn privilege_subject(&self) -> Result<&str, SQLError> {
107 self.inherited.privilege_subject()
108 }
109}