sqlparser/ast/
dcl.rs

1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements.  See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership.  The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License.  You may obtain a copy of the License at
8//
9//   http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied.  See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! AST types specific to GRANT/REVOKE/ROLE variants of [`Statement`](crate::ast::Statement)
19//! (commonly referred to as Data Control Language, or DCL)
20
21#[cfg(not(feature = "std"))]
22use alloc::vec::Vec;
23use core::fmt;
24
25#[cfg(feature = "serde")]
26use serde::{Deserialize, Serialize};
27
28#[cfg(feature = "visitor")]
29use sqlparser_derive::{Visit, VisitMut};
30
31use super::{display_comma_separated, Expr, Ident, Password, Spanned};
32use crate::ast::{display_separated, ObjectName};
33use crate::tokenizer::Span;
34
35/// An option in `ROLE` statement.
36///
37/// <https://www.postgresql.org/docs/current/sql-createrole.html>
38#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
39#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
40#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
41pub enum RoleOption {
42    BypassRLS(bool),
43    ConnectionLimit(Expr),
44    CreateDB(bool),
45    CreateRole(bool),
46    Inherit(bool),
47    Login(bool),
48    Password(Password),
49    Replication(bool),
50    SuperUser(bool),
51    ValidUntil(Expr),
52}
53
54impl fmt::Display for RoleOption {
55    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
56        match self {
57            RoleOption::BypassRLS(value) => {
58                write!(f, "{}", if *value { "BYPASSRLS" } else { "NOBYPASSRLS" })
59            }
60            RoleOption::ConnectionLimit(expr) => {
61                write!(f, "CONNECTION LIMIT {expr}")
62            }
63            RoleOption::CreateDB(value) => {
64                write!(f, "{}", if *value { "CREATEDB" } else { "NOCREATEDB" })
65            }
66            RoleOption::CreateRole(value) => {
67                write!(f, "{}", if *value { "CREATEROLE" } else { "NOCREATEROLE" })
68            }
69            RoleOption::Inherit(value) => {
70                write!(f, "{}", if *value { "INHERIT" } else { "NOINHERIT" })
71            }
72            RoleOption::Login(value) => {
73                write!(f, "{}", if *value { "LOGIN" } else { "NOLOGIN" })
74            }
75            RoleOption::Password(password) => match password {
76                Password::Password(expr) => write!(f, "PASSWORD {expr}"),
77                Password::NullPassword => write!(f, "PASSWORD NULL"),
78            },
79            RoleOption::Replication(value) => {
80                write!(
81                    f,
82                    "{}",
83                    if *value {
84                        "REPLICATION"
85                    } else {
86                        "NOREPLICATION"
87                    }
88                )
89            }
90            RoleOption::SuperUser(value) => {
91                write!(f, "{}", if *value { "SUPERUSER" } else { "NOSUPERUSER" })
92            }
93            RoleOption::ValidUntil(expr) => {
94                write!(f, "VALID UNTIL {expr}")
95            }
96        }
97    }
98}
99
100/// SET config value option:
101/// * SET `configuration_parameter` { TO | = } { `value` | DEFAULT }
102/// * SET `configuration_parameter` FROM CURRENT
103#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
104#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
105#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
106pub enum SetConfigValue {
107    Default,
108    FromCurrent,
109    Value(Expr),
110}
111
112/// RESET config option:
113/// * RESET `configuration_parameter`
114/// * RESET ALL
115#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
116#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
117#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
118pub enum ResetConfig {
119    ALL,
120    ConfigName(ObjectName),
121}
122
123/// An `ALTER ROLE` (`Statement::AlterRole`) operation
124#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
125#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
126#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
127pub enum AlterRoleOperation {
128    /// Generic
129    RenameRole {
130        role_name: Ident,
131    },
132    /// MS SQL Server
133    /// <https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-role-transact-sql>
134    AddMember {
135        member_name: Ident,
136    },
137    DropMember {
138        member_name: Ident,
139    },
140    /// PostgreSQL
141    /// <https://www.postgresql.org/docs/current/sql-alterrole.html>
142    WithOptions {
143        options: Vec<RoleOption>,
144    },
145    Set {
146        config_name: ObjectName,
147        config_value: SetConfigValue,
148        in_database: Option<ObjectName>,
149    },
150    Reset {
151        config_name: ResetConfig,
152        in_database: Option<ObjectName>,
153    },
154}
155
156impl fmt::Display for AlterRoleOperation {
157    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
158        match self {
159            AlterRoleOperation::RenameRole { role_name } => {
160                write!(f, "RENAME TO {role_name}")
161            }
162            AlterRoleOperation::AddMember { member_name } => {
163                write!(f, "ADD MEMBER {member_name}")
164            }
165            AlterRoleOperation::DropMember { member_name } => {
166                write!(f, "DROP MEMBER {member_name}")
167            }
168            AlterRoleOperation::WithOptions { options } => {
169                write!(f, "WITH {}", display_separated(options, " "))
170            }
171            AlterRoleOperation::Set {
172                config_name,
173                config_value,
174                in_database,
175            } => {
176                if let Some(database_name) = in_database {
177                    write!(f, "IN DATABASE {database_name} ")?;
178                }
179
180                match config_value {
181                    SetConfigValue::Default => write!(f, "SET {config_name} TO DEFAULT"),
182                    SetConfigValue::FromCurrent => write!(f, "SET {config_name} FROM CURRENT"),
183                    SetConfigValue::Value(expr) => write!(f, "SET {config_name} TO {expr}"),
184                }
185            }
186            AlterRoleOperation::Reset {
187                config_name,
188                in_database,
189            } => {
190                if let Some(database_name) = in_database {
191                    write!(f, "IN DATABASE {database_name} ")?;
192                }
193
194                match config_name {
195                    ResetConfig::ALL => write!(f, "RESET ALL"),
196                    ResetConfig::ConfigName(name) => write!(f, "RESET {name}"),
197                }
198            }
199        }
200    }
201}
202
203/// A `USE` (`Statement::Use`) operation
204#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
205#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
206#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
207pub enum Use {
208    Catalog(ObjectName),            // e.g. `USE CATALOG foo.bar`
209    Schema(ObjectName),             // e.g. `USE SCHEMA foo.bar`
210    Database(ObjectName),           // e.g. `USE DATABASE foo.bar`
211    Warehouse(ObjectName),          // e.g. `USE WAREHOUSE foo.bar`
212    Role(ObjectName),               // e.g. `USE ROLE PUBLIC`
213    SecondaryRoles(SecondaryRoles), // e.g. `USE SECONDARY ROLES ALL`
214    Object(ObjectName),             // e.g. `USE foo.bar`
215    Default,                        // e.g. `USE DEFAULT`
216}
217
218impl fmt::Display for Use {
219    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
220        f.write_str("USE ")?;
221        match self {
222            Use::Catalog(name) => write!(f, "CATALOG {name}"),
223            Use::Schema(name) => write!(f, "SCHEMA {name}"),
224            Use::Database(name) => write!(f, "DATABASE {name}"),
225            Use::Warehouse(name) => write!(f, "WAREHOUSE {name}"),
226            Use::Role(name) => write!(f, "ROLE {name}"),
227            Use::SecondaryRoles(secondary_roles) => {
228                write!(f, "SECONDARY ROLES {secondary_roles}")
229            }
230            Use::Object(name) => write!(f, "{name}"),
231            Use::Default => write!(f, "DEFAULT"),
232        }
233    }
234}
235
236/// Snowflake `SECONDARY ROLES` USE variant
237/// See: <https://docs.snowflake.com/en/sql-reference/sql/use-secondary-roles>
238#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
239#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
240#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
241pub enum SecondaryRoles {
242    All,
243    None,
244    List(Vec<Ident>),
245}
246
247impl fmt::Display for SecondaryRoles {
248    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
249        match self {
250            SecondaryRoles::All => write!(f, "ALL"),
251            SecondaryRoles::None => write!(f, "NONE"),
252            SecondaryRoles::List(roles) => write!(f, "{}", display_comma_separated(roles)),
253        }
254    }
255}
256
257/// CREATE ROLE statement
258/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createrole.html)
259#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
260#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
261#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
262pub struct CreateRole {
263    pub names: Vec<ObjectName>,
264    pub if_not_exists: bool,
265    // Postgres
266    pub login: Option<bool>,
267    pub inherit: Option<bool>,
268    pub bypassrls: Option<bool>,
269    pub password: Option<Password>,
270    pub superuser: Option<bool>,
271    pub create_db: Option<bool>,
272    pub create_role: Option<bool>,
273    pub replication: Option<bool>,
274    pub connection_limit: Option<Expr>,
275    pub valid_until: Option<Expr>,
276    pub in_role: Vec<Ident>,
277    pub in_group: Vec<Ident>,
278    pub role: Vec<Ident>,
279    pub user: Vec<Ident>,
280    pub admin: Vec<Ident>,
281    // MSSQL
282    pub authorization_owner: Option<ObjectName>,
283}
284
285impl fmt::Display for CreateRole {
286    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
287        write!(
288            f,
289            "CREATE ROLE {if_not_exists}{names}{superuser}{create_db}{create_role}{inherit}{login}{replication}{bypassrls}",
290            if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
291            names = display_separated(&self.names, ", "),
292            superuser = match self.superuser {
293                Some(true) => " SUPERUSER",
294                Some(false) => " NOSUPERUSER",
295                None => ""
296            },
297            create_db = match self.create_db {
298                Some(true) => " CREATEDB",
299                Some(false) => " NOCREATEDB",
300                None => ""
301            },
302            create_role = match self.create_role {
303                Some(true) => " CREATEROLE",
304                Some(false) => " NOCREATEROLE",
305                None => ""
306            },
307            inherit = match self.inherit {
308                Some(true) => " INHERIT",
309                Some(false) => " NOINHERIT",
310                None => ""
311            },
312            login = match self.login {
313                Some(true) => " LOGIN",
314                Some(false) => " NOLOGIN",
315                None => ""
316            },
317            replication = match self.replication {
318                Some(true) => " REPLICATION",
319                Some(false) => " NOREPLICATION",
320                None => ""
321            },
322            bypassrls = match self.bypassrls {
323                Some(true) => " BYPASSRLS",
324                Some(false) => " NOBYPASSRLS",
325                None => ""
326            }
327        )?;
328        if let Some(limit) = &self.connection_limit {
329            write!(f, " CONNECTION LIMIT {limit}")?;
330        }
331        match &self.password {
332            Some(Password::Password(pass)) => write!(f, " PASSWORD {pass}")?,
333            Some(Password::NullPassword) => write!(f, " PASSWORD NULL")?,
334            None => {}
335        };
336        if let Some(until) = &self.valid_until {
337            write!(f, " VALID UNTIL {until}")?;
338        }
339        if !self.in_role.is_empty() {
340            write!(f, " IN ROLE {}", display_comma_separated(&self.in_role))?;
341        }
342        if !self.in_group.is_empty() {
343            write!(f, " IN GROUP {}", display_comma_separated(&self.in_group))?;
344        }
345        if !self.role.is_empty() {
346            write!(f, " ROLE {}", display_comma_separated(&self.role))?;
347        }
348        if !self.user.is_empty() {
349            write!(f, " USER {}", display_comma_separated(&self.user))?;
350        }
351        if !self.admin.is_empty() {
352            write!(f, " ADMIN {}", display_comma_separated(&self.admin))?;
353        }
354        if let Some(owner) = &self.authorization_owner {
355            write!(f, " AUTHORIZATION {owner}")?;
356        }
357        Ok(())
358    }
359}
360
361impl Spanned for CreateRole {
362    fn span(&self) -> Span {
363        Span::empty()
364    }
365}