Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support CREATE ROLE and DROP ROLE #598

Merged
merged 6 commits into from Sep 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
114 changes: 114 additions & 0 deletions src/ast/mod.rs
Expand Up @@ -892,6 +892,13 @@ impl fmt::Display for CommentObject {
}
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum Password {
Password(Expr),
NullPassword,
}

/// A top-level statement (SELECT, INSERT, CREATE, etc.)
#[allow(clippy::large_enum_variant)]
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -1047,6 +1054,27 @@ pub enum Statement {
unique: bool,
if_not_exists: bool,
},
/// CREATE ROLE
CreateRole {
names: Vec<ObjectName>,
if_not_exists: bool,
// Postgres
login: Option<bool>,
inherit: Option<bool>,
bypassrls: Option<bool>,
password: Option<Password>,
superuser: Option<bool>,
create_db: Option<bool>,
create_role: Option<bool>,
replication: Option<bool>,
connection_limit: Option<Expr>,
valid_until: Option<Expr>,
Comment on lines +1062 to +1071
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One downside with this implementation is that the order of the grants is not preserved and thus the original SQL can not be reconstructed

What do you think about an alternate encoding like:

...
role_grants: Vec<RoleGrant>
...

And then

enum RoleGrant {
  Login, 
  Inherit,
  Password(Password)
   ..
}

However, I see this PR follows the model of GRANT so I think it is also fine as is

in_role: Vec<Ident>,
role: Vec<Ident>,
admin: Vec<Ident>,
// MSSQL
authorization_owner: Option<ObjectName>,
},
/// ALTER TABLE
AlterTable {
/// Table name
Expand Down Expand Up @@ -1890,6 +1918,90 @@ impl fmt::Display for Statement {
table_name = table_name,
columns = display_separated(columns, ",")
),
Statement::CreateRole {
names,
if_not_exists,
inherit,
login,
bypassrls,
password,
create_db,
create_role,
superuser,
replication,
connection_limit,
valid_until,
in_role,
role,
admin,
authorization_owner,
} => {
write!(
f,
"CREATE ROLE {if_not_exists}{names}{superuser}{create_db}{create_role}{inherit}{login}{replication}{bypassrls}",
if_not_exists = if *if_not_exists { "IF NOT EXISTS " } else { "" },
names = display_separated(names, ", "),
superuser = match *superuser {
Some(true) => " SUPERUSER",
Some(false) => " NOSUPERUSER",
None => ""
},
create_db = match *create_db {
Some(true) => " CREATEDB",
Some(false) => " NOCREATEDB",
None => ""
},
create_role = match *create_role {
Some(true) => " CREATEROLE",
Some(false) => " NOCREATEROLE",
None => ""
},
inherit = match *inherit {
Some(true) => " INHERIT",
Some(false) => " NOINHERIT",
None => ""
},
login = match *login {
Some(true) => " LOGIN",
Some(false) => " NOLOGIN",
None => ""
},
replication = match *replication {
Some(true) => " REPLICATION",
Some(false) => " NOREPLICATION",
None => ""
},
bypassrls = match *bypassrls {
Some(true) => " BYPASSRLS",
Some(false) => " NOBYPASSRLS",
None => ""
}
)?;
if let Some(limit) = connection_limit {
write!(f, " CONNECTION LIMIT {}", limit)?;
}
match password {
Some(Password::Password(pass)) => write!(f, " PASSWORD {}", pass),
Some(Password::NullPassword) => write!(f, " PASSWORD NULL"),
None => Ok(()),
}?;
if let Some(until) = valid_until {
write!(f, " VALID UNTIL {}", until)?;
}
if !in_role.is_empty() {
write!(f, " IN ROLE {}", display_comma_separated(in_role))?;
}
if !role.is_empty() {
write!(f, " ROLE {}", display_comma_separated(role))?;
}
if !admin.is_empty() {
write!(f, " ADMIN {}", display_comma_separated(admin))?;
}
if let Some(owner) = authorization_owner {
write!(f, " AUTHORIZATION {}", owner)?;
}
Ok(())
}
Statement::AlterTable { name, operation } => {
write!(f, "ALTER TABLE {} {}", name, operation)
}
Expand Down Expand Up @@ -2603,6 +2715,7 @@ pub enum ObjectType {
View,
Index,
Schema,
Role,
}

impl fmt::Display for ObjectType {
Expand All @@ -2612,6 +2725,7 @@ impl fmt::Display for ObjectType {
ObjectType::View => "VIEW",
ObjectType::Index => "INDEX",
ObjectType::Schema => "SCHEMA",
ObjectType::Role => "ROLE",
})
}
}
Expand Down
18 changes: 18 additions & 0 deletions src/keywords.rs
Expand Up @@ -70,6 +70,7 @@ define_keywords!(
ABSOLUTE,
ACTION,
ADD,
ADMIN,
ALL,
ALLOCATE,
ALTER,
Expand Down Expand Up @@ -105,6 +106,7 @@ define_keywords!(
BOOLEAN,
BOTH,
BY,
BYPASSRLS,
BYTEA,
CACHE,
CALL,
Expand Down Expand Up @@ -152,6 +154,8 @@ define_keywords!(
COVAR_POP,
COVAR_SAMP,
CREATE,
CREATEDB,
CREATEROLE,
CROSS,
CSV,
CUBE,
Expand Down Expand Up @@ -270,6 +274,7 @@ define_keywords!(
IN,
INDEX,
INDICATOR,
INHERIT,
INNER,
INOUT,
INPUTFORMAT,
Expand Down Expand Up @@ -310,6 +315,7 @@ define_keywords!(
LOCALTIME,
LOCALTIMESTAMP,
LOCATION,
LOGIN,
LOWER,
MANAGEDLOCATION,
MATCH,
Expand Down Expand Up @@ -339,9 +345,16 @@ define_keywords!(
NEW,
NEXT,
NO,
NOBYPASSRLS,
NOCREATEDB,
NOCREATEROLE,
NOINHERIT,
NOLOGIN,
NONE,
NOREPLICATION,
NORMALIZE,
NOSCAN,
NOSUPERUSER,
NOT,
NTH_VALUE,
NTILE,
Expand Down Expand Up @@ -377,6 +390,7 @@ define_keywords!(
PARTITION,
PARTITIONED,
PARTITIONS,
PASSWORD,
PERCENT,
PERCENTILE_CONT,
PERCENTILE_DISC,
Expand Down Expand Up @@ -429,6 +443,7 @@ define_keywords!(
REPAIR,
REPEATABLE,
REPLACE,
REPLICATION,
RESTRICT,
RESULT,
RETURN,
Expand Down Expand Up @@ -489,6 +504,7 @@ define_keywords!(
SUCCEEDS,
SUM,
SUPER,
SUPERUSER,
SYMMETRIC,
SYNC,
SYSTEM,
Expand Down Expand Up @@ -535,13 +551,15 @@ define_keywords!(
UNLOGGED,
UNNEST,
UNSIGNED,
UNTIL,
UPDATE,
UPPER,
USAGE,
USE,
USER,
USING,
UUID,
VALID,
VALUE,
VALUES,
VALUE_OF,
Expand Down