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