sqlparser/ast/
dcl.rs1// 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}