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 pub(super) include_authorization_only_columns: bool,
75}
76impl<'a> PrivilegeScope<'a> {
77 pub fn new(
78 catalog: &'a dyn PrivilegeCatalog,
79 resolution: RelationNameResolution,
80 inherited: &'a dyn PrivilegeCteCatalog,
81 scalar_subqueries: Vec<QueryPlan>,
82 ) -> Self {
83 Self {
84 catalog,
85 resolution,
86 inherited,
87 scalar_subqueries,
88 local_ctes: BTreeMap::new(),
89 include_authorization_only_columns: true,
90 }
91 }
92 pub fn insert_deferred(&mut self, plan: CtePlan) {
93 self.local_ctes.insert(plan.name.clone(), plan);
94 }
95 pub fn is_visible_cte(&self, name: &str) -> bool {
96 crate::semantics::cte_reference_name(name)
97 .is_some_and(|name| self.local_ctes.contains_key(&name))
98 || self.inherited.is_visible_cte(name)
99 }
100 pub fn materialized_for_scan(&self, name: &str) -> Option<Vec<String>> {
101 let canonical = crate::semantics::cte_reference_name(name)?;
102 if self.local_ctes.contains_key(&canonical) {
103 None
104 } else {
105 self.inherited.materialized_columns(name)
106 }
107 }
108 pub fn deferred_reference(&self, name: &str) -> Option<&CtePlan> {
109 self.local_ctes
110 .get(&crate::semantics::cte_reference_name(name)?)
111 .or_else(|| self.inherited.deferred_reference(name))
112 }
113
114 pub fn privilege_subject(&self) -> Result<&RoleReference, SQLError> {
115 self.inherited.privilege_subject()
116 }
117}