mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-08-04 06:18:17 +00:00
feat: add ALTER ROLE
syntax of PostgreSQL and MS SQL Server (#942)
This commit is contained in:
parent
a7d28582e5
commit
a49ea1908d
7 changed files with 666 additions and 2 deletions
195
src/ast/dcl.rs
Normal file
195
src/ast/dcl.rs
Normal file
|
@ -0,0 +1,195 @@
|
|||
// Licensed 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::{Expr, Ident, Password};
|
||||
use crate::ast::{display_separated, ObjectName};
|
||||
|
||||
/// 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 {
|
||||
BypassRLS(bool),
|
||||
ConnectionLimit(Expr),
|
||||
CreateDB(bool),
|
||||
CreateRole(bool),
|
||||
Inherit(bool),
|
||||
Login(bool),
|
||||
Password(Password),
|
||||
Replication(bool),
|
||||
SuperUser(bool),
|
||||
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 {
|
||||
Default,
|
||||
FromCurrent,
|
||||
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 {
|
||||
ALL,
|
||||
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: Ident,
|
||||
},
|
||||
/// MS SQL Server
|
||||
/// <https://learn.microsoft.com/en-us/sql/t-sql/statements/alter-role-transact-sql>
|
||||
AddMember {
|
||||
member_name: Ident,
|
||||
},
|
||||
DropMember {
|
||||
member_name: Ident,
|
||||
},
|
||||
/// PostgreSQL
|
||||
/// <https://www.postgresql.org/docs/current/sql-alterrole.html>
|
||||
WithOptions {
|
||||
options: Vec<RoleOption>,
|
||||
},
|
||||
Set {
|
||||
config_name: ObjectName,
|
||||
config_value: SetConfigValue,
|
||||
in_database: Option<ObjectName>,
|
||||
},
|
||||
Reset {
|
||||
config_name: ResetConfig,
|
||||
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}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ use sqlparser_derive::{Visit, VisitMut};
|
|||
pub use self::data_type::{
|
||||
CharLengthUnits, CharacterLength, DataType, ExactNumberInfo, TimezoneInfo,
|
||||
};
|
||||
pub use self::dcl::{AlterRoleOperation, ResetConfig, RoleOption, SetConfigValue};
|
||||
pub use self::ddl::{
|
||||
AlterColumnOperation, AlterIndexOperation, AlterTableOperation, ColumnDef, ColumnOption,
|
||||
ColumnOptionDef, GeneratedAs, IndexType, KeyOrIndexDisplay, ProcedureParam, ReferentialAction,
|
||||
|
@ -52,6 +53,7 @@ use crate::ast::helpers::stmt_data_loading::{
|
|||
pub use visitor::*;
|
||||
|
||||
mod data_type;
|
||||
mod dcl;
|
||||
mod ddl;
|
||||
pub mod helpers;
|
||||
mod operator;
|
||||
|
@ -1398,6 +1400,11 @@ pub enum Statement {
|
|||
query: Box<Query>,
|
||||
with_options: Vec<SqlOption>,
|
||||
},
|
||||
/// ALTER ROLE
|
||||
AlterRole {
|
||||
name: Ident,
|
||||
operation: AlterRoleOperation,
|
||||
},
|
||||
/// DROP
|
||||
Drop {
|
||||
/// The type of the object to drop: TABLE, VIEW, etc.
|
||||
|
@ -2585,6 +2592,9 @@ impl fmt::Display for Statement {
|
|||
}
|
||||
write!(f, " AS {query}")
|
||||
}
|
||||
Statement::AlterRole { name, operation } => {
|
||||
write!(f, "ALTER ROLE {name} {operation}")
|
||||
}
|
||||
Statement::Drop {
|
||||
object_type,
|
||||
if_exists,
|
||||
|
|
|
@ -508,6 +508,7 @@ define_keywords!(
|
|||
REPEATABLE,
|
||||
REPLACE,
|
||||
REPLICATION,
|
||||
RESET,
|
||||
RESTRICT,
|
||||
RESULT,
|
||||
RETAIN,
|
||||
|
|
204
src/parser/alter.rs
Normal file
204
src/parser/alter.rs
Normal file
|
@ -0,0 +1,204 @@
|
|||
// Licensed 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.
|
||||
|
||||
//! SQL Parser for ALTER
|
||||
|
||||
#[cfg(not(feature = "std"))]
|
||||
use alloc::vec;
|
||||
|
||||
use super::{Parser, ParserError};
|
||||
use crate::{
|
||||
ast::{AlterRoleOperation, Expr, Password, ResetConfig, RoleOption, SetConfigValue, Statement},
|
||||
dialect::{MsSqlDialect, PostgreSqlDialect},
|
||||
keywords::Keyword,
|
||||
tokenizer::Token,
|
||||
};
|
||||
|
||||
impl<'a> Parser<'a> {
|
||||
pub fn parse_alter_role(&mut self) -> Result<Statement, ParserError> {
|
||||
if dialect_of!(self is PostgreSqlDialect) {
|
||||
return self.parse_pg_alter_role();
|
||||
} else if dialect_of!(self is MsSqlDialect) {
|
||||
return self.parse_mssql_alter_role();
|
||||
}
|
||||
|
||||
Err(ParserError::ParserError(
|
||||
"ALTER ROLE is only support for PostgreSqlDialect, MsSqlDialect".into(),
|
||||
))
|
||||
}
|
||||
|
||||
fn parse_mssql_alter_role(&mut self) -> Result<Statement, ParserError> {
|
||||
let role_name = self.parse_identifier()?;
|
||||
|
||||
let operation = if self.parse_keywords(&[Keyword::ADD, Keyword::MEMBER]) {
|
||||
let member_name = self.parse_identifier()?;
|
||||
AlterRoleOperation::AddMember { member_name }
|
||||
} else if self.parse_keywords(&[Keyword::DROP, Keyword::MEMBER]) {
|
||||
let member_name = self.parse_identifier()?;
|
||||
AlterRoleOperation::DropMember { member_name }
|
||||
} else if self.parse_keywords(&[Keyword::WITH, Keyword::NAME]) {
|
||||
if self.consume_token(&Token::Eq) {
|
||||
let role_name = self.parse_identifier()?;
|
||||
AlterRoleOperation::RenameRole { role_name }
|
||||
} else {
|
||||
return self.expected("= after WITH NAME ", self.peek_token());
|
||||
}
|
||||
} else {
|
||||
return self.expected("'ADD' or 'DROP' or 'WITH NAME'", self.peek_token());
|
||||
};
|
||||
|
||||
Ok(Statement::AlterRole {
|
||||
name: role_name,
|
||||
operation,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_pg_alter_role(&mut self) -> Result<Statement, ParserError> {
|
||||
let role_name = self.parse_identifier()?;
|
||||
|
||||
// [ IN DATABASE _`database_name`_ ]
|
||||
let in_database = if self.parse_keywords(&[Keyword::IN, Keyword::DATABASE]) {
|
||||
self.parse_object_name().ok()
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let operation = if self.parse_keyword(Keyword::RENAME) {
|
||||
if self.parse_keyword(Keyword::TO) {
|
||||
let role_name = self.parse_identifier()?;
|
||||
AlterRoleOperation::RenameRole { role_name }
|
||||
} else {
|
||||
return self.expected("TO after RENAME", self.peek_token());
|
||||
}
|
||||
// SET
|
||||
} else if self.parse_keyword(Keyword::SET) {
|
||||
let config_name = self.parse_object_name()?;
|
||||
// FROM CURRENT
|
||||
if self.parse_keywords(&[Keyword::FROM, Keyword::CURRENT]) {
|
||||
AlterRoleOperation::Set {
|
||||
config_name,
|
||||
config_value: SetConfigValue::FromCurrent,
|
||||
in_database,
|
||||
}
|
||||
// { TO | = } { value | DEFAULT }
|
||||
} else if self.consume_token(&Token::Eq) || self.parse_keyword(Keyword::TO) {
|
||||
if self.parse_keyword(Keyword::DEFAULT) {
|
||||
AlterRoleOperation::Set {
|
||||
config_name,
|
||||
config_value: SetConfigValue::Default,
|
||||
in_database,
|
||||
}
|
||||
} else if let Ok(expr) = self.parse_expr() {
|
||||
AlterRoleOperation::Set {
|
||||
config_name,
|
||||
config_value: SetConfigValue::Value(expr),
|
||||
in_database,
|
||||
}
|
||||
} else {
|
||||
self.expected("config value", self.peek_token())?
|
||||
}
|
||||
} else {
|
||||
self.expected("'TO' or '=' or 'FROM CURRENT'", self.peek_token())?
|
||||
}
|
||||
// RESET
|
||||
} else if self.parse_keyword(Keyword::RESET) {
|
||||
if self.parse_keyword(Keyword::ALL) {
|
||||
AlterRoleOperation::Reset {
|
||||
config_name: ResetConfig::ALL,
|
||||
in_database,
|
||||
}
|
||||
} else {
|
||||
let config_name = self.parse_object_name()?;
|
||||
AlterRoleOperation::Reset {
|
||||
config_name: ResetConfig::ConfigName(config_name),
|
||||
in_database,
|
||||
}
|
||||
}
|
||||
// option
|
||||
} else {
|
||||
// [ WITH ]
|
||||
let _ = self.parse_keyword(Keyword::WITH);
|
||||
// option
|
||||
let mut options = vec![];
|
||||
while let Some(opt) = self.maybe_parse(|parser| parser.parse_pg_role_option()) {
|
||||
options.push(opt);
|
||||
}
|
||||
// check option
|
||||
if options.is_empty() {
|
||||
return self.expected("option", self.peek_token())?;
|
||||
}
|
||||
|
||||
AlterRoleOperation::WithOptions { options }
|
||||
};
|
||||
|
||||
Ok(Statement::AlterRole {
|
||||
name: role_name,
|
||||
operation,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_pg_role_option(&mut self) -> Result<RoleOption, ParserError> {
|
||||
let option = match self.parse_one_of_keywords(&[
|
||||
Keyword::BYPASSRLS,
|
||||
Keyword::NOBYPASSRLS,
|
||||
Keyword::CONNECTION,
|
||||
Keyword::CREATEDB,
|
||||
Keyword::NOCREATEDB,
|
||||
Keyword::CREATEROLE,
|
||||
Keyword::NOCREATEROLE,
|
||||
Keyword::INHERIT,
|
||||
Keyword::NOINHERIT,
|
||||
Keyword::LOGIN,
|
||||
Keyword::NOLOGIN,
|
||||
Keyword::PASSWORD,
|
||||
Keyword::REPLICATION,
|
||||
Keyword::NOREPLICATION,
|
||||
Keyword::SUPERUSER,
|
||||
Keyword::NOSUPERUSER,
|
||||
Keyword::VALID,
|
||||
]) {
|
||||
Some(Keyword::BYPASSRLS) => RoleOption::BypassRLS(true),
|
||||
Some(Keyword::NOBYPASSRLS) => RoleOption::BypassRLS(false),
|
||||
Some(Keyword::CONNECTION) => {
|
||||
self.expect_keyword(Keyword::LIMIT)?;
|
||||
RoleOption::ConnectionLimit(Expr::Value(self.parse_number_value()?))
|
||||
}
|
||||
Some(Keyword::CREATEDB) => RoleOption::CreateDB(true),
|
||||
Some(Keyword::NOCREATEDB) => RoleOption::CreateDB(false),
|
||||
Some(Keyword::CREATEROLE) => RoleOption::CreateRole(true),
|
||||
Some(Keyword::NOCREATEROLE) => RoleOption::CreateRole(false),
|
||||
Some(Keyword::INHERIT) => RoleOption::Inherit(true),
|
||||
Some(Keyword::NOINHERIT) => RoleOption::Inherit(false),
|
||||
Some(Keyword::LOGIN) => RoleOption::Login(true),
|
||||
Some(Keyword::NOLOGIN) => RoleOption::Login(false),
|
||||
Some(Keyword::PASSWORD) => {
|
||||
let password = if self.parse_keyword(Keyword::NULL) {
|
||||
Password::NullPassword
|
||||
} else {
|
||||
Password::Password(Expr::Value(self.parse_value()?))
|
||||
};
|
||||
RoleOption::Password(password)
|
||||
}
|
||||
Some(Keyword::REPLICATION) => RoleOption::Replication(true),
|
||||
Some(Keyword::NOREPLICATION) => RoleOption::Replication(false),
|
||||
Some(Keyword::SUPERUSER) => RoleOption::SuperUser(true),
|
||||
Some(Keyword::NOSUPERUSER) => RoleOption::SuperUser(false),
|
||||
Some(Keyword::VALID) => {
|
||||
self.expect_keyword(Keyword::UNTIL)?;
|
||||
RoleOption::ValidUntil(Expr::Value(self.parse_value()?))
|
||||
}
|
||||
_ => self.expected("option", self.peek_token())?,
|
||||
};
|
||||
|
||||
Ok(option)
|
||||
}
|
||||
}
|
|
@ -33,6 +33,8 @@ use crate::dialect::*;
|
|||
use crate::keywords::{self, Keyword};
|
||||
use crate::tokenizer::*;
|
||||
|
||||
mod alter;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum ParserError {
|
||||
TokenizerError(String),
|
||||
|
@ -3990,8 +3992,12 @@ impl<'a> Parser<'a> {
|
|||
}
|
||||
|
||||
pub fn parse_alter(&mut self) -> Result<Statement, ParserError> {
|
||||
let object_type =
|
||||
self.expect_one_of_keywords(&[Keyword::VIEW, Keyword::TABLE, Keyword::INDEX])?;
|
||||
let object_type = self.expect_one_of_keywords(&[
|
||||
Keyword::VIEW,
|
||||
Keyword::TABLE,
|
||||
Keyword::INDEX,
|
||||
Keyword::ROLE,
|
||||
])?;
|
||||
match object_type {
|
||||
Keyword::VIEW => self.parse_alter_view(),
|
||||
Keyword::TABLE => {
|
||||
|
@ -4186,6 +4192,7 @@ impl<'a> Parser<'a> {
|
|||
operation,
|
||||
})
|
||||
}
|
||||
Keyword::ROLE => self.parse_alter_role(),
|
||||
// unreachable because expect_one_of_keywords used above
|
||||
_ => unreachable!(),
|
||||
}
|
|
@ -216,6 +216,60 @@ fn parse_mssql_create_role() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_alter_role() {
|
||||
let sql = "ALTER ROLE old_name WITH NAME = new_name";
|
||||
assert_eq!(
|
||||
ms().parse_sql_statements(sql).unwrap(),
|
||||
[Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "old_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::RenameRole {
|
||||
role_name: Ident {
|
||||
value: "new_name".into(),
|
||||
quote_style: None
|
||||
}
|
||||
},
|
||||
}]
|
||||
);
|
||||
|
||||
let sql = "ALTER ROLE role_name ADD MEMBER new_member";
|
||||
assert_eq!(
|
||||
ms().verified_stmt(sql),
|
||||
Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "role_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::AddMember {
|
||||
member_name: Ident {
|
||||
value: "new_member".into(),
|
||||
quote_style: None
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let sql = "ALTER ROLE role_name DROP MEMBER old_member";
|
||||
assert_eq!(
|
||||
ms().verified_stmt(sql),
|
||||
Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "role_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::DropMember {
|
||||
member_name: Ident {
|
||||
value: "old_member".into(),
|
||||
quote_style: None
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_delimited_identifiers() {
|
||||
// check that quoted identifiers in any position remain quoted after serialization
|
||||
|
|
|
@ -2447,6 +2447,199 @@ fn parse_create_role() {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_alter_role() {
|
||||
let sql = "ALTER ROLE old_name RENAME TO new_name";
|
||||
assert_eq!(
|
||||
pg().verified_stmt(sql),
|
||||
Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "old_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::RenameRole {
|
||||
role_name: Ident {
|
||||
value: "new_name".into(),
|
||||
quote_style: None
|
||||
}
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let sql = "ALTER ROLE role_name WITH SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN REPLICATION BYPASSRLS CONNECTION LIMIT 100 PASSWORD 'abcdef' VALID UNTIL '2025-01-01'";
|
||||
assert_eq!(
|
||||
pg().verified_stmt(sql),
|
||||
Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "role_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::WithOptions {
|
||||
options: vec![
|
||||
RoleOption::SuperUser(true),
|
||||
RoleOption::CreateDB(true),
|
||||
RoleOption::CreateRole(true),
|
||||
RoleOption::Inherit(true),
|
||||
RoleOption::Login(true),
|
||||
RoleOption::Replication(true),
|
||||
RoleOption::BypassRLS(true),
|
||||
RoleOption::ConnectionLimit(Expr::Value(number("100"))),
|
||||
RoleOption::Password({
|
||||
Password::Password(Expr::Value(Value::SingleQuotedString("abcdef".into())))
|
||||
}),
|
||||
RoleOption::ValidUntil(Expr::Value(Value::SingleQuotedString(
|
||||
"2025-01-01".into(),
|
||||
)))
|
||||
]
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let sql = "ALTER ROLE role_name WITH NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOLOGIN NOREPLICATION NOBYPASSRLS PASSWORD NULL";
|
||||
assert_eq!(
|
||||
pg().verified_stmt(sql),
|
||||
Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "role_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::WithOptions {
|
||||
options: vec![
|
||||
RoleOption::SuperUser(false),
|
||||
RoleOption::CreateDB(false),
|
||||
RoleOption::CreateRole(false),
|
||||
RoleOption::Inherit(false),
|
||||
RoleOption::Login(false),
|
||||
RoleOption::Replication(false),
|
||||
RoleOption::BypassRLS(false),
|
||||
RoleOption::Password(Password::NullPassword),
|
||||
]
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let sql = "ALTER ROLE role_name SET maintenance_work_mem FROM CURRENT";
|
||||
assert_eq!(
|
||||
pg().verified_stmt(sql),
|
||||
Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "role_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::Set {
|
||||
config_name: ObjectName(vec![Ident {
|
||||
value: "maintenance_work_mem".into(),
|
||||
quote_style: None
|
||||
}]),
|
||||
config_value: SetConfigValue::FromCurrent,
|
||||
in_database: None
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let sql = "ALTER ROLE role_name IN DATABASE database_name SET maintenance_work_mem = 100000";
|
||||
assert_eq!(
|
||||
pg().parse_sql_statements(sql).unwrap(),
|
||||
[Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "role_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::Set {
|
||||
config_name: ObjectName(vec![Ident {
|
||||
value: "maintenance_work_mem".into(),
|
||||
quote_style: None
|
||||
}]),
|
||||
config_value: SetConfigValue::Value(Expr::Value(number("100000"))),
|
||||
in_database: Some(ObjectName(vec![Ident {
|
||||
value: "database_name".into(),
|
||||
quote_style: None
|
||||
}]))
|
||||
},
|
||||
}]
|
||||
);
|
||||
|
||||
let sql = "ALTER ROLE role_name IN DATABASE database_name SET maintenance_work_mem TO 100000";
|
||||
assert_eq!(
|
||||
pg().verified_stmt(sql),
|
||||
Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "role_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::Set {
|
||||
config_name: ObjectName(vec![Ident {
|
||||
value: "maintenance_work_mem".into(),
|
||||
quote_style: None
|
||||
}]),
|
||||
config_value: SetConfigValue::Value(Expr::Value(number("100000"))),
|
||||
in_database: Some(ObjectName(vec![Ident {
|
||||
value: "database_name".into(),
|
||||
quote_style: None
|
||||
}]))
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let sql = "ALTER ROLE role_name IN DATABASE database_name SET maintenance_work_mem TO DEFAULT";
|
||||
assert_eq!(
|
||||
pg().verified_stmt(sql),
|
||||
Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "role_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::Set {
|
||||
config_name: ObjectName(vec![Ident {
|
||||
value: "maintenance_work_mem".into(),
|
||||
quote_style: None
|
||||
}]),
|
||||
config_value: SetConfigValue::Default,
|
||||
in_database: Some(ObjectName(vec![Ident {
|
||||
value: "database_name".into(),
|
||||
quote_style: None
|
||||
}]))
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let sql = "ALTER ROLE role_name RESET ALL";
|
||||
assert_eq!(
|
||||
pg().verified_stmt(sql),
|
||||
Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "role_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::Reset {
|
||||
config_name: ResetConfig::ALL,
|
||||
in_database: None
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
let sql = "ALTER ROLE role_name IN DATABASE database_name RESET maintenance_work_mem";
|
||||
assert_eq!(
|
||||
pg().verified_stmt(sql),
|
||||
Statement::AlterRole {
|
||||
name: Ident {
|
||||
value: "role_name".into(),
|
||||
quote_style: None
|
||||
},
|
||||
operation: AlterRoleOperation::Reset {
|
||||
config_name: ResetConfig::ConfigName(ObjectName(vec![Ident {
|
||||
value: "maintenance_work_mem".into(),
|
||||
quote_style: None
|
||||
}])),
|
||||
in_database: Some(ObjectName(vec![Ident {
|
||||
value: "database_name".into(),
|
||||
quote_style: None
|
||||
}]))
|
||||
},
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_delimited_identifiers() {
|
||||
// check that quoted identifiers in any position remain quoted after serialization
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue