dcl.rs - source

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::{
33    display_separated, CascadeOption, CurrentGrantsKind, GrantObjects, Grantee, ObjectName,
34    Privileges,
35};
36use crate::tokenizer::Span;
37
38/// An option in `ROLE` statement.
39///
40/// <https://www.postgresql.org/docs/current/sql-createrole.html>
41#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
42#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
43#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
44pub enum RoleOption {
45    /// Enable or disable BYPASSRLS.
46    BypassRLS(bool),
47    /// Connection limit expression.
48    ConnectionLimit(Expr),
49    /// CREATEDB flag.
50    CreateDB(bool),
51    /// CREATEROLE flag.
52    CreateRole(bool),
53    /// INHERIT flag.
54    Inherit(bool),
55    /// LOGIN flag.
56    Login(bool),
57    /// Password value or NULL password.
58    Password(Password),
59    /// Replication privilege flag.
60    Replication(bool),
61    /// SUPERUSER flag.
62    SuperUser(bool),
63    /// `VALID UNTIL` expression.
64    ValidUntil(Expr),
65}
66
67impl fmt::Display for RoleOption {
68    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
69        match self {
70            RoleOption::BypassRLS(value) => {
71                write!(f, "{}", if *value { "BYPASSRLS" } else { "NOBYPASSRLS" })
72            }
73            RoleOption::ConnectionLimit(expr) => {
74                write!(f, "CONNECTION LIMIT {expr}")
75            }
76            RoleOption::CreateDB(value) => {
77                write!(f, "{}", if *value { "CREATEDB" } else { "NOCREATEDB" })
78            }
79            RoleOption::CreateRole(value) => {
80                write!(f, "{}", if *value { "CREATEROLE" } else { "NOCREATEROLE" })
81            }
82            RoleOption::Inherit(value) => {
83                write!(f, "{}", if *value { "INHERIT" } else { "NOINHERIT" })
84            }
85            RoleOption::Login(value) => {
86                write!(f, "{}", if *value { "LOGIN" } else { "NOLOGIN" })
87            }
88            RoleOption::Password(password) => match password {
89                Password::Password(expr) => write!(f, "PASSWORD {expr}"),
90                Password::NullPassword => write!(f, "PASSWORD NULL"),
91            },
92            RoleOption::Replication(value) => {
93                write!(
94                    f,
95                    "{}",
96                    if *value {
97                        "REPLICATION"
98                    } else {
99                        "NOREPLICATION"
100                    }
101                )
102            }
103            RoleOption::SuperUser(value) => {
104                write!(f, "{}", if *value { "SUPERUSER" } else { "NOSUPERUSER" })
105            }
106            RoleOption::ValidUntil(expr) => {
107                write!(f, "VALID UNTIL {expr}")
108            }
109        }
110    }
111}
112
113/// SET config value option:
114/// * SET `configuration_parameter` { TO | = } { `value` | DEFAULT }
115/// * SET `configuration_parameter` FROM CURRENT
116#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
117#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
118#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
119pub enum SetConfigValue {
120    /// Use the default value.
121    Default,
122    /// Use the current value (`FROM CURRENT`).
123    FromCurrent,
124    /// Set to the provided expression value.
125    Value(Expr),
126}
127
128/// RESET config option:
129/// * RESET `configuration_parameter`
130/// * RESET ALL
131#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
132#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
133#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
134pub enum ResetConfig {
135    /// Reset all configuration parameters.
136    ALL,
137    /// Reset the named configuration parameter.
138    ConfigName(ObjectName),
139}
140
141/// An `ALTER ROLE` (`Statement::AlterRole`) operation
142#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
143#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
144#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
145pub enum AlterRoleOperation {
146    /// Generic
147    RenameRole {
148        /// Role name to rename.
149        role_name: Ident,
150    },
151    /// MS SQL Server
152    /// <https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-role-transact-sql>
153    AddMember {
154        /// Member name to add to the role.
155        member_name: Ident,
156    },
157    /// MS SQL Server
158    ///
159    /// <https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-role-transact-sql>
160    DropMember {
161        /// Member name to remove from the role.
162        member_name: Ident,
163    },
164    /// PostgreSQL
165    /// <https://www.postgresql.org/docs/current/sql-alterrole.html>
166    WithOptions {
167        /// Role options to apply.
168        options: Vec<RoleOption>,
169    },
170    /// PostgreSQL
171    /// <https://www.postgresql.org/docs/current/sql-alterrole.html>
172    ///
173    /// `SET configuration_parameter { TO | = } { value | DEFAULT }`
174    Set {
175        /// Configuration name to set.
176        config_name: ObjectName,
177        /// Value to assign to the configuration.
178        config_value: SetConfigValue,
179        /// Optional database scope for the setting.
180        in_database: Option<ObjectName>,
181    },
182    /// PostgreSQL
183    /// <https://www.postgresql.org/docs/current/sql-alterrole.html>
184    ///
185    /// `RESET configuration_parameter` | `RESET ALL`
186    Reset {
187        /// Configuration to reset.
188        config_name: ResetConfig,
189        /// Optional database scope for the reset.
190        in_database: Option<ObjectName>,
191    },
192}
193
194impl fmt::Display for AlterRoleOperation {
195    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
196        match self {
197            AlterRoleOperation::RenameRole { role_name } => {
198                write!(f, "RENAME TO {role_name}")
199            }
200            AlterRoleOperation::AddMember { member_name } => {
201                write!(f, "ADD MEMBER {member_name}")
202            }
203            AlterRoleOperation::DropMember { member_name } => {
204                write!(f, "DROP MEMBER {member_name}")
205            }
206            AlterRoleOperation::WithOptions { options } => {
207                write!(f, "WITH {}", display_separated(options, " "))
208            }
209            AlterRoleOperation::Set {
210                config_name,
211                config_value,
212                in_database,
213            } => {
214                if let Some(database_name) = in_database {
215                    write!(f, "IN DATABASE {database_name} ")?;
216                }
217
218                match config_value {
219                    SetConfigValue::Default => write!(f, "SET {config_name} TO DEFAULT"),
220                    SetConfigValue::FromCurrent => write!(f, "SET {config_name} FROM CURRENT"),
221                    SetConfigValue::Value(expr) => write!(f, "SET {config_name} TO {expr}"),
222                }
223            }
224            AlterRoleOperation::Reset {
225                config_name,
226                in_database,
227            } => {
228                if let Some(database_name) = in_database {
229                    write!(f, "IN DATABASE {database_name} ")?;
230                }
231
232                match config_name {
233                    ResetConfig::ALL => write!(f, "RESET ALL"),
234                    ResetConfig::ConfigName(name) => write!(f, "RESET {name}"),
235                }
236            }
237        }
238    }
239}
240
241/// A `USE` (`Statement::Use`) operation
242#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
243#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
244#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
245pub enum Use {
246    /// Switch to the given catalog (e.g. `USE CATALOG ...`).
247    Catalog(ObjectName),
248    /// Switch to the given schema (e.g. `USE SCHEMA ...`).
249    Schema(ObjectName),
250    /// Switch to the given database (e.g. `USE DATABASE ...`).
251    Database(ObjectName),
252    /// Switch to the given warehouse (e.g. `USE WAREHOUSE ...`).
253    Warehouse(ObjectName),
254    /// Switch to the given role (e.g. `USE ROLE ...`).
255    Role(ObjectName),
256    /// Use secondary roles specification (e.g. `USE SECONDARY ROLES ...`).
257    SecondaryRoles(SecondaryRoles),
258    /// Use the specified object (e.g. `USE foo.bar`).
259    Object(ObjectName),
260    /// Reset to default (e.g. `USE DEFAULT`).
261    Default,
262}
263
264impl fmt::Display for Use {
265    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
266        f.write_str("USE ")?;
267        match self {
268            Use::Catalog(name) => write!(f, "CATALOG {name}"),
269            Use::Schema(name) => write!(f, "SCHEMA {name}"),
270            Use::Database(name) => write!(f, "DATABASE {name}"),
271            Use::Warehouse(name) => write!(f, "WAREHOUSE {name}"),
272            Use::Role(name) => write!(f, "ROLE {name}"),
273            Use::SecondaryRoles(secondary_roles) => {
274                write!(f, "SECONDARY ROLES {secondary_roles}")
275            }
276            Use::Object(name) => write!(f, "{name}"),
277            Use::Default => write!(f, "DEFAULT"),
278        }
279    }
280}
281
282/// Snowflake `SECONDARY ROLES` USE variant
283/// See: <https://docs.snowflake.com/en/sql-reference/sql/use-secondary-roles>
284#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
285#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
286#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
287pub enum SecondaryRoles {
288    /// Use all secondary roles.
289    All,
290    /// Use no secondary roles.
291    None,
292    /// Explicit list of secondary roles.
293    List(Vec<Ident>),
294}
295
296impl fmt::Display for SecondaryRoles {
297    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
298        match self {
299            SecondaryRoles::All => write!(f, "ALL"),
300            SecondaryRoles::None => write!(f, "NONE"),
301            SecondaryRoles::List(roles) => write!(f, "{}", display_comma_separated(roles)),
302        }
303    }
304}
305
306/// CREATE ROLE statement
307/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createrole.html)
308#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
309#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
310#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
311pub struct CreateRole {
312    /// Role names to create.
313    pub names: Vec<ObjectName>,
314    /// Whether `IF NOT EXISTS` was specified.
315    pub if_not_exists: bool,
316    // Postgres
317    /// Whether `LOGIN` was specified.
318    pub login: Option<bool>,
319    /// Whether `INHERIT` was specified.
320    pub inherit: Option<bool>,
321    /// Whether `BYPASSRLS` was specified.
322    pub bypassrls: Option<bool>,
323    /// Optional password for the role.
324    pub password: Option<Password>,
325    /// Whether `SUPERUSER` was specified.
326    pub superuser: Option<bool>,
327    /// Whether `CREATEDB` was specified.
328    pub create_db: Option<bool>,
329    /// Whether `CREATEROLE` was specified.
330    pub create_role: Option<bool>,
331    /// Whether `REPLICATION` privilege was specified.
332    pub replication: Option<bool>,
333    /// Optional connection limit expression.
334    pub connection_limit: Option<Expr>,
335    /// Optional account validity expression.
336    pub valid_until: Option<Expr>,
337    /// Members of `IN ROLE` clause.
338    pub in_role: Vec<Ident>,
339    /// Members of `IN GROUP` clause.
340    pub in_group: Vec<Ident>,
341    /// Roles listed in `ROLE` clause.
342    pub role: Vec<Ident>,
343    /// Users listed in `USER` clause.
344    pub user: Vec<Ident>,
345    /// Admin users listed in `ADMIN` clause.
346    pub admin: Vec<Ident>,
347    // MSSQL
348    /// Optional authorization owner.
349    pub authorization_owner: Option<ObjectName>,
350}
351
352impl fmt::Display for CreateRole {
353    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
354        write!(
355            f,
356            "CREATE ROLE {if_not_exists}{names}{superuser}{create_db}{create_role}{inherit}{login}{replication}{bypassrls}",
357            if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
358            names = display_separated(&self.names, ", "),
359            superuser = match self.superuser {
360                Some(true) => " SUPERUSER",
361                Some(false) => " NOSUPERUSER",
362                None => ""
363            },
364            create_db = match self.create_db {
365                Some(true) => " CREATEDB",
366                Some(false) => " NOCREATEDB",
367                None => ""
368            },
369            create_role = match self.create_role {
370                Some(true) => " CREATEROLE",
371                Some(false) => " NOCREATEROLE",
372                None => ""
373            },
374            inherit = match self.inherit {
375                Some(true) => " INHERIT",
376                Some(false) => " NOINHERIT",
377                None => ""
378            },
379            login = match self.login {
380                Some(true) => " LOGIN",
381                Some(false) => " NOLOGIN",
382                None => ""
383            },
384            replication = match self.replication {
385                Some(true) => " REPLICATION",
386                Some(false) => " NOREPLICATION",
387                None => ""
388            },
389            bypassrls = match self.bypassrls {
390                Some(true) => " BYPASSRLS",
391                Some(false) => " NOBYPASSRLS",
392                None => ""
393            }
394        )?;
395        if let Some(limit) = &self.connection_limit {
396            write!(f, " CONNECTION LIMIT {limit}")?;
397        }
398        match &self.password {
399            Some(Password::Password(pass)) => write!(f, " PASSWORD {pass}")?,
400            Some(Password::NullPassword) => write!(f, " PASSWORD NULL")?,
401            None => {}
402        };
403        if let Some(until) = &self.valid_until {
404            write!(f, " VALID UNTIL {until}")?;
405        }
406        if !self.in_role.is_empty() {
407            write!(f, " IN ROLE {}", display_comma_separated(&self.in_role))?;
408        }
409        if !self.in_group.is_empty() {
410            write!(f, " IN GROUP {}", display_comma_separated(&self.in_group))?;
411        }
412        if !self.role.is_empty() {
413            write!(f, " ROLE {}", display_comma_separated(&self.role))?;
414        }
415        if !self.user.is_empty() {
416            write!(f, " USER {}", display_comma_separated(&self.user))?;
417        }
418        if !self.admin.is_empty() {
419            write!(f, " ADMIN {}", display_comma_separated(&self.admin))?;
420        }
421        if let Some(owner) = &self.authorization_owner {
422            write!(f, " AUTHORIZATION {owner}")?;
423        }
424        Ok(())
425    }
426}
427
428impl Spanned for CreateRole {
429    fn span(&self) -> Span {
430        Span::empty()
431    }
432}
433
434/// GRANT privileges ON objects TO grantees
435#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
436#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
437#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
438pub struct Grant {
439    /// Privileges being granted.
440    pub privileges: Privileges,
441    /// Optional objects the privileges apply to.
442    pub objects: Option<GrantObjects>,
443    /// List of grantees receiving the privileges.
444    pub grantees: Vec<Grantee>,
445    /// Whether `WITH GRANT OPTION` is present.
446    pub with_grant_option: bool,
447    /// Optional `AS GRANTOR` identifier.
448    pub as_grantor: Option<Ident>,
449    /// Optional `GRANTED BY` identifier.
450    ///
451    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/dcl-statements)
452    pub granted_by: Option<Ident>,
453    /// Optional `CURRENT GRANTS` modifier.
454    ///
455    /// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/grant-privilege)
456    pub current_grants: Option<CurrentGrantsKind>,
457}
458
459impl fmt::Display for Grant {
460    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
461        write!(f, "GRANT {privileges}", privileges = self.privileges)?;
462        if let Some(ref objects) = self.objects {
463            write!(f, " ON {objects}")?;
464        }
465        write!(f, " TO {}", display_comma_separated(&self.grantees))?;
466        if let Some(ref current_grants) = self.current_grants {
467            write!(f, " {current_grants}")?;
468        }
469        if self.with_grant_option {
470            write!(f, " WITH GRANT OPTION")?;
471        }
472        if let Some(ref as_grantor) = self.as_grantor {
473            write!(f, " AS {as_grantor}")?;
474        }
475        if let Some(ref granted_by) = self.granted_by {
476            write!(f, " GRANTED BY {granted_by}")?;
477        }
478        Ok(())
479    }
480}
481
482impl From<Grant> for crate::ast::Statement {
483    fn from(v: Grant) -> Self {
484        crate::ast::Statement::Grant(v)
485    }
486}
487
488/// REVOKE privileges ON objects FROM grantees
489#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
490#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
491#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
492pub struct Revoke {
493    /// Privileges to revoke.
494    pub privileges: Privileges,
495    /// Optional objects from which to revoke.
496    pub objects: Option<GrantObjects>,
497    /// Grantees affected by the revoke.
498    pub grantees: Vec<Grantee>,
499    /// Optional `GRANTED BY` identifier.
500    ///
501    /// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/dcl-statements)
502    pub granted_by: Option<Ident>,
503    /// Optional `CASCADE`/`RESTRICT` behavior.
504    pub cascade: Option<CascadeOption>,
505}
506
507impl fmt::Display for Revoke {
508    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
509        write!(f, "REVOKE {privileges}", privileges = self.privileges)?;
510        if let Some(ref objects) = self.objects {
511            write!(f, " ON {objects}")?;
512        }
513        write!(f, " FROM {}", display_comma_separated(&self.grantees))?;
514        if let Some(ref granted_by) = self.granted_by {
515            write!(f, " GRANTED BY {granted_by}")?;
516        }
517        if let Some(ref cascade) = self.cascade {
518            write!(f, " {cascade}")?;
519        }
520        Ok(())
521    }
522}
523
524impl From<Revoke> for crate::ast::Statement {
525    fn from(v: Revoke) -> Self {
526        crate::ast::Statement::Revoke(v)
527    }
528}