@@ -4753,6 +4753,108 @@ fn parse_create_role() {
47534753 }
47544754}
47554755
4756+ #[ test]
4757+ fn parse_create_group ( ) {
4758+ // `GROUP` names the same object as `ROLE` in PostgreSQL, but the keyword is preserved.
4759+ pg ( ) . verified_stmt ( "CREATE GROUP g" ) ;
4760+ pg ( ) . verified_stmt ( "CREATE GROUP staff SUPERUSER LOGIN CONNECTION LIMIT 5 USER karl, john" ) ;
4761+ pg ( ) . one_statement_parses_to (
4762+ "CREATE GROUP staff WITH SUPERUSER" ,
4763+ "CREATE GROUP staff SUPERUSER" ,
4764+ ) ;
4765+
4766+ match pg ( ) . verified_stmt ( "CREATE GROUP staff" ) {
4767+ Statement :: CreateRole ( create_role) => {
4768+ assert_eq ! ( create_role. keyword, RoleKeyword :: Group ) ;
4769+ assert_eq_vec ( & [ "staff" ] , & create_role. names ) ;
4770+ }
4771+ other => panic ! ( "expected CREATE ROLE statement, got {other:?}" ) ,
4772+ }
4773+
4774+ // The `ROLE` spelling is unaffected.
4775+ match pg ( ) . verified_stmt ( "CREATE ROLE staff" ) {
4776+ Statement :: CreateRole ( create_role) => {
4777+ assert_eq ! ( create_role. keyword, RoleKeyword :: Role )
4778+ }
4779+ other => panic ! ( "expected CREATE ROLE statement, got {other:?}" ) ,
4780+ }
4781+
4782+ assert_eq ! (
4783+ pg( ) . parse_sql_statements( "CREATE GROUP IF NOT EXISTS g" ) ,
4784+ Err ( ParserError :: ParserError (
4785+ "IF NOT EXISTS is not supported for CREATE GROUP" . to_string( )
4786+ ) )
4787+ ) ;
4788+ pg ( ) . verified_stmt ( r#"CREATE GROUP "IF""# ) ;
4789+ }
4790+
4791+ #[ test]
4792+ fn parse_drop_group ( ) {
4793+ pg ( ) . verified_stmt ( "DROP GROUP IF EXISTS staff, workers" ) ;
4794+
4795+ assert_eq ! (
4796+ pg( ) . verified_stmt( "DROP GROUP staff" ) ,
4797+ Statement :: Drop {
4798+ object_type: ObjectType :: Group ,
4799+ if_exists: false ,
4800+ names: vec![ ObjectName :: from( vec![ Ident :: new( "staff" ) ] ) ] ,
4801+ cascade: false ,
4802+ restrict: false ,
4803+ purge: false ,
4804+ temporary: false ,
4805+ table: None ,
4806+ }
4807+ ) ;
4808+
4809+ // PostgreSQL rejects a drop behavior after `DROP GROUP`, exactly as after `DROP ROLE`.
4810+ assert_eq ! (
4811+ pg( ) . parse_sql_statements( "DROP GROUP staff CASCADE" )
4812+ . unwrap_err( )
4813+ . to_string( ) ,
4814+ "sql parser error: Cannot specify CASCADE, RESTRICT, or PURGE in DROP GROUP"
4815+ ) ;
4816+
4817+ pg ( ) . verified_stmt ( "DROP ROLE staff" ) ;
4818+ }
4819+
4820+ #[ test]
4821+ fn parse_user_group_statements_is_dialect_gated ( ) {
4822+ // Only PostgreSQL opts in. Redshift documents the same statements and can turn the hook
4823+ // on, but its narrower `CREATE GROUP` option list is a separate question.
4824+ let others = TestedDialects :: new ( vec ! [
4825+ Box :: new( GenericDialect { } ) ,
4826+ Box :: new( MySqlDialect { } ) ,
4827+ Box :: new( MsSqlDialect { } ) ,
4828+ ] ) ;
4829+ for ( sql, err) in [
4830+ (
4831+ "CREATE GROUP staff" ,
4832+ "Expected: an object type after CREATE, found: GROUP" ,
4833+ ) ,
4834+ (
4835+ "DROP GROUP staff" ,
4836+ "Expected: COLLATION, CONNECTOR, DATABASE, EXTENSION, FUNCTION, GROUP, INDEX, OPERATOR, POLICY, PROCEDURE, ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, VIEW, MATERIALIZED VIEW, USER or WAREHOUSE after DROP, found: GROUP" ,
4837+ ) ,
4838+ ] {
4839+ assert_eq ! (
4840+ others. parse_sql_statements( sql) ,
4841+ Err ( ParserError :: ParserError ( err. to_string( ) ) ) ,
4842+ "{sql}"
4843+ ) ;
4844+ }
4845+ }
4846+
4847+ #[ test]
4848+ fn parse_create_role_if_not_exists_rejected ( ) {
4849+ assert_eq ! (
4850+ pg( ) . parse_sql_statements( "CREATE ROLE IF NOT EXISTS r" ) ,
4851+ Err ( ParserError :: ParserError (
4852+ "IF NOT EXISTS is not supported for CREATE ROLE" . to_string( )
4853+ ) )
4854+ ) ;
4855+ pg ( ) . verified_stmt ( r#"CREATE ROLE "IF""# ) ;
4856+ }
4857+
47564858#[ test]
47574859fn parse_alter_role ( ) {
47584860 let sql = "ALTER ROLE old_name RENAME TO new_name" ;
@@ -10472,105 +10574,3 @@ fn parse_geometric_typed_literal_error_propagates() {
1047210574 ParserError :: ParserError ( "Expected: a value, found: (" . to_string( ) )
1047310575 ) ;
1047410576}
10475-
10476- #[ test]
10477- fn parse_create_group ( ) {
10478- // `GROUP` names the same object as `ROLE` in PostgreSQL, but the keyword is preserved.
10479- pg ( ) . verified_stmt ( "CREATE GROUP g" ) ;
10480- pg ( ) . verified_stmt ( "CREATE GROUP staff SUPERUSER LOGIN CONNECTION LIMIT 5 USER karl, john" ) ;
10481- pg ( ) . one_statement_parses_to (
10482- "CREATE GROUP staff WITH SUPERUSER" ,
10483- "CREATE GROUP staff SUPERUSER" ,
10484- ) ;
10485-
10486- match pg ( ) . verified_stmt ( "CREATE GROUP staff" ) {
10487- Statement :: CreateRole ( create_role) => {
10488- assert_eq ! ( create_role. keyword, RoleKeyword :: Group ) ;
10489- assert_eq_vec ( & [ "staff" ] , & create_role. names ) ;
10490- }
10491- other => panic ! ( "expected CREATE ROLE statement, got {other:?}" ) ,
10492- }
10493-
10494- // The `ROLE` spelling is unaffected.
10495- match pg ( ) . verified_stmt ( "CREATE ROLE staff" ) {
10496- Statement :: CreateRole ( create_role) => {
10497- assert_eq ! ( create_role. keyword, RoleKeyword :: Role )
10498- }
10499- other => panic ! ( "expected CREATE ROLE statement, got {other:?}" ) ,
10500- }
10501-
10502- assert_eq ! (
10503- pg( ) . parse_sql_statements( "CREATE GROUP IF NOT EXISTS g" ) ,
10504- Err ( ParserError :: ParserError (
10505- "IF NOT EXISTS is not supported for CREATE GROUP" . to_string( )
10506- ) )
10507- ) ;
10508- pg ( ) . verified_stmt ( r#"CREATE GROUP "IF""# ) ;
10509- }
10510-
10511- #[ test]
10512- fn parse_drop_group ( ) {
10513- pg ( ) . verified_stmt ( "DROP GROUP IF EXISTS staff, workers" ) ;
10514-
10515- assert_eq ! (
10516- pg( ) . verified_stmt( "DROP GROUP staff" ) ,
10517- Statement :: Drop {
10518- object_type: ObjectType :: Group ,
10519- if_exists: false ,
10520- names: vec![ ObjectName :: from( vec![ Ident :: new( "staff" ) ] ) ] ,
10521- cascade: false ,
10522- restrict: false ,
10523- purge: false ,
10524- temporary: false ,
10525- table: None ,
10526- }
10527- ) ;
10528-
10529- // PostgreSQL rejects a drop behavior after `DROP GROUP`, exactly as after `DROP ROLE`.
10530- assert_eq ! (
10531- pg( ) . parse_sql_statements( "DROP GROUP staff CASCADE" )
10532- . unwrap_err( )
10533- . to_string( ) ,
10534- "sql parser error: Cannot specify CASCADE, RESTRICT, or PURGE in DROP GROUP"
10535- ) ;
10536-
10537- pg ( ) . verified_stmt ( "DROP ROLE staff" ) ;
10538- }
10539-
10540- #[ test]
10541- fn parse_user_group_statements_is_dialect_gated ( ) {
10542- // Only PostgreSQL opts in. Redshift documents the same statements and can turn the hook
10543- // on, but its narrower `CREATE GROUP` option list is a separate question.
10544- let others = TestedDialects :: new ( vec ! [
10545- Box :: new( GenericDialect { } ) ,
10546- Box :: new( MySqlDialect { } ) ,
10547- Box :: new( MsSqlDialect { } ) ,
10548- ] ) ;
10549- for ( sql, err) in [
10550- (
10551- "CREATE GROUP staff" ,
10552- "Expected: an object type after CREATE, found: GROUP" ,
10553- ) ,
10554- (
10555- "DROP GROUP staff" ,
10556- "Expected: COLLATION, CONNECTOR, DATABASE, EXTENSION, FUNCTION, GROUP, INDEX, OPERATOR, POLICY, PROCEDURE, ROLE, SCHEMA, SECRET, SEQUENCE, STAGE, TABLE, TRIGGER, TYPE, VIEW, MATERIALIZED VIEW, USER or WAREHOUSE after DROP, found: GROUP" ,
10557- ) ,
10558- ] {
10559- assert_eq ! (
10560- others. parse_sql_statements( sql) ,
10561- Err ( ParserError :: ParserError ( err. to_string( ) ) ) ,
10562- "{sql}"
10563- ) ;
10564- }
10565- }
10566-
10567- #[ test]
10568- fn parse_create_role_if_not_exists_rejected ( ) {
10569- assert_eq ! (
10570- pg( ) . parse_sql_statements( "CREATE ROLE IF NOT EXISTS r" ) ,
10571- Err ( ParserError :: ParserError (
10572- "IF NOT EXISTS is not supported for CREATE ROLE" . to_string( )
10573- ) )
10574- ) ;
10575- pg ( ) . verified_stmt ( r#"CREATE ROLE "IF""# ) ;
10576- }
0 commit comments