From ce13652be79e7064129bc84d8f92b3b8c2841454 Mon Sep 17 00:00:00 2001 From: LucaCappelletti94 Date: Tue, 27 Oct 2026 09:36:01 +0100 Subject: [PATCH 1/2] PostgreSQL: Accept a signed CONNECTION LIMIT in CREATE ROLE and ALTER ROLE --- src/parser/alter.rs | 2 +- src/parser/mod.rs | 2 +- tests/sqlparser_postgres.rs | 43 +++++++++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 2 deletions(-) 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" + ); +} From 4345af134228273ad706e95235dd3de7a309583b Mon Sep 17 00:00:00 2001 From: LucaCappelletti94 Date: Tue, 27 Oct 2026 09:47:55 +0100 Subject: [PATCH 2/2] Add fuzz seed for signed CONNECTION LIMIT --- fuzz/fuzz_seeds/postgres_2731_signed_connection_limit.sql | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 fuzz/fuzz_seeds/postgres_2731_signed_connection_limit.sql 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