1use crate::ast::{CreateRoleStmt, RoleAttribute};
10use serde::{Deserialize, Serialize};
11use std::collections::BTreeSet;
12
13pub mod memberships;
14pub use memberships::{role_can_set, role_inherits};
15
16#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17pub struct RoleDefinition {
18 pub oid: i64,
19 pub name: String,
20 pub attributes: BTreeSet<RoleAttribute>,
21 pub connection_limit: i32,
22}
23
24#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize)]
25pub struct RoleMembershipKey {
26 pub role: String,
27 pub member: String,
28 pub grantor: String,
29}
30
31#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
32pub struct RoleMembership {
33 pub oid: i64,
34 pub role: String,
35 pub member: String,
36 pub grantor: String,
37 pub admin_option: bool,
38 pub inherit_option: bool,
39 pub set_option: bool,
40}
41
42impl RoleMembership {
43 pub fn key(&self) -> RoleMembershipKey {
44 RoleMembershipKey {
45 role: self.role.clone(),
46 member: self.member.clone(),
47 grantor: self.grantor.clone(),
48 }
49 }
50}
51
52impl RoleDefinition {
53 pub fn bootstrap() -> Self {
54 Self {
55 oid: 10,
56 name: "uqa".into(),
57 attributes: BTreeSet::from([
58 RoleAttribute::Superuser,
59 RoleAttribute::Inherit,
60 RoleAttribute::CreateRole,
61 RoleAttribute::CreateDb,
62 RoleAttribute::Login,
63 RoleAttribute::BypassRls,
64 ]),
65 connection_limit: -1,
66 }
67 }
68
69 pub fn from_create(statement: &CreateRoleStmt) -> Self {
70 Self {
71 oid: role_oid(&statement.name),
72 name: statement.name.clone(),
73 attributes: statement.attributes.clone(),
74 connection_limit: statement.connection_limit,
75 }
76 }
77
78 pub fn has(&self, attribute: RoleAttribute) -> bool {
79 self.attributes.contains(&attribute)
80 }
81}
82
83pub fn role_oid(name: &str) -> i64 {
84 if name == "uqa" {
85 return 10;
86 }
87 let mut hash = 14_695_981_039_346_656_037_u64;
88 for byte in name.as_bytes() {
89 hash ^= u64::from(*byte);
90 hash = hash.wrapping_mul(1_099_511_628_211);
91 }
92 20_000 + i64::try_from(hash % 2_000_000_000).unwrap_or(0)
93}
94
95pub trait RoleReferenceNames {
97 fn current_user_name(&self) -> String;
98 fn session_user_name(&self) -> String;
99}
100pub fn resolve_role_reference(names: &dyn RoleReferenceNames, name: &str) -> String {
101 match name {
102 "CURRENT_USER" => names.current_user_name(),
103 "SESSION_USER" => names.session_user_name(),
104 other => other.to_string(),
105 }
106}
107pub fn require_role_exists(
108 roles: &std::collections::BTreeMap<String, RoleDefinition>,
109 name: &str,
110) -> Result<(), crate::SQLError> {
111 if roles.contains_key(name) {
112 return Ok(());
113 }
114 Err(crate::SQLError::Routine {
115 sqlstate: "42704".into(),
116 message: format!("role \"{name}\" does not exist"),
117 })
118}
119pub fn require_set_role(
120 roles: &std::collections::BTreeMap<String, RoleDefinition>,
121 memberships: &std::collections::BTreeMap<RoleMembershipKey, RoleMembership>,
122 current: &str,
123 target: &str,
124) -> Result<(), crate::SQLError> {
125 if role_can_set(roles, memberships, current, target) {
126 return Ok(());
127 }
128 Err(crate::SQLError::Routine {
129 sqlstate: "42501".into(),
130 message: format!("must be able to SET ROLE \"{target}\""),
131 })
132}
133
134pub mod definition;
135pub mod dependencies;
136pub mod guards;
137pub mod inquiry;
138pub mod restoration;