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

Disambiguate CREATE ROLE ... USER and GROUP #628

Merged
merged 1 commit 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
11 changes: 11 additions & 0 deletions src/ast/mod.rs
Expand Up @@ -1117,6 +1117,7 @@ pub enum Statement {
if_not_exists: bool,
},
/// CREATE ROLE
/// See [postgres](https://www.postgresql.org/docs/current/sql-createrole.html)
CreateRole {
names: Vec<ObjectName>,
if_not_exists: bool,
Expand All @@ -1132,7 +1133,9 @@ pub enum Statement {
connection_limit: Option<Expr>,
valid_until: Option<Expr>,
in_role: Vec<Ident>,
in_group: Vec<Ident>,
role: Vec<Ident>,
user: Vec<Ident>,
admin: Vec<Ident>,
// MSSQL
authorization_owner: Option<ObjectName>,
Expand Down Expand Up @@ -2005,7 +2008,9 @@ impl fmt::Display for Statement {
connection_limit,
valid_until,
in_role,
in_group,
role,
user,
admin,
authorization_owner,
} => {
Expand Down Expand Up @@ -2064,9 +2069,15 @@ impl fmt::Display for Statement {
if !in_role.is_empty() {
write!(f, " IN ROLE {}", display_comma_separated(in_role))?;
}
if !in_group.is_empty() {
write!(f, " IN GROUP {}", display_comma_separated(in_group))?;
}
if !role.is_empty() {
write!(f, " ROLE {}", display_comma_separated(role))?;
}
if !user.is_empty() {
write!(f, " USER {}", display_comma_separated(user))?;
}
if !admin.is_empty() {
write!(f, " ADMIN {}", display_comma_separated(admin))?;
}
Expand Down
35 changes: 27 additions & 8 deletions src/parser.rs
Expand Up @@ -2109,7 +2109,9 @@ impl<'a> Parser<'a> {
let mut connection_limit = None;
let mut valid_until = None;
let mut in_role = vec![];
let mut roles = vec![];
let mut in_group = vec![];
let mut role = vec![];
let mut user = vec![];
let mut admin = vec![];

while let Some(keyword) = self.parse_one_of_keywords(&optional_keywords) {
Expand Down Expand Up @@ -2209,22 +2211,37 @@ impl<'a> Parser<'a> {
}
}
Keyword::IN => {
if self.parse_keyword(Keyword::ROLE) || self.parse_keyword(Keyword::GROUP) {
if self.parse_keyword(Keyword::ROLE) {
if !in_role.is_empty() {
parser_err!("Found multiple IN ROLE or IN GROUP")
parser_err!("Found multiple IN ROLE")
} else {
in_role = self.parse_comma_separated(Parser::parse_identifier)?;
Ok(())
}
} else if self.parse_keyword(Keyword::GROUP) {
if !in_group.is_empty() {
parser_err!("Found multiple IN GROUP")
} else {
in_group = self.parse_comma_separated(Parser::parse_identifier)?;
Ok(())
}
} else {
self.expected("ROLE or GROUP after IN", self.peek_token())
}
}
Keyword::ROLE | Keyword::USER => {
if !roles.is_empty() {
parser_err!("Found multiple ROLE or USER")
Keyword::ROLE => {
if !role.is_empty() {
parser_err!("Found multiple ROLE")
} else {
role = self.parse_comma_separated(Parser::parse_identifier)?;
Ok(())
}
}
Keyword::USER => {
if !user.is_empty() {
parser_err!("Found multiple USER")
} else {
roles = self.parse_comma_separated(Parser::parse_identifier)?;
user = self.parse_comma_separated(Parser::parse_identifier)?;
Ok(())
}
}
Expand Down Expand Up @@ -2254,7 +2271,9 @@ impl<'a> Parser<'a> {
connection_limit,
valid_until,
in_role,
role: roles,
in_group,
role,
user,
admin,
authorization_owner,
})
Expand Down
18 changes: 18 additions & 0 deletions tests/sqlparser_postgres.rs
Expand Up @@ -1807,7 +1807,9 @@ fn parse_create_role() {
connection_limit,
valid_until,
in_role,
in_group,
role,
user,
admin,
authorization_owner,
}],
Expand All @@ -1833,13 +1835,29 @@ fn parse_create_role() {
Some(Expr::Value(Value::SingleQuotedString("2025-01-01".into())))
);
assert_eq_vec(&["role1", "role2"], in_role);
assert!(in_group.is_empty());
assert_eq_vec(&["role3"], role);
assert!(user.is_empty());
assert_eq_vec(&["role4", "role5"], admin);
assert_eq!(*authorization_owner, None);
}
err => panic!("Failed to parse CREATE ROLE test case: {:?}", err),
}

let sql = "CREATE ROLE abc WITH USER foo, bar ROLE baz ";
match pg().parse_sql_statements(sql).as_deref() {
Ok(
[Statement::CreateRole {
names, user, role, ..
}],
) => {
assert_eq_vec(&["abc"], names);
assert_eq_vec(&["foo", "bar"], user);
assert_eq_vec(&["baz"], role);
}
err => panic!("Failed to parse CREATE ROLE test case: {:?}", err),
}

let negatables = vec![
"BYPASSRLS",
"CREATEDB",
Expand Down