From 88656d4f51fc592a72fbd20444817fdf1355c145 Mon Sep 17 00:00:00 2001 From: Ben Cook Date: Tue, 30 Aug 2022 20:44:11 -0700 Subject: [PATCH 1/6] Parse GRANT ROLE and DROP ROLE --- src/ast/mod.rs | 120 +++++++++++++++++++++++ src/keywords.rs | 18 ++++ src/parser.rs | 200 +++++++++++++++++++++++++++++++++++++- src/test_utils.rs | 7 ++ tests/sqlparser_common.rs | 182 ++++++++++++++++++++++++++-------- 5 files changed, 485 insertions(+), 42 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 4f5fdb2eb..e595d8788 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -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)] @@ -1047,6 +1054,27 @@ pub enum Statement { unique: bool, if_not_exists: bool, }, + /// CREATE ROLE + CreateRole { + names: Vec, + if_not_exists: bool, + // Postgres + login: Option, + inherit: Option, + bypassrls: Option, + password: Option, + superuser: Option, + create_db: Option, + create_role: Option, + replication: Option, + connection_limit: Option, + valid_until: Option, + in_role: Vec, + role: Vec, + admin: Vec, + // MSSQL + authorization_owner: Option, + }, /// ALTER TABLE AlterTable { /// Table name @@ -1890,6 +1918,96 @@ 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}{connection_limit}{password}{valid_until}{in_role}{role}{admin}{authorization_owner}", + 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 => "" + }, + connection_limit = match &*connection_limit { + Some(limit) => format!(" CONNECTION LIMIT {}", limit), + None => "".to_string(), + }, + password = match &*password { + Some(Password::Password(pass)) => format!(" PASSWORD {}", pass), + Some(Password::NullPassword) => " PASSWORD NULL".to_string(), + None => "".to_string(), + }, + valid_until = match &*valid_until { + Some(until) => format!(" VALID UNTIL {}", until), + None => "".to_string(), + }, + in_role = if in_role.is_empty() { + "".into() + } else { + format!(" IN ROLE {}", display_comma_separated(in_role)) + }, + role = if role.is_empty() { + "".into() + } else { + format!(" ROLE {}", display_comma_separated(role)) + }, + admin = if admin.is_empty() { + "".into() + } else { + format!(" ADMIN {}", display_comma_separated(admin)) + }, + authorization_owner = match &*authorization_owner { + Some(owner) => format!(" AUTHORIZATION {}", owner), + None => "".to_string() + }, + ), Statement::AlterTable { name, operation } => { write!(f, "ALTER TABLE {} {}", name, operation) } @@ -2603,6 +2721,7 @@ pub enum ObjectType { View, Index, Schema, + Role, } impl fmt::Display for ObjectType { @@ -2612,6 +2731,7 @@ impl fmt::Display for ObjectType { ObjectType::View => "VIEW", ObjectType::Index => "INDEX", ObjectType::Schema => "SCHEMA", + ObjectType::Role => "ROLE", }) } } diff --git a/src/keywords.rs b/src/keywords.rs index 30ec735f7..e888dc7c7 100644 --- a/src/keywords.rs +++ b/src/keywords.rs @@ -70,6 +70,7 @@ define_keywords!( ABSOLUTE, ACTION, ADD, + ADMIN, ALL, ALLOCATE, ALTER, @@ -105,6 +106,7 @@ define_keywords!( BOOLEAN, BOTH, BY, + BYPASSRLS, BYTEA, CACHE, CALL, @@ -152,6 +154,8 @@ define_keywords!( COVAR_POP, COVAR_SAMP, CREATE, + CREATEDB, + CREATEROLE, CROSS, CSV, CUBE, @@ -270,6 +274,7 @@ define_keywords!( IN, INDEX, INDICATOR, + INHERIT, INNER, INOUT, INPUTFORMAT, @@ -310,6 +315,7 @@ define_keywords!( LOCALTIME, LOCALTIMESTAMP, LOCATION, + LOGIN, LOWER, MANAGEDLOCATION, MATCH, @@ -339,9 +345,16 @@ define_keywords!( NEW, NEXT, NO, + NOBYPASSRLS, + NOCREATEDB, + NOCREATEROLE, + NOINHERIT, + NOLOGIN, NONE, + NOREPLICATION, NORMALIZE, NOSCAN, + NOSUPERUSER, NOT, NTH_VALUE, NTILE, @@ -377,6 +390,7 @@ define_keywords!( PARTITION, PARTITIONED, PARTITIONS, + PASSWORD, PERCENT, PERCENTILE_CONT, PERCENTILE_DISC, @@ -429,6 +443,7 @@ define_keywords!( REPAIR, REPEATABLE, REPLACE, + REPLICATION, RESTRICT, RESULT, RETURN, @@ -489,6 +504,7 @@ define_keywords!( SUCCEEDS, SUM, SUPER, + SUPERUSER, SYMMETRIC, SYNC, SYSTEM, @@ -535,6 +551,7 @@ define_keywords!( UNLOGGED, UNNEST, UNSIGNED, + UNTIL, UPDATE, UPPER, USAGE, @@ -542,6 +559,7 @@ define_keywords!( USER, USING, UUID, + VALID, VALUE, VALUES, VALUE_OF, diff --git a/src/parser.rs b/src/parser.rs index 877c47303..48837f7d7 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1866,6 +1866,8 @@ impl<'a> Parser<'a> { self.parse_create_database() } else if dialect_of!(self is HiveDialect) && self.parse_keyword(Keyword::FUNCTION) { self.parse_create_function(temporary) + } else if self.parse_keyword(Keyword::ROLE) { + self.parse_create_role() } else { self.expected("an object type after CREATE", self.peek_token()) } @@ -2044,6 +2046,197 @@ impl<'a> Parser<'a> { }) } + pub fn parse_create_role(&mut self) -> Result { + let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]); + let names = self.parse_comma_separated(Parser::parse_object_name)?; + + let _ = self.parse_keyword(Keyword::WITH); + + let optional_keywords = [ + // MSSQL + Keyword::AUTHORIZATION, + // Postgres + Keyword::LOGIN, Keyword::NOLOGIN, + Keyword::INHERIT, Keyword::NOINHERIT, + Keyword::BYPASSRLS, Keyword::NOBYPASSRLS, + Keyword::PASSWORD, + Keyword::CREATEDB, Keyword::NOCREATEDB, + Keyword::CREATEROLE, Keyword::NOCREATEROLE, + Keyword::SUPERUSER, Keyword::NOSUPERUSER, + Keyword::REPLICATION, Keyword::NOREPLICATION, + Keyword::CONNECTION, + Keyword::VALID, + Keyword::IN, + Keyword::ROLE, + Keyword::ADMIN, + Keyword::USER, + ]; + + // MSSQL + let mut authorization_owner = None; + // Postgres + let mut login = None; + let mut inherit = None; + let mut bypassrls = None; + let mut password = None; + let mut create_db = None; + let mut create_role = None; + let mut superuser = None; + let mut replication = None; + let mut connection_limit = None; + let mut valid_until = None; + let mut in_role = vec![]; + let mut roles = vec![]; + let mut admin = vec![]; + + while let Some(keyword) = self.parse_one_of_keywords(&optional_keywords) { + match keyword { + Keyword::AUTHORIZATION => { + if authorization_owner.is_some() { + parser_err!("Found multiple AUTHORIZATION") + } else { + authorization_owner = Some(self.parse_object_name()?); + Ok(()) + } + } + Keyword::LOGIN | Keyword::NOLOGIN => { + if login.is_some() { + parser_err!("Found multiple LOGIN or NOLOGIN") + } else { + login = Some(keyword == Keyword::LOGIN); + Ok(()) + } + } + Keyword::INHERIT | Keyword::NOINHERIT => { + if inherit.is_some() { + parser_err!("Found multiple INHERIT or NOINHERIT") + } else { + inherit = Some(keyword == Keyword::INHERIT); + Ok(()) + } + } + Keyword::BYPASSRLS | Keyword::NOBYPASSRLS => { + if bypassrls.is_some() { + parser_err!("Found multiple BYPASSRLS or NOBYPASSRLS") + } else { + bypassrls = Some(keyword == Keyword::BYPASSRLS); + Ok(()) + } + } + Keyword::CREATEDB | Keyword::NOCREATEDB => { + if create_db.is_some() { + parser_err!("Found multiple CREATEDB or NOCREATEDB") + } else { + create_db = Some(keyword == Keyword::CREATEDB); + Ok(()) + } + } + Keyword::CREATEROLE | Keyword::NOCREATEROLE => { + if create_role.is_some() { + parser_err!("Found multiple CREATEROLE or NOCREATEROLE") + } else { + create_role = Some(keyword == Keyword::CREATEROLE); + Ok(()) + } + } + Keyword::SUPERUSER | Keyword::NOSUPERUSER => { + if superuser.is_some() { + parser_err!("Found multiple SUPERUSER or NOSUPERUSER") + } else { + superuser = Some(keyword == Keyword::SUPERUSER); + Ok(()) + } + } + Keyword::REPLICATION | Keyword::NOREPLICATION => { + if replication.is_some() { + parser_err!("Found multiple REPLICATION or NOREPLICATION") + } else { + replication = Some(keyword == Keyword::REPLICATION); + Ok(()) + } + } + Keyword::PASSWORD => { + if password.is_some() { + parser_err!("Found multiple PASSWORD") + } else { + password = if self.parse_keyword(Keyword::NULL) { + Some(Password::NullPassword) + } else { + Some(Password::Password(Expr::Value(self.parse_value()?))) + }; + Ok(()) + } + } + Keyword::CONNECTION => { + self.expect_keyword(Keyword::LIMIT)?; + if connection_limit.is_some() { + parser_err!("Found multiple CONNECTION LIMIT") + } else { + connection_limit = Some(Expr::Value(self.parse_number_value()?)); + Ok(()) + } + } + Keyword::VALID => { + self.expect_keyword(Keyword::UNTIL)?; + if valid_until.is_some() { + parser_err!("Found multiple VALID UNTIL") + } else { + valid_until = Some(Expr::Value(self.parse_value()?)); + Ok(()) + } + } + Keyword::IN => { + if self.parse_keyword(Keyword::ROLE) || self.parse_keyword(Keyword::GROUP) { + if !in_role.is_empty() { + parser_err!("Found multiple IN ROLE or IN GROUP") + } else { + in_role = 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") + } else { + roles = self.parse_comma_separated(Parser::parse_identifier)?; + Ok(()) + } + } + Keyword::ADMIN => { + if !admin.is_empty() { + parser_err!("Found multiple ADMIN") + } else { + admin = self.parse_comma_separated(Parser::parse_identifier)?; + Ok(()) + } + } + _ => break + }? + } + + Ok(Statement::CreateRole { + names, + if_not_exists, + login, + inherit, + bypassrls, + password, + create_db, + create_role, + replication, + superuser, + connection_limit, + valid_until, + in_role, + role: roles, + admin, + authorization_owner, + }) + } + pub fn parse_drop(&mut self) -> Result { let object_type = if self.parse_keyword(Keyword::TABLE) { ObjectType::Table @@ -2051,10 +2244,12 @@ impl<'a> Parser<'a> { ObjectType::View } else if self.parse_keyword(Keyword::INDEX) { ObjectType::Index + } else if self.parse_keyword(Keyword::ROLE) { + ObjectType::Role } else if self.parse_keyword(Keyword::SCHEMA) { ObjectType::Schema } else { - return self.expected("TABLE, VIEW, INDEX or SCHEMA after DROP", self.peek_token()); + return self.expected("TABLE, VIEW, INDEX, ROLE, or SCHEMA after DROP", self.peek_token()); }; // Many dialects support the non standard `IF EXISTS` clause and allow // specifying multiple objects to delete in a single statement @@ -2066,6 +2261,9 @@ impl<'a> Parser<'a> { if cascade && restrict { return parser_err!("Cannot specify both CASCADE and RESTRICT in DROP"); } + if object_type == ObjectType::Role && (cascade || restrict || purge) { + return parser_err!("Cannot specify CASCADE, RESTRICT, or PURGE in DROP ROLE"); + } Ok(Statement::Drop { object_type, if_exists, diff --git a/src/test_utils.rs b/src/test_utils.rs index c5ea62085..d948bc2ed 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -146,6 +146,13 @@ pub fn all_dialects() -> TestedDialects { } } +pub fn assert_eq_vec(expected: &[&str], actual: &Vec) { + assert_eq!( + expected, + actual.iter().map(ToString::to_string).collect::>() + ); +} + pub fn only(v: impl IntoIterator) -> T { let mut iter = v.into_iter(); if let (Some(item), None) = (iter.next(), iter.next()) { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 6fee5e88b..7b65855bf 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -31,7 +31,7 @@ use sqlparser::keywords::ALL_KEYWORDS; use sqlparser::parser::{Parser, ParserError}; use test_utils::{ - all_dialects, expr_from_projection, join, number, only, table, table_alias, TestedDialects, + all_dialects, assert_eq_vec, expr_from_projection, join, number, only, table, table_alias, TestedDialects, }; #[test] @@ -4763,6 +4763,136 @@ fn parse_drop_index() { } } +#[test] +fn parse_create_role() { + let sql = "CREATE ROLE consultant"; + match verified_stmt(sql) { + Statement::CreateRole { + names, + .. + } => { + assert_eq_vec(&["consultant"], &names); + }, + _ => unreachable!() + } + + let sql = "CREATE ROLE mssql AUTHORIZATION helena"; + match verified_stmt(sql) { + Statement::CreateRole { + names, + authorization_owner, + .. + } => { + assert_eq_vec(&["mssql"], &names); + assert_eq!(authorization_owner, Some(ObjectName(vec![Ident { value: "helena".into(), quote_style: None }]))); + }, + _ => unreachable!() + } + + let sql = "CREATE ROLE IF NOT EXISTS mysql_a, mysql_b"; + match verified_stmt(sql) { + Statement::CreateRole { + names, + if_not_exists, + .. + } => { + assert_eq_vec(&["mysql_a", "mysql_b"], &names); + assert_eq!(if_not_exists, true); + }, + _ => unreachable!() + } + + let sql = "CREATE ROLE abc LOGIN PASSWORD NULL"; + match parse_sql_statements(sql).as_deref() { + Ok([Statement::CreateRole { + names, + login, + password, + .. + }]) => { + assert_eq_vec(&["abc"], names); + assert_eq!(*login, Some(true)); + assert_eq!(*password, Some(Password::NullPassword)); + }, + err => panic!("Failed to parse CREATE ROLE test case: {:?}", err) + } + + let sql = "CREATE ROLE magician WITH SUPERUSER CREATEROLE NOCREATEDB BYPASSRLS INHERIT PASSWORD 'abcdef' LOGIN VALID UNTIL '2025-01-01' IN ROLE role1, role2 ROLE role3 ADMIN role4, role5 REPLICATION"; + // Roundtrip order of optional parameters is not preserved + match parse_sql_statements(sql).as_deref() { + Ok([Statement::CreateRole { + names, + if_not_exists, + bypassrls, + login, + inherit, + password, + superuser, + create_db, + create_role, + replication, + connection_limit, + valid_until, + in_role, + role, + admin, + authorization_owner, + }]) => { + assert_eq_vec(&["magician"], names); + assert_eq!(*if_not_exists, false); + assert_eq!(*login, Some(true)); + assert_eq!(*inherit, Some(true)); + assert_eq!(*bypassrls, Some(true)); + assert_eq!(*password, Some(Password::Password(Expr::Value(Value::SingleQuotedString("abcdef".into()))))); + assert_eq!(*superuser, Some(true)); + assert_eq!(*create_db, Some(false)); + assert_eq!(*create_role, Some(true)); + assert_eq!(*replication, Some(true)); + assert_eq!(*connection_limit, None); + assert_eq!(*valid_until, Some(Expr::Value(Value::SingleQuotedString("2025-01-01".into())))); + assert_eq_vec(&["role1", "role2"], in_role); + assert_eq_vec(&["role3"], role); + assert_eq_vec(&["role4", "role5"], admin); + assert_eq!(*authorization_owner, None); + }, + err => panic!("Failed to parse CREATE ROLE test case: {:?}", err) + } + + let negatables = vec!["BYPASSRLS", "CREATEDB", "CREATEROLE", "INHERIT", "LOGIN", "REPLICATION", "SUPERUSER"]; + + for negatable_kw in negatables.iter() { + let sql = format!("CREATE ROLE abc {kw} NO{kw}", kw = negatable_kw); + match parse_sql_statements(&sql) { + Ok(_) => panic!("Should not be able to parse CREATE ROLE containing both negated and non-negated versions of the same keyword: {}", negatable_kw), + _ => () + } + } +} + +#[test] +fn parse_drop_role() { + let sql = "DROP ROLE abc"; + match verified_stmt(sql) { + Statement::Drop { names, object_type, if_exists, .. } => { + assert_eq_vec(&["abc"], &names); + assert_eq!(ObjectType::Role, object_type); + assert_eq!(if_exists, false); + } + _ => unreachable!() + }; + + let sql = "DROP ROLE IF EXISTS def, magician, quaternion"; + match verified_stmt(sql) { + Statement::Drop { names, object_type, if_exists, .. } => { + assert_eq_vec(&["def", "magician", "quaternion"], &names); + assert_eq!(ObjectType::Role, object_type); + assert_eq!(if_exists, true); + } + _ => unreachable!() + } +} + + #[test] fn parse_grant() { let sql = "GRANT SELECT, INSERT, UPDATE (shape, size), USAGE, DELETE, TRUNCATE, REFERENCES, TRIGGER, CONNECT, CREATE, EXECUTE, TEMPORARY ON abc, def TO xyz, m WITH GRANT OPTION GRANTED BY jj"; @@ -4804,14 +4934,8 @@ fn parse_grant() { ], actions ); - assert_eq!( - vec!["abc", "def"], - objects.iter().map(ToString::to_string).collect::>() - ); - assert_eq!( - vec!["xyz", "m"], - grantees.iter().map(ToString::to_string).collect::>() - ); + assert_eq_vec(&["abc", "def"], &objects); + assert_eq_vec(&["xyz", "m"], &grantees); assert!(with_grant_option); assert_eq!("jj", granted_by.unwrap().to_string()); } @@ -4831,14 +4955,8 @@ fn parse_grant() { } => match (privileges, objects) { (Privileges::Actions(actions), GrantObjects::AllTablesInSchema { schemas }) => { assert_eq!(vec![Action::Insert { columns: None }], actions); - assert_eq!( - vec!["public"], - schemas.iter().map(ToString::to_string).collect::>() - ); - assert_eq!( - vec!["browser"], - grantees.iter().map(ToString::to_string).collect::>() - ); + assert_eq_vec(&["public"], &schemas); + assert_eq_vec(&["browser"], &grantees); assert!(!with_grant_option); } _ => unreachable!(), @@ -4860,14 +4978,8 @@ fn parse_grant() { vec![Action::Usage, Action::Select { columns: None }], actions ); - assert_eq!( - vec!["p"], - objects.iter().map(ToString::to_string).collect::>() - ); - assert_eq!( - vec!["u"], - grantees.iter().map(ToString::to_string).collect::>() - ); + assert_eq_vec(&["p"], &objects); + assert_eq_vec(&["u"], &grantees); } _ => unreachable!(), }, @@ -4901,10 +5013,7 @@ fn parse_grant() { GrantObjects::Schemas(schemas), ) => { assert!(!with_privileges_keyword); - assert_eq!( - vec!["aa", "b"], - schemas.iter().map(ToString::to_string).collect::>() - ); + assert_eq_vec(&["aa", "b"], &schemas); } _ => unreachable!(), }, @@ -4920,10 +5029,7 @@ fn parse_grant() { } => match (privileges, objects) { (Privileges::Actions(actions), GrantObjects::AllSequencesInSchema { schemas }) => { assert_eq!(vec![Action::Usage], actions); - assert_eq!( - vec!["bus"], - schemas.iter().map(ToString::to_string).collect::>() - ); + assert_eq_vec(&["bus"], &schemas); } _ => unreachable!(), }, @@ -4948,14 +5054,8 @@ fn test_revoke() { }, privileges ); - assert_eq!( - vec!["users", "auth"], - tables.iter().map(ToString::to_string).collect::>() - ); - assert_eq!( - vec!["analyst"], - grantees.iter().map(ToString::to_string).collect::>() - ); + assert_eq_vec(&["users", "auth"], &tables); + assert_eq_vec(&["analyst"], &grantees); assert!(cascade); assert_eq!(None, granted_by); } From a8c441f729b96de1e307a913945dce01a4c21455 Mon Sep 17 00:00:00 2001 From: Ben Cook Date: Wed, 31 Aug 2022 23:22:26 -0700 Subject: [PATCH 2/6] Gate create role on dialect --- src/parser.rs | 39 +++++++++--------- tests/sqlparser_common.rs | 79 ----------------------------------- tests/sqlparser_mssql.rs | 16 ++++++++ tests/sqlparser_postgres.rs | 82 +++++++++++++++++++++++++++++++++++++ 4 files changed, 118 insertions(+), 98 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index 48837f7d7..bcc21a316 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2052,25 +2052,26 @@ impl<'a> Parser<'a> { let _ = self.parse_keyword(Keyword::WITH); - let optional_keywords = [ - // MSSQL - Keyword::AUTHORIZATION, - // Postgres - Keyword::LOGIN, Keyword::NOLOGIN, - Keyword::INHERIT, Keyword::NOINHERIT, - Keyword::BYPASSRLS, Keyword::NOBYPASSRLS, - Keyword::PASSWORD, - Keyword::CREATEDB, Keyword::NOCREATEDB, - Keyword::CREATEROLE, Keyword::NOCREATEROLE, - Keyword::SUPERUSER, Keyword::NOSUPERUSER, - Keyword::REPLICATION, Keyword::NOREPLICATION, - Keyword::CONNECTION, - Keyword::VALID, - Keyword::IN, - Keyword::ROLE, - Keyword::ADMIN, - Keyword::USER, - ]; + let optional_keywords = if dialect_of!(self is MsSqlDialect) { + vec![Keyword::AUTHORIZATION] + } else if dialect_of!(self is PostgreSqlDialect) { + vec![ + Keyword::LOGIN, Keyword::NOLOGIN, + Keyword::INHERIT, Keyword::NOINHERIT, + Keyword::BYPASSRLS, Keyword::NOBYPASSRLS, + Keyword::PASSWORD, + Keyword::CREATEDB, Keyword::NOCREATEDB, + Keyword::CREATEROLE, Keyword::NOCREATEROLE, + Keyword::SUPERUSER, Keyword::NOSUPERUSER, + Keyword::REPLICATION, Keyword::NOREPLICATION, + Keyword::CONNECTION, + Keyword::VALID, + Keyword::IN, + Keyword::ROLE, + Keyword::ADMIN, + Keyword::USER, + ] + } else { vec![] }; // MSSQL let mut authorization_owner = None; diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 7b65855bf..804855ba2 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -4776,19 +4776,6 @@ fn parse_create_role() { _ => unreachable!() } - let sql = "CREATE ROLE mssql AUTHORIZATION helena"; - match verified_stmt(sql) { - Statement::CreateRole { - names, - authorization_owner, - .. - } => { - assert_eq_vec(&["mssql"], &names); - assert_eq!(authorization_owner, Some(ObjectName(vec![Ident { value: "helena".into(), quote_style: None }]))); - }, - _ => unreachable!() - } - let sql = "CREATE ROLE IF NOT EXISTS mysql_a, mysql_b"; match verified_stmt(sql) { Statement::CreateRole { @@ -4801,72 +4788,6 @@ fn parse_create_role() { }, _ => unreachable!() } - - let sql = "CREATE ROLE abc LOGIN PASSWORD NULL"; - match parse_sql_statements(sql).as_deref() { - Ok([Statement::CreateRole { - names, - login, - password, - .. - }]) => { - assert_eq_vec(&["abc"], names); - assert_eq!(*login, Some(true)); - assert_eq!(*password, Some(Password::NullPassword)); - }, - err => panic!("Failed to parse CREATE ROLE test case: {:?}", err) - } - - let sql = "CREATE ROLE magician WITH SUPERUSER CREATEROLE NOCREATEDB BYPASSRLS INHERIT PASSWORD 'abcdef' LOGIN VALID UNTIL '2025-01-01' IN ROLE role1, role2 ROLE role3 ADMIN role4, role5 REPLICATION"; - // Roundtrip order of optional parameters is not preserved - match parse_sql_statements(sql).as_deref() { - Ok([Statement::CreateRole { - names, - if_not_exists, - bypassrls, - login, - inherit, - password, - superuser, - create_db, - create_role, - replication, - connection_limit, - valid_until, - in_role, - role, - admin, - authorization_owner, - }]) => { - assert_eq_vec(&["magician"], names); - assert_eq!(*if_not_exists, false); - assert_eq!(*login, Some(true)); - assert_eq!(*inherit, Some(true)); - assert_eq!(*bypassrls, Some(true)); - assert_eq!(*password, Some(Password::Password(Expr::Value(Value::SingleQuotedString("abcdef".into()))))); - assert_eq!(*superuser, Some(true)); - assert_eq!(*create_db, Some(false)); - assert_eq!(*create_role, Some(true)); - assert_eq!(*replication, Some(true)); - assert_eq!(*connection_limit, None); - assert_eq!(*valid_until, Some(Expr::Value(Value::SingleQuotedString("2025-01-01".into())))); - assert_eq_vec(&["role1", "role2"], in_role); - assert_eq_vec(&["role3"], role); - assert_eq_vec(&["role4", "role5"], admin); - assert_eq!(*authorization_owner, None); - }, - err => panic!("Failed to parse CREATE ROLE test case: {:?}", err) - } - - let negatables = vec!["BYPASSRLS", "CREATEDB", "CREATEROLE", "INHERIT", "LOGIN", "REPLICATION", "SUPERUSER"]; - - for negatable_kw in negatables.iter() { - let sql = format!("CREATE ROLE abc {kw} NO{kw}", kw = negatable_kw); - match parse_sql_statements(&sql) { - Ok(_) => panic!("Should not be able to parse CREATE ROLE containing both negated and non-negated versions of the same keyword: {}", negatable_kw), - _ => () - } - } } #[test] diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs index c613b8b16..9548ee355 100644 --- a/tests/sqlparser_mssql.rs +++ b/tests/sqlparser_mssql.rs @@ -118,6 +118,22 @@ fn parse_mssql_bin_literal() { let _ = ms_and_generic().one_statement_parses_to("SELECT 0xdeadBEEF", "SELECT X'deadBEEF'"); } +#[test] +fn parse_mssql_create_role() { + let sql = "CREATE ROLE mssql AUTHORIZATION helena"; + match ms().verified_stmt(sql) { + Statement::CreateRole { + names, + authorization_owner, + .. + } => { + assert_eq_vec(&["mssql"], &names); + assert_eq!(authorization_owner, Some(ObjectName(vec![Ident { value: "helena".into(), quote_style: None }]))); + }, + _ => unreachable!() + } +} + fn ms() -> TestedDialects { TestedDialects { dialects: vec![Box::new(MsSqlDialect {})], diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index 3aaabc9e3..fd4f491bf 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -1739,3 +1739,85 @@ fn parse_custom_operator() { }) ); } + +#[test] +fn parse_create_role() { + let sql = "CREATE ROLE IF NOT EXISTS mysql_a, mysql_b"; + match pg().verified_stmt(sql) { + Statement::CreateRole { + names, + if_not_exists, + .. + } => { + assert_eq_vec(&["mysql_a", "mysql_b"], &names); + assert_eq!(if_not_exists, true); + }, + _ => unreachable!() + } + + let sql = "CREATE ROLE abc LOGIN PASSWORD NULL"; + match pg().parse_sql_statements(sql).as_deref() { + Ok([Statement::CreateRole { + names, + login, + password, + .. + }]) => { + assert_eq_vec(&["abc"], names); + assert_eq!(*login, Some(true)); + assert_eq!(*password, Some(Password::NullPassword)); + }, + err => panic!("Failed to parse CREATE ROLE test case: {:?}", err) + } + + let sql = "CREATE ROLE magician WITH SUPERUSER CREATEROLE NOCREATEDB BYPASSRLS INHERIT PASSWORD 'abcdef' LOGIN VALID UNTIL '2025-01-01' IN ROLE role1, role2 ROLE role3 ADMIN role4, role5 REPLICATION"; + // Roundtrip order of optional parameters is not preserved + match pg().parse_sql_statements(sql).as_deref() { + Ok([Statement::CreateRole { + names, + if_not_exists, + bypassrls, + login, + inherit, + password, + superuser, + create_db, + create_role, + replication, + connection_limit, + valid_until, + in_role, + role, + admin, + authorization_owner, + }]) => { + assert_eq_vec(&["magician"], names); + assert_eq!(*if_not_exists, false); + assert_eq!(*login, Some(true)); + assert_eq!(*inherit, Some(true)); + assert_eq!(*bypassrls, Some(true)); + assert_eq!(*password, Some(Password::Password(Expr::Value(Value::SingleQuotedString("abcdef".into()))))); + assert_eq!(*superuser, Some(true)); + assert_eq!(*create_db, Some(false)); + assert_eq!(*create_role, Some(true)); + assert_eq!(*replication, Some(true)); + assert_eq!(*connection_limit, None); + assert_eq!(*valid_until, Some(Expr::Value(Value::SingleQuotedString("2025-01-01".into())))); + assert_eq_vec(&["role1", "role2"], in_role); + assert_eq_vec(&["role3"], role); + assert_eq_vec(&["role4", "role5"], admin); + assert_eq!(*authorization_owner, None); + }, + err => panic!("Failed to parse CREATE ROLE test case: {:?}", err) + } + + let negatables = vec!["BYPASSRLS", "CREATEDB", "CREATEROLE", "INHERIT", "LOGIN", "REPLICATION", "SUPERUSER"]; + + for negatable_kw in negatables.iter() { + let sql = format!("CREATE ROLE abc {kw} NO{kw}", kw = negatable_kw); + match pg().parse_sql_statements(&sql) { + Ok(_) => panic!("Should not be able to parse CREATE ROLE containing both negated and non-negated versions of the same keyword: {}", negatable_kw), + _ => () + } + } +} From 23a56b4f1ffad44366c2ca1b9d9c553ca604ef88 Mon Sep 17 00:00:00 2001 From: Ben Cook Date: Wed, 31 Aug 2022 23:41:25 -0700 Subject: [PATCH 3/6] cargo fmt --- src/parser.rs | 32 +++++++++----- tests/sqlparser_common.rs | 35 +++++++++------ tests/sqlparser_mssql.rs | 12 ++++-- tests/sqlparser_postgres.rs | 86 +++++++++++++++++++++++-------------- 4 files changed, 105 insertions(+), 60 deletions(-) diff --git a/src/parser.rs b/src/parser.rs index bcc21a316..6c362b3e3 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -2056,14 +2056,21 @@ impl<'a> Parser<'a> { vec![Keyword::AUTHORIZATION] } else if dialect_of!(self is PostgreSqlDialect) { vec![ - Keyword::LOGIN, Keyword::NOLOGIN, - Keyword::INHERIT, Keyword::NOINHERIT, - Keyword::BYPASSRLS, Keyword::NOBYPASSRLS, + Keyword::LOGIN, + Keyword::NOLOGIN, + Keyword::INHERIT, + Keyword::NOINHERIT, + Keyword::BYPASSRLS, + Keyword::NOBYPASSRLS, Keyword::PASSWORD, - Keyword::CREATEDB, Keyword::NOCREATEDB, - Keyword::CREATEROLE, Keyword::NOCREATEROLE, - Keyword::SUPERUSER, Keyword::NOSUPERUSER, - Keyword::REPLICATION, Keyword::NOREPLICATION, + Keyword::CREATEDB, + Keyword::NOCREATEDB, + Keyword::CREATEROLE, + Keyword::NOCREATEROLE, + Keyword::SUPERUSER, + Keyword::NOSUPERUSER, + Keyword::REPLICATION, + Keyword::NOREPLICATION, Keyword::CONNECTION, Keyword::VALID, Keyword::IN, @@ -2071,7 +2078,9 @@ impl<'a> Parser<'a> { Keyword::ADMIN, Keyword::USER, ] - } else { vec![] }; + } else { + vec![] + }; // MSSQL let mut authorization_owner = None; @@ -2214,7 +2223,7 @@ impl<'a> Parser<'a> { Ok(()) } } - _ => break + _ => break, }? } @@ -2250,7 +2259,10 @@ impl<'a> Parser<'a> { } else if self.parse_keyword(Keyword::SCHEMA) { ObjectType::Schema } else { - return self.expected("TABLE, VIEW, INDEX, ROLE, or SCHEMA after DROP", self.peek_token()); + return self.expected( + "TABLE, VIEW, INDEX, ROLE, or SCHEMA after DROP", + self.peek_token(), + ); }; // Many dialects support the non standard `IF EXISTS` clause and allow // specifying multiple objects to delete in a single statement diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 804855ba2..e06a43064 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -31,7 +31,8 @@ use sqlparser::keywords::ALL_KEYWORDS; use sqlparser::parser::{Parser, ParserError}; use test_utils::{ - all_dialects, assert_eq_vec, expr_from_projection, join, number, only, table, table_alias, TestedDialects, + all_dialects, assert_eq_vec, expr_from_projection, join, number, only, table, table_alias, + TestedDialects, }; #[test] @@ -4767,13 +4768,10 @@ fn parse_drop_index() { fn parse_create_role() { let sql = "CREATE ROLE consultant"; match verified_stmt(sql) { - Statement::CreateRole { - names, - .. - } => { + Statement::CreateRole { names, .. } => { assert_eq_vec(&["consultant"], &names); - }, - _ => unreachable!() + } + _ => unreachable!(), } let sql = "CREATE ROLE IF NOT EXISTS mysql_a, mysql_b"; @@ -4785,8 +4783,8 @@ fn parse_create_role() { } => { assert_eq_vec(&["mysql_a", "mysql_b"], &names); assert_eq!(if_not_exists, true); - }, - _ => unreachable!() + } + _ => unreachable!(), } } @@ -4794,26 +4792,35 @@ fn parse_create_role() { fn parse_drop_role() { let sql = "DROP ROLE abc"; match verified_stmt(sql) { - Statement::Drop { names, object_type, if_exists, .. } => { + Statement::Drop { + names, + object_type, + if_exists, + .. + } => { assert_eq_vec(&["abc"], &names); assert_eq!(ObjectType::Role, object_type); assert_eq!(if_exists, false); } - _ => unreachable!() + _ => unreachable!(), }; let sql = "DROP ROLE IF EXISTS def, magician, quaternion"; match verified_stmt(sql) { - Statement::Drop { names, object_type, if_exists, .. } => { + Statement::Drop { + names, + object_type, + if_exists, + .. + } => { assert_eq_vec(&["def", "magician", "quaternion"], &names); assert_eq!(ObjectType::Role, object_type); assert_eq!(if_exists, true); } - _ => unreachable!() + _ => unreachable!(), } } - #[test] fn parse_grant() { let sql = "GRANT SELECT, INSERT, UPDATE (shape, size), USAGE, DELETE, TRUNCATE, REFERENCES, TRIGGER, CONNECT, CREATE, EXECUTE, TEMPORARY ON abc, def TO xyz, m WITH GRANT OPTION GRANTED BY jj"; diff --git a/tests/sqlparser_mssql.rs b/tests/sqlparser_mssql.rs index 9548ee355..de2376f92 100644 --- a/tests/sqlparser_mssql.rs +++ b/tests/sqlparser_mssql.rs @@ -128,9 +128,15 @@ fn parse_mssql_create_role() { .. } => { assert_eq_vec(&["mssql"], &names); - assert_eq!(authorization_owner, Some(ObjectName(vec![Ident { value: "helena".into(), quote_style: None }]))); - }, - _ => unreachable!() + assert_eq!( + authorization_owner, + Some(ObjectName(vec![Ident { + value: "helena".into(), + quote_style: None + }])) + ); + } + _ => unreachable!(), } } diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index fd4f491bf..f51a72d52 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -1751,67 +1751,87 @@ fn parse_create_role() { } => { assert_eq_vec(&["mysql_a", "mysql_b"], &names); assert_eq!(if_not_exists, true); - }, - _ => unreachable!() + } + _ => unreachable!(), } let sql = "CREATE ROLE abc LOGIN PASSWORD NULL"; match pg().parse_sql_statements(sql).as_deref() { - Ok([Statement::CreateRole { - names, - login, - password, - .. - }]) => { + Ok( + [Statement::CreateRole { + names, + login, + password, + .. + }], + ) => { assert_eq_vec(&["abc"], names); assert_eq!(*login, Some(true)); assert_eq!(*password, Some(Password::NullPassword)); - }, - err => panic!("Failed to parse CREATE ROLE test case: {:?}", err) + } + err => panic!("Failed to parse CREATE ROLE test case: {:?}", err), } let sql = "CREATE ROLE magician WITH SUPERUSER CREATEROLE NOCREATEDB BYPASSRLS INHERIT PASSWORD 'abcdef' LOGIN VALID UNTIL '2025-01-01' IN ROLE role1, role2 ROLE role3 ADMIN role4, role5 REPLICATION"; // Roundtrip order of optional parameters is not preserved match pg().parse_sql_statements(sql).as_deref() { - Ok([Statement::CreateRole { - names, - if_not_exists, - bypassrls, - login, - inherit, - password, - superuser, - create_db, - create_role, - replication, - connection_limit, - valid_until, - in_role, - role, - admin, - authorization_owner, - }]) => { + Ok( + [Statement::CreateRole { + names, + if_not_exists, + bypassrls, + login, + inherit, + password, + superuser, + create_db, + create_role, + replication, + connection_limit, + valid_until, + in_role, + role, + admin, + authorization_owner, + }], + ) => { assert_eq_vec(&["magician"], names); assert_eq!(*if_not_exists, false); assert_eq!(*login, Some(true)); assert_eq!(*inherit, Some(true)); assert_eq!(*bypassrls, Some(true)); - assert_eq!(*password, Some(Password::Password(Expr::Value(Value::SingleQuotedString("abcdef".into()))))); + assert_eq!( + *password, + Some(Password::Password(Expr::Value(Value::SingleQuotedString( + "abcdef".into() + )))) + ); assert_eq!(*superuser, Some(true)); assert_eq!(*create_db, Some(false)); assert_eq!(*create_role, Some(true)); assert_eq!(*replication, Some(true)); assert_eq!(*connection_limit, None); - assert_eq!(*valid_until, Some(Expr::Value(Value::SingleQuotedString("2025-01-01".into())))); + assert_eq!( + *valid_until, + Some(Expr::Value(Value::SingleQuotedString("2025-01-01".into()))) + ); assert_eq_vec(&["role1", "role2"], in_role); assert_eq_vec(&["role3"], role); assert_eq_vec(&["role4", "role5"], admin); assert_eq!(*authorization_owner, None); - }, - err => panic!("Failed to parse CREATE ROLE test case: {:?}", err) + } + err => panic!("Failed to parse CREATE ROLE test case: {:?}", err), } - let negatables = vec!["BYPASSRLS", "CREATEDB", "CREATEROLE", "INHERIT", "LOGIN", "REPLICATION", "SUPERUSER"]; + let negatables = vec![ + "BYPASSRLS", + "CREATEDB", + "CREATEROLE", + "INHERIT", + "LOGIN", + "REPLICATION", + "SUPERUSER", + ]; for negatable_kw in negatables.iter() { let sql = format!("CREATE ROLE abc {kw} NO{kw}", kw = negatable_kw); From f14e138578622629fb5133fbb2d9530709cf7a7a Mon Sep 17 00:00:00 2001 From: Ben Cook Date: Wed, 31 Aug 2022 23:50:06 -0700 Subject: [PATCH 4/6] clippy --- src/test_utils.rs | 2 +- tests/sqlparser_common.rs | 6 +++--- tests/sqlparser_postgres.rs | 9 ++++----- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/src/test_utils.rs b/src/test_utils.rs index d948bc2ed..c3d60ee62 100644 --- a/src/test_utils.rs +++ b/src/test_utils.rs @@ -146,7 +146,7 @@ pub fn all_dialects() -> TestedDialects { } } -pub fn assert_eq_vec(expected: &[&str], actual: &Vec) { +pub fn assert_eq_vec(expected: &[&str], actual: &[T]) { assert_eq!( expected, actual.iter().map(ToString::to_string).collect::>() diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index e06a43064..87a089c1b 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -4782,7 +4782,7 @@ fn parse_create_role() { .. } => { assert_eq_vec(&["mysql_a", "mysql_b"], &names); - assert_eq!(if_not_exists, true); + assert!(if_not_exists); } _ => unreachable!(), } @@ -4800,7 +4800,7 @@ fn parse_drop_role() { } => { assert_eq_vec(&["abc"], &names); assert_eq!(ObjectType::Role, object_type); - assert_eq!(if_exists, false); + assert!(!if_exists); } _ => unreachable!(), }; @@ -4815,7 +4815,7 @@ fn parse_drop_role() { } => { assert_eq_vec(&["def", "magician", "quaternion"], &names); assert_eq!(ObjectType::Role, object_type); - assert_eq!(if_exists, true); + assert!(if_exists); } _ => unreachable!(), } diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index f51a72d52..ecc41a4d3 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -1750,7 +1750,7 @@ fn parse_create_role() { .. } => { assert_eq_vec(&["mysql_a", "mysql_b"], &names); - assert_eq!(if_not_exists, true); + assert!(if_not_exists); } _ => unreachable!(), } @@ -1796,7 +1796,7 @@ fn parse_create_role() { }], ) => { assert_eq_vec(&["magician"], names); - assert_eq!(*if_not_exists, false); + assert!(!*if_not_exists); assert_eq!(*login, Some(true)); assert_eq!(*inherit, Some(true)); assert_eq!(*bypassrls, Some(true)); @@ -1835,9 +1835,8 @@ fn parse_create_role() { for negatable_kw in negatables.iter() { let sql = format!("CREATE ROLE abc {kw} NO{kw}", kw = negatable_kw); - match pg().parse_sql_statements(&sql) { - Ok(_) => panic!("Should not be able to parse CREATE ROLE containing both negated and non-negated versions of the same keyword: {}", negatable_kw), - _ => () + if pg().parse_sql_statements(&sql).is_ok() { + panic!("Should not be able to parse CREATE ROLE containing both negated and non-negated versions of the same keyword: {}", negatable_kw) } } } From 1cae696e098be5382752b3901c63392c14926f26 Mon Sep 17 00:00:00 2001 From: Ben Cook Date: Thu, 1 Sep 2022 00:01:00 -0700 Subject: [PATCH 5/6] no-std --- src/ast/mod.rs | 140 +++++++++++++++++++++++-------------------------- 1 file changed, 67 insertions(+), 73 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index e595d8788..e96d18378 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1935,79 +1935,73 @@ impl fmt::Display for Statement { role, admin, authorization_owner, - } => write!( - f, - "CREATE ROLE {if_not_exists}{names}{superuser}{create_db}{create_role}{inherit}{login}{replication}{bypassrls}{connection_limit}{password}{valid_until}{in_role}{role}{admin}{authorization_owner}", - 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 => "" - }, - connection_limit = match &*connection_limit { - Some(limit) => format!(" CONNECTION LIMIT {}", limit), - None => "".to_string(), - }, - password = match &*password { - Some(Password::Password(pass)) => format!(" PASSWORD {}", pass), - Some(Password::NullPassword) => " PASSWORD NULL".to_string(), - None => "".to_string(), - }, - valid_until = match &*valid_until { - Some(until) => format!(" VALID UNTIL {}", until), - None => "".to_string(), - }, - in_role = if in_role.is_empty() { - "".into() - } else { - format!(" IN ROLE {}", display_comma_separated(in_role)) - }, - role = if role.is_empty() { - "".into() - } else { - format!(" ROLE {}", display_comma_separated(role)) - }, - admin = if admin.is_empty() { - "".into() - } else { - format!(" ADMIN {}", display_comma_separated(admin)) - }, - authorization_owner = match &*authorization_owner { - Some(owner) => format!(" AUTHORIZATION {}", owner), - None => "".to_string() - }, - ), + } => { + 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) } From 3a38d6dfa138bdf3481c97e7269106690f3e551f Mon Sep 17 00:00:00 2001 From: Ben Cook Date: Thu, 1 Sep 2022 00:05:36 -0700 Subject: [PATCH 6/6] clippy again --- src/ast/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ast/mod.rs b/src/ast/mod.rs index e96d18378..4efc797d1 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -1977,10 +1977,10 @@ impl fmt::Display for Statement { None => "" } )?; - if let Some(limit) = &*connection_limit { + if let Some(limit) = connection_limit { write!(f, " CONNECTION LIMIT {}", limit)?; } - match &*password { + match password { Some(Password::Password(pass)) => write!(f, " PASSWORD {}", pass), Some(Password::NullPassword) => write!(f, " PASSWORD NULL"), None => Ok(()),