diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 745478300..d36e1adcd 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -20811,7 +20811,11 @@ impl<'a> Parser<'a> { return self.expected_ref(" another option or EOF", self.peek_token_ref()); } } - Token::EOF | Token::SemiColon => break, + Token::EOF => break, + Token::SemiColon => { + self.prev_token(); + break; + } Token::Comma => { delimiter = KeyValueOptionsDelimiter::Comma; continue; diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index b48b1b5a0..be3026f63 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -18286,6 +18286,22 @@ fn parse_create_user() { } } +#[test] +fn key_value_option_statements_do_not_swallow_following_statement() { + // An unparenthesized key-value option list must not swallow the statement + // terminator, otherwise any following statement fails to parse. This covers + // every unparenthesized caller of `parse_key_value_options`: `CREATE USER` + // and both `ALTER USER ... SET` forms. + for sql in [ + "CREATE USER user1; SELECT 1", + "ALTER USER user1 SET x = 'y'; SELECT 1", + "ALTER USER user1 SET TAG t = 'v'; SELECT 1", + ] { + let statements = all_dialects().parse_sql_statements(sql).unwrap(); + assert_eq!(statements.len(), 2, "{sql}"); + } +} + #[test] fn parse_drop_stream() { let sql = "DROP STREAM s1";