blob: 3c50a81c0681a80a02e2786fb919354c6564af7d [file]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//! AST types specific to GRANT/REVOKE/ROLE variants of [`Statement`](crate::ast::Statement)
//! (commonly referred to as Data Control Language, or DCL)
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::fmt;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
#[cfg(feature = "visitor")]
use sqlparser_derive::{Visit, VisitMut};
use super::{display_comma_separated, Expr, Ident, Password, Spanned};
use crate::ast::{
display_separated, CascadeOption, CurrentGrantsKind, GrantObjects, Grantee, ObjectName,
Privileges,
};
use crate::tokenizer::Span;
/// An option in `ROLE` statement.
///
/// <https://www.postgresql.org/docs/current/sql-createrole.html>
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum RoleOption {
/// Enable or disable BYPASSRLS.
BypassRLS(bool),
/// Connection limit expression.
ConnectionLimit(Expr),
/// CREATEDB flag.
CreateDB(bool),
/// CREATEROLE flag.
CreateRole(bool),
/// INHERIT flag.
Inherit(bool),
/// LOGIN flag.
Login(bool),
/// Password value or NULL password.
Password(Password),
/// Replication privilege flag.
Replication(bool),
/// SUPERUSER flag.
SuperUser(bool),
/// `VALID UNTIL` expression.
ValidUntil(Expr),
}
impl fmt::Display for RoleOption {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
RoleOption::BypassRLS(value) => {
write!(f, "{}", if *value { "BYPASSRLS" } else { "NOBYPASSRLS" })
}
RoleOption::ConnectionLimit(expr) => {
write!(f, "CONNECTION LIMIT {expr}")
}
RoleOption::CreateDB(value) => {
write!(f, "{}", if *value { "CREATEDB" } else { "NOCREATEDB" })
}
RoleOption::CreateRole(value) => {
write!(f, "{}", if *value { "CREATEROLE" } else { "NOCREATEROLE" })
}
RoleOption::Inherit(value) => {
write!(f, "{}", if *value { "INHERIT" } else { "NOINHERIT" })
}
RoleOption::Login(value) => {
write!(f, "{}", if *value { "LOGIN" } else { "NOLOGIN" })
}
RoleOption::Password(password) => match password {
Password::Password(expr) => write!(f, "PASSWORD {expr}"),
Password::NullPassword => write!(f, "PASSWORD NULL"),
},
RoleOption::Replication(value) => {
write!(
f,
"{}",
if *value {
"REPLICATION"
} else {
"NOREPLICATION"
}
)
}
RoleOption::SuperUser(value) => {
write!(f, "{}", if *value { "SUPERUSER" } else { "NOSUPERUSER" })
}
RoleOption::ValidUntil(expr) => {
write!(f, "VALID UNTIL {expr}")
}
}
}
}
/// SET config value option:
/// * SET `configuration_parameter` { TO | = } { `value` | DEFAULT }
/// * SET `configuration_parameter` FROM CURRENT
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum SetConfigValue {
/// Use the default value.
Default,
/// Use the current value (`FROM CURRENT`).
FromCurrent,
/// Set to the provided expression value.
Value(Expr),
}
/// RESET config option:
/// * RESET `configuration_parameter`
/// * RESET ALL
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum ResetConfig {
/// Reset all configuration parameters.
ALL,
/// Reset the named configuration parameter.
ConfigName(ObjectName),
}
/// An `ALTER ROLE` (`Statement::AlterRole`) operation
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum AlterRoleOperation {
/// Generic
RenameRole {
/// Role name to rename.
role_name: Ident,
},
/// MS SQL Server
/// <https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-role-transact-sql>
AddMember {
/// Member name to add to the role.
member_name: Ident,
},
/// MS SQL Server
///
/// <https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-role-transact-sql>
DropMember {
/// Member name to remove from the role.
member_name: Ident,
},
/// PostgreSQL
/// <https://www.postgresql.org/docs/current/sql-alterrole.html>
WithOptions {
/// Role options to apply.
options: Vec<RoleOption>,
},
/// PostgreSQL
/// <https://www.postgresql.org/docs/current/sql-alterrole.html>
///
/// `SET configuration_parameter { TO | = } { value | DEFAULT }`
Set {
/// Configuration name to set.
config_name: ObjectName,
/// Value to assign to the configuration.
config_value: SetConfigValue,
/// Optional database scope for the setting.
in_database: Option<ObjectName>,
},
/// PostgreSQL
/// <https://www.postgresql.org/docs/current/sql-alterrole.html>
///
/// `RESET configuration_parameter` | `RESET ALL`
Reset {
/// Configuration to reset.
config_name: ResetConfig,
/// Optional database scope for the reset.
in_database: Option<ObjectName>,
},
}
impl fmt::Display for AlterRoleOperation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
AlterRoleOperation::RenameRole { role_name } => {
write!(f, "RENAME TO {role_name}")
}
AlterRoleOperation::AddMember { member_name } => {
write!(f, "ADD MEMBER {member_name}")
}
AlterRoleOperation::DropMember { member_name } => {
write!(f, "DROP MEMBER {member_name}")
}
AlterRoleOperation::WithOptions { options } => {
write!(f, "WITH {}", display_separated(options, " "))
}
AlterRoleOperation::Set {
config_name,
config_value,
in_database,
} => {
if let Some(database_name) = in_database {
write!(f, "IN DATABASE {database_name} ")?;
}
match config_value {
SetConfigValue::Default => write!(f, "SET {config_name} TO DEFAULT"),
SetConfigValue::FromCurrent => write!(f, "SET {config_name} FROM CURRENT"),
SetConfigValue::Value(expr) => write!(f, "SET {config_name} TO {expr}"),
}
}
AlterRoleOperation::Reset {
config_name,
in_database,
} => {
if let Some(database_name) = in_database {
write!(f, "IN DATABASE {database_name} ")?;
}
match config_name {
ResetConfig::ALL => write!(f, "RESET ALL"),
ResetConfig::ConfigName(name) => write!(f, "RESET {name}"),
}
}
}
}
}
/// A `USE` (`Statement::Use`) operation
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum Use {
/// Switch to the given catalog (e.g. `USE CATALOG ...`).
Catalog(ObjectName),
/// Switch to the given schema (e.g. `USE SCHEMA ...`).
Schema(ObjectName),
/// Switch to the given database (e.g. `USE DATABASE ...`).
Database(ObjectName),
/// Switch to the given warehouse (e.g. `USE WAREHOUSE ...`).
Warehouse(ObjectName),
/// Switch to the given role (e.g. `USE ROLE ...`).
Role(ObjectName),
/// Use secondary roles specification (e.g. `USE SECONDARY ROLES ...`).
SecondaryRoles(SecondaryRoles),
/// Use the specified object (e.g. `USE foo.bar`).
Object(ObjectName),
/// Reset to default (e.g. `USE DEFAULT`).
Default,
}
impl fmt::Display for Use {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("USE ")?;
match self {
Use::Catalog(name) => write!(f, "CATALOG {name}"),
Use::Schema(name) => write!(f, "SCHEMA {name}"),
Use::Database(name) => write!(f, "DATABASE {name}"),
Use::Warehouse(name) => write!(f, "WAREHOUSE {name}"),
Use::Role(name) => write!(f, "ROLE {name}"),
Use::SecondaryRoles(secondary_roles) => {
write!(f, "SECONDARY ROLES {secondary_roles}")
}
Use::Object(name) => write!(f, "{name}"),
Use::Default => write!(f, "DEFAULT"),
}
}
}
/// Snowflake `SECONDARY ROLES` USE variant
/// See: <https://docs.snowflake.com/en/sql-reference/sql/use-secondary-roles>
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub enum SecondaryRoles {
/// Use all secondary roles.
All,
/// Use no secondary roles.
None,
/// Explicit list of secondary roles.
List(Vec<Ident>),
}
impl fmt::Display for SecondaryRoles {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
SecondaryRoles::All => write!(f, "ALL"),
SecondaryRoles::None => write!(f, "NONE"),
SecondaryRoles::List(roles) => write!(f, "{}", display_comma_separated(roles)),
}
}
}
/// CREATE ROLE statement
/// See [PostgreSQL](https://www.postgresql.org/docs/current/sql-createrole.html)
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct CreateRole {
/// Role names to create.
pub names: Vec<ObjectName>,
/// Whether `IF NOT EXISTS` was specified.
pub if_not_exists: bool,
// Postgres
/// Whether `LOGIN` was specified.
pub login: Option<bool>,
/// Whether `INHERIT` was specified.
pub inherit: Option<bool>,
/// Whether `BYPASSRLS` was specified.
pub bypassrls: Option<bool>,
/// Optional password for the role.
pub password: Option<Password>,
/// Whether `SUPERUSER` was specified.
pub superuser: Option<bool>,
/// Whether `CREATEDB` was specified.
pub create_db: Option<bool>,
/// Whether `CREATEROLE` was specified.
pub create_role: Option<bool>,
/// Whether `REPLICATION` privilege was specified.
pub replication: Option<bool>,
/// Optional connection limit expression.
pub connection_limit: Option<Expr>,
/// Optional account validity expression.
pub valid_until: Option<Expr>,
/// Members of `IN ROLE` clause.
pub in_role: Vec<Ident>,
/// Members of `IN GROUP` clause.
pub in_group: Vec<Ident>,
/// Roles listed in `ROLE` clause.
pub role: Vec<Ident>,
/// Users listed in `USER` clause.
pub user: Vec<Ident>,
/// Admin users listed in `ADMIN` clause.
pub admin: Vec<Ident>,
// MSSQL
/// Optional authorization owner.
pub authorization_owner: Option<ObjectName>,
}
impl fmt::Display for CreateRole {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(
f,
"CREATE ROLE {if_not_exists}{names}{superuser}{create_db}{create_role}{inherit}{login}{replication}{bypassrls}",
if_not_exists = if self.if_not_exists { "IF NOT EXISTS " } else { "" },
names = display_separated(&self.names, ", "),
superuser = match self.superuser {
Some(true) => " SUPERUSER",
Some(false) => " NOSUPERUSER",
None => ""
},
create_db = match self.create_db {
Some(true) => " CREATEDB",
Some(false) => " NOCREATEDB",
None => ""
},
create_role = match self.create_role {
Some(true) => " CREATEROLE",
Some(false) => " NOCREATEROLE",
None => ""
},
inherit = match self.inherit {
Some(true) => " INHERIT",
Some(false) => " NOINHERIT",
None => ""
},
login = match self.login {
Some(true) => " LOGIN",
Some(false) => " NOLOGIN",
None => ""
},
replication = match self.replication {
Some(true) => " REPLICATION",
Some(false) => " NOREPLICATION",
None => ""
},
bypassrls = match self.bypassrls {
Some(true) => " BYPASSRLS",
Some(false) => " NOBYPASSRLS",
None => ""
}
)?;
if let Some(limit) = &self.connection_limit {
write!(f, " CONNECTION LIMIT {limit}")?;
}
match &self.password {
Some(Password::Password(pass)) => write!(f, " PASSWORD {pass}")?,
Some(Password::NullPassword) => write!(f, " PASSWORD NULL")?,
None => {}
};
if let Some(until) = &self.valid_until {
write!(f, " VALID UNTIL {until}")?;
}
if !self.in_role.is_empty() {
write!(f, " IN ROLE {}", display_comma_separated(&self.in_role))?;
}
if !self.in_group.is_empty() {
write!(f, " IN GROUP {}", display_comma_separated(&self.in_group))?;
}
if !self.role.is_empty() {
write!(f, " ROLE {}", display_comma_separated(&self.role))?;
}
if !self.user.is_empty() {
write!(f, " USER {}", display_comma_separated(&self.user))?;
}
if !self.admin.is_empty() {
write!(f, " ADMIN {}", display_comma_separated(&self.admin))?;
}
if let Some(owner) = &self.authorization_owner {
write!(f, " AUTHORIZATION {owner}")?;
}
Ok(())
}
}
impl Spanned for CreateRole {
fn span(&self) -> Span {
Span::empty()
}
}
/// GRANT privileges ON objects TO grantees
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Grant {
/// Privileges being granted.
pub privileges: Privileges,
/// Optional objects the privileges apply to.
pub objects: Option<GrantObjects>,
/// List of grantees receiving the privileges.
pub grantees: Vec<Grantee>,
/// Whether `WITH GRANT OPTION` is present.
pub with_grant_option: bool,
/// Optional `AS GRANTOR` identifier.
pub as_grantor: Option<Ident>,
/// Optional `GRANTED BY` identifier.
///
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/dcl-statements)
pub granted_by: Option<Ident>,
/// Optional `CURRENT GRANTS` modifier.
///
/// [Snowflake](https://docs.snowflake.com/en/sql-reference/sql/grant-privilege)
pub current_grants: Option<CurrentGrantsKind>,
}
impl fmt::Display for Grant {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "GRANT {privileges}", privileges = self.privileges)?;
if let Some(ref objects) = self.objects {
write!(f, " ON {objects}")?;
}
write!(f, " TO {}", display_comma_separated(&self.grantees))?;
if let Some(ref current_grants) = self.current_grants {
write!(f, " {current_grants}")?;
}
if self.with_grant_option {
write!(f, " WITH GRANT OPTION")?;
}
if let Some(ref as_grantor) = self.as_grantor {
write!(f, " AS {as_grantor}")?;
}
if let Some(ref granted_by) = self.granted_by {
write!(f, " GRANTED BY {granted_by}")?;
}
Ok(())
}
}
impl From<Grant> for crate::ast::Statement {
fn from(v: Grant) -> Self {
crate::ast::Statement::Grant(v)
}
}
/// REVOKE privileges ON objects FROM grantees
#[derive(Debug, Clone, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(feature = "visitor", derive(Visit, VisitMut))]
pub struct Revoke {
/// Privileges to revoke.
pub privileges: Privileges,
/// Optional objects from which to revoke.
pub objects: Option<GrantObjects>,
/// Grantees affected by the revoke.
pub grantees: Vec<Grantee>,
/// Optional `GRANTED BY` identifier.
///
/// [BigQuery](https://cloud.google.com/bigquery/docs/reference/standard-sql/dcl-statements)
pub granted_by: Option<Ident>,
/// Optional `CASCADE`/`RESTRICT` behavior.
pub cascade: Option<CascadeOption>,
}
impl fmt::Display for Revoke {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "REVOKE {privileges}", privileges = self.privileges)?;
if let Some(ref objects) = self.objects {
write!(f, " ON {objects}")?;
}
write!(f, " FROM {}", display_comma_separated(&self.grantees))?;
if let Some(ref granted_by) = self.granted_by {
write!(f, " GRANTED BY {granted_by}")?;
}
if let Some(ref cascade) = self.cascade {
write!(f, " {cascade}")?;
}
Ok(())
}
}
impl From<Revoke> for crate::ast::Statement {
fn from(v: Revoke) -> Self {
crate::ast::Statement::Revoke(v)
}
}