Skip to main content

radixdb_sql/ast/
security.rs

1// Copyright 2026 RadixDB Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8
9use super::*;
10
11#[derive(Debug, Clone, PartialEq)]
12pub struct CreateSchemaStatement {
13    pub token: Token,
14    pub name: ObjectName,
15}
16
17impl fmt::Display for CreateSchemaStatement {
18    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
19        write!(formatter, "CREATE SCHEMA {}", self.name)
20    }
21}
22
23#[derive(Clone, PartialEq)]
24pub struct CreatePrincipalStatement {
25    pub token: Token,
26    pub name: Identifier,
27    /// Plaintext exists only in the transient parsed statement. Display is
28    /// deliberately redacted and the catalog stores only a verifier.
29    pub password: Option<String>,
30}
31
32impl fmt::Debug for CreatePrincipalStatement {
33    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
34        formatter
35            .debug_struct("CreatePrincipalStatement")
36            .field("token", &self.token)
37            .field("name", &self.name)
38            .field("password", &self.password.as_ref().map(|_| "<redacted>"))
39            .finish()
40    }
41}
42
43impl fmt::Display for CreatePrincipalStatement {
44    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
45        write!(formatter, "CREATE PRINCIPAL {}", self.name)?;
46        if self.password.is_some() {
47            formatter.write_str(" PASSWORD '<redacted>'")?;
48        }
49        Ok(())
50    }
51}
52
53#[derive(Debug, Clone, PartialEq)]
54pub struct CreateRoleStatement {
55    pub token: Token,
56    pub name: Identifier,
57}
58
59impl fmt::Display for CreateRoleStatement {
60    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
61        write!(formatter, "CREATE ROLE {}", self.name)
62    }
63}
64
65#[derive(Debug, Clone, Copy, PartialEq, Eq)]
66pub enum SecuritySubjectKindSyntax {
67    Principal,
68    Role,
69}
70
71impl fmt::Display for SecuritySubjectKindSyntax {
72    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
73        formatter.write_str(match self {
74            Self::Principal => "PRINCIPAL",
75            Self::Role => "ROLE",
76        })
77    }
78}
79
80#[derive(Clone, PartialEq)]
81pub enum AlterSecuritySubjectActionSyntax {
82    Enable,
83    Disable,
84    RenameTo(Identifier),
85    SetPassword(String),
86    ClearPassword,
87}
88
89impl fmt::Debug for AlterSecuritySubjectActionSyntax {
90    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
91        match self {
92            Self::Enable => formatter.write_str("Enable"),
93            Self::Disable => formatter.write_str("Disable"),
94            Self::RenameTo(name) => formatter.debug_tuple("RenameTo").field(name).finish(),
95            Self::SetPassword(_) => formatter
96                .debug_tuple("SetPassword")
97                .field(&"<redacted>")
98                .finish(),
99            Self::ClearPassword => formatter.write_str("ClearPassword"),
100        }
101    }
102}
103
104#[derive(Debug, Clone, PartialEq)]
105pub struct AlterSecuritySubjectStatement {
106    pub token: Token,
107    pub kind: SecuritySubjectKindSyntax,
108    pub name: Identifier,
109    pub action: AlterSecuritySubjectActionSyntax,
110}
111
112impl fmt::Display for AlterSecuritySubjectStatement {
113    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
114        write!(formatter, "ALTER {} {} ", self.kind, self.name)?;
115        match &self.action {
116            AlterSecuritySubjectActionSyntax::Enable => formatter.write_str("ENABLE"),
117            AlterSecuritySubjectActionSyntax::Disable => formatter.write_str("DISABLE"),
118            AlterSecuritySubjectActionSyntax::RenameTo(name) => {
119                write!(formatter, "RENAME TO {name}")
120            }
121            AlterSecuritySubjectActionSyntax::SetPassword(_) => {
122                formatter.write_str("PASSWORD '<redacted>'")
123            }
124            AlterSecuritySubjectActionSyntax::ClearPassword => formatter.write_str("PASSWORD NULL"),
125        }
126    }
127}
128
129#[derive(Debug, Clone, Copy, PartialEq, Eq)]
130pub enum DropBehaviorSyntax {
131    Restrict,
132    Cascade,
133}
134
135impl fmt::Display for DropBehaviorSyntax {
136    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
137        formatter.write_str(match self {
138            Self::Restrict => "RESTRICT",
139            Self::Cascade => "CASCADE",
140        })
141    }
142}
143
144#[derive(Debug, Clone, PartialEq)]
145pub struct DropSecuritySubjectStatement {
146    pub token: Token,
147    pub kind: SecuritySubjectKindSyntax,
148    pub name: Identifier,
149    pub behavior: DropBehaviorSyntax,
150}
151
152impl fmt::Display for DropSecuritySubjectStatement {
153    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
154        write!(
155            formatter,
156            "DROP {} {} {}",
157            self.kind, self.name, self.behavior
158        )
159    }
160}
161
162#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
163pub enum ObjectPrivilegeSyntax {
164    Connect,
165    Usage,
166    Create,
167    Select,
168    Insert,
169    Update,
170    Delete,
171    Execute,
172}
173
174impl fmt::Display for ObjectPrivilegeSyntax {
175    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
176        formatter.write_str(match self {
177            Self::Connect => "CONNECT",
178            Self::Usage => "USAGE",
179            Self::Create => "CREATE",
180            Self::Select => "SELECT",
181            Self::Insert => "INSERT",
182            Self::Update => "UPDATE",
183            Self::Delete => "DELETE",
184            Self::Execute => "EXECUTE",
185        })
186    }
187}
188
189#[derive(Debug, Clone, PartialEq)]
190pub struct PrivilegeSyntax {
191    pub kind: ObjectPrivilegeSyntax,
192    pub columns: Vec<Identifier>,
193}
194
195impl fmt::Display for PrivilegeSyntax {
196    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
197        write!(formatter, "{}", self.kind)?;
198        if !self.columns.is_empty() {
199            formatter.write_str(" (")?;
200            for (index, column) in self.columns.iter().enumerate() {
201                if index > 0 {
202                    formatter.write_str(", ")?;
203                }
204                write!(formatter, "{column}")?;
205            }
206            formatter.write_str(")")?;
207        }
208        Ok(())
209    }
210}
211
212#[derive(Debug, Clone, PartialEq)]
213pub enum PrivilegeTargetSyntax {
214    Database(ObjectName),
215    Schema(ObjectName),
216    Table(ObjectName),
217    Function(RoutineSignatureSyntax),
218    Procedure(RoutineSignatureSyntax),
219}
220
221impl fmt::Display for PrivilegeTargetSyntax {
222    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
223        match self {
224            Self::Database(name) => write!(formatter, "DATABASE {name}"),
225            Self::Schema(name) => write!(formatter, "SCHEMA {name}"),
226            Self::Table(name) => write!(formatter, "TABLE {name}"),
227            Self::Function(signature) => write!(formatter, "FUNCTION {signature}"),
228            Self::Procedure(signature) => write!(formatter, "PROCEDURE {signature}"),
229        }
230    }
231}
232
233#[derive(Debug, Clone, PartialEq)]
234pub enum GrantSyntax {
235    RoleMembership {
236        role: Identifier,
237        member: Identifier,
238        admin_option: bool,
239    },
240    ObjectPrivileges {
241        privileges: Vec<PrivilegeSyntax>,
242        target: PrivilegeTargetSyntax,
243        grantee: Identifier,
244        grant_option: bool,
245    },
246}
247
248#[derive(Debug, Clone, PartialEq)]
249pub struct GrantStatement {
250    pub token: Token,
251    pub grant: GrantSyntax,
252}
253
254impl fmt::Display for GrantStatement {
255    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
256        formatter.write_str("GRANT ")?;
257        match &self.grant {
258            GrantSyntax::RoleMembership {
259                role,
260                member,
261                admin_option,
262            } => {
263                write!(formatter, "{role} TO {member}")?;
264                if *admin_option {
265                    formatter.write_str(" WITH ADMIN OPTION")?;
266                }
267                Ok(())
268            }
269            GrantSyntax::ObjectPrivileges {
270                privileges,
271                target,
272                grantee,
273                grant_option,
274            } => {
275                write_privileges(formatter, privileges)?;
276                write!(formatter, " ON {target} TO {grantee}")?;
277                if *grant_option {
278                    formatter.write_str(" WITH GRANT OPTION")?;
279                }
280                Ok(())
281            }
282        }
283    }
284}
285
286#[derive(Debug, Clone, PartialEq)]
287pub enum RevokeSyntax {
288    RoleMembership {
289        role: Identifier,
290        member: Identifier,
291        admin_option_only: bool,
292    },
293    ObjectPrivileges {
294        privileges: Vec<PrivilegeSyntax>,
295        target: PrivilegeTargetSyntax,
296        grantee: Identifier,
297        grant_option_only: bool,
298    },
299}
300
301#[derive(Debug, Clone, PartialEq)]
302pub struct RevokeStatement {
303    pub token: Token,
304    pub revoke: RevokeSyntax,
305    pub behavior: DropBehaviorSyntax,
306}
307
308impl fmt::Display for RevokeStatement {
309    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
310        formatter.write_str("REVOKE ")?;
311        match &self.revoke {
312            RevokeSyntax::RoleMembership {
313                role,
314                member,
315                admin_option_only,
316            } => {
317                if *admin_option_only {
318                    formatter.write_str("ADMIN OPTION FOR ")?;
319                }
320                write!(formatter, "{role} FROM {member}")
321            }
322            RevokeSyntax::ObjectPrivileges {
323                privileges,
324                target,
325                grantee,
326                grant_option_only,
327            } => {
328                if *grant_option_only {
329                    formatter.write_str("GRANT OPTION FOR ")?;
330                }
331                write_privileges(formatter, privileges)?;
332                write!(formatter, " ON {target} FROM {grantee}")
333            }
334        }?;
335        write!(formatter, " {}", self.behavior)
336    }
337}
338
339#[derive(Debug, Clone, PartialEq)]
340pub enum OwnershipTargetSyntax {
341    Table(ObjectName),
342    Function(RoutineSignatureSyntax),
343    Procedure(RoutineSignatureSyntax),
344}
345
346impl fmt::Display for OwnershipTargetSyntax {
347    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
348        match self {
349            Self::Table(name) => write!(formatter, "TABLE {name}"),
350            Self::Function(signature) => write!(formatter, "FUNCTION {signature}"),
351            Self::Procedure(signature) => write!(formatter, "PROCEDURE {signature}"),
352        }
353    }
354}
355
356#[derive(Debug, Clone, PartialEq)]
357pub struct AlterOwnerStatement {
358    pub token: Token,
359    pub target: OwnershipTargetSyntax,
360    pub owner: Identifier,
361}
362
363impl fmt::Display for AlterOwnerStatement {
364    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
365        write!(formatter, "ALTER {} OWNER TO {}", self.target, self.owner)
366    }
367}
368
369fn write_privileges(
370    formatter: &mut fmt::Formatter<'_>,
371    privileges: &[PrivilegeSyntax],
372) -> fmt::Result {
373    for (index, privilege) in privileges.iter().enumerate() {
374        if index > 0 {
375            formatter.write_str(", ")?;
376        }
377        write!(formatter, "{privilege}")?;
378    }
379    Ok(())
380}