diff --git a/fuzz/fuzz_seeds/postgres_2731_signed_connection_limit.sql b/fuzz/fuzz_seeds/postgres_2731_signed_connection_limit.sql new file mode 100644 index 0000000000..79b5b43e10 --- /dev/null +++ b/fuzz/fuzz_seeds/postgres_2731_signed_connection_limit.sql @@ -0,0 +1,2 @@ +CREATE ROLE a CONNECTION LIMIT -1; +ALTER ROLE a CONNECTION LIMIT -1 diff --git a/src/parser/alter.rs b/src/parser/alter.rs index 047023b893..0396ed871a 100644 --- a/src/parser/alter.rs +++ b/src/parser/alter.rs @@ -523,7 +523,7 @@ impl Parser<'_> { Some(Keyword::NOBYPASSRLS) => RoleOption::BypassRLS(false), Some(Keyword::CONNECTION) => { self.expect_keyword_is(Keyword::LIMIT)?; - RoleOption::ConnectionLimit(Expr::Value(self.parse_number_value()?)) + RoleOption::ConnectionLimit(self.parse_number()?) } Some(Keyword::CREATEDB) => RoleOption::CreateDB(true), Some(Keyword::NOCREATEDB) => RoleOption::CreateDB(false), diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 0b31e49907..7a980ca0b6 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -7227,7 +7227,7 @@ impl<'a> Parser<'a> { if connection_limit.is_some() { parser_err!("Found multiple CONNECTION LIMIT", loc) } else { - connection_limit = Some(Expr::Value(self.parse_number_value()?)); + connection_limit = Some(self.parse_number()?); Ok(()) } } diff --git a/tests/sqlparser_postgres.rs b/tests/sqlparser_postgres.rs index e882668378..11a4703f55 100644 --- a/tests/sqlparser_postgres.rs +++ b/tests/sqlparser_postgres.rs @@ -11014,3 +11014,46 @@ fn parse_alter_operator_family_order_by_followed_by_search() { ] ); } + +#[test] +fn parse_role_signed_connection_limit() { + let minus_one = Expr::UnaryOp { + op: UnaryOperator::Minus, + expr: Box::new(Expr::value(number("1"))), + }; + + match pg().verified_stmt("CREATE ROLE a CONNECTION LIMIT -1") { + Statement::CreateRole(create_role) => { + assert_eq!(create_role.connection_limit.as_ref(), Some(&minus_one)); + } + _ => unreachable!(), + } + pg().verified_stmt("CREATE ROLE a CONNECTION LIMIT +5"); + + assert_eq!( + pg().one_statement_parses_to( + "ALTER ROLE a CONNECTION LIMIT -1", + "ALTER ROLE a WITH CONNECTION LIMIT -1", + ), + Statement::AlterRole { + name: Ident::new("a"), + operation: AlterRoleOperation::WithOptions { + options: vec![RoleOption::ConnectionLimit(minus_one)], + }, + } + ); + pg().verified_stmt("ALTER ROLE a WITH CONNECTION LIMIT +5"); + + assert_eq!( + pg().parse_sql_statements("CREATE ROLE a CONNECTION LIMIT -'x'") + .unwrap_err() + .to_string(), + "sql parser error: Expected: literal number, found: 'x'" + ); + assert_eq!( + pg().parse_sql_statements("ALTER ROLE a CONNECTION LIMIT -'x'") + .unwrap_err() + .to_string(), + "sql parser error: Expected: option, found: CONNECTION" + ); +}