uqa_sql/catalog/roles/dependencies/
temporary.rs1use super::context::TemporaryRoleDependencyCatalog;
10use crate::{
11 ast::RelationPersistence,
12 catalog::{
13 roles::RoleDefinition,
14 security::{dependencies::AclRoleReferences, BoundTableSecurity},
15 },
16 SQLError,
17};
18use std::collections::{BTreeMap, BTreeSet};
19
20pub fn role_dependencies(
21 catalog: &dyn TemporaryRoleDependencyCatalog,
22 roles: &BTreeMap<String, RoleDefinition>,
23 limit: usize,
24) -> Result<BTreeSet<u32>, SQLError> {
25 let mut referenced = BTreeSet::new();
26 {
27 let tables = catalog.tables();
28 for (_, table) in tables.iter() {
29 if table.persistence() == RelationPersistence::Temporary {
30 table_dependencies(&table.security(), roles, limit, &mut referenced)?;
31 }
32 }
33 }
34 {
35 let views = catalog.views();
36 for view in views.values() {
37 if view.persistence == RelationPersistence::Temporary {
38 table_dependencies(&view.security(), roles, limit, &mut referenced)?;
39 }
40 }
41 }
42 {
43 let sequences = catalog.sequences();
44 let persistence = catalog.sequence_persistence();
45 for (name, security) in sequences.iter() {
46 if persistence.get(name) == Some(&RelationPersistence::Temporary) {
47 let security = security.resolve(roles).map_err(SQLError::Internal)?;
48 add_role(&security.role_owner, roles, limit, &mut referenced)?;
49 acl_dependencies(
50 security.acl.as_deref().unwrap_or_default(),
51 roles,
52 limit,
53 &mut referenced,
54 )?;
55 }
56 }
57 }
58 Ok(referenced)
59}
60
61fn table_dependencies(
62 security: &BoundTableSecurity,
63 roles: &BTreeMap<String, RoleDefinition>,
64 limit: usize,
65 referenced: &mut BTreeSet<u32>,
66) -> Result<(), SQLError> {
67 let named = security.resolve(roles).map_err(SQLError::Internal)?;
69 add_role(&named.role_owner, roles, limit, referenced)?;
70 acl_dependencies(
71 named.acl.as_deref().unwrap_or_default(),
72 roles,
73 limit,
74 referenced,
75 )?;
76 for acl in named.column_acls.values() {
77 acl_dependencies(acl, roles, limit, referenced)?;
78 }
79 Ok(())
80}
81
82fn acl_dependencies<T: AclRoleReferences>(
83 acl: &[T],
84 roles: &BTreeMap<String, RoleDefinition>,
85 limit: usize,
86 referenced: &mut BTreeSet<u32>,
87) -> Result<(), SQLError> {
88 for entry in acl {
89 let (grantee, grantor) = entry.role_references();
90 if let Some(grantee) = grantee {
91 add_role(grantee, roles, limit, referenced)?;
92 }
93 if let Some(grantor) = grantor {
94 add_role(grantor, roles, limit, referenced)?;
95 }
96 }
97 Ok(())
98}
99
100fn add_role(
101 name: &str,
102 roles: &BTreeMap<String, RoleDefinition>,
103 limit: usize,
104 referenced: &mut BTreeSet<u32>,
105) -> Result<(), SQLError> {
106 let role = roles.get(name).ok_or_else(|| SQLError::Routine {
107 sqlstate: "42704".into(),
108 message: format!("role \"{name}\" does not exist"),
109 })?;
110 if role.oid <= 0 {
111 return Err(SQLError::Internal("invalid role OID".into()));
112 }
113 if role.oid != 10 {
114 referenced.insert(
115 u32::try_from(role.oid).map_err(|_| SQLError::Internal("invalid role OID".into()))?,
116 );
117 if referenced.len() > limit {
118 return Err(SQLError::Routine {
119 sqlstate: "53200".into(),
120 message: "temporary role dependency capacity exhausted".into(),
121 });
122 }
123 }
124 Ok(())
125}