@@ -265,6 +265,22 @@ impl ParserOptions {
265265 self.unescape = unescape;
266266 self
267267 }
268+
269+ /// Set if semicolon statement delimiters are required.
270+ ///
271+ /// If this option is `true`, the following SQL will not parse. If the option is `false`, the SQL will parse.
272+ ///
273+ /// ```sql
274+ /// SELECT 1
275+ /// SELECT 2
276+ /// ```
277+ pub fn with_require_semicolon_stmt_delimiter(
278+ mut self,
279+ require_semicolon_stmt_delimiter: bool,
280+ ) -> Self {
281+ self.require_semicolon_stmt_delimiter = require_semicolon_stmt_delimiter;
282+ self
283+ }
268284}
269285
270286#[derive(Copy, Clone)]
@@ -355,7 +371,11 @@ impl<'a> Parser<'a> {
355371 state: ParserState::Normal,
356372 dialect,
357373 recursion_counter: RecursionCounter::new(DEFAULT_REMAINING_DEPTH),
358- options: ParserOptions::new().with_trailing_commas(dialect.supports_trailing_commas()),
374+ options: ParserOptions::new()
375+ .with_trailing_commas(dialect.supports_trailing_commas())
376+ .with_require_semicolon_stmt_delimiter(
377+ !dialect.supports_statements_without_semicolon_delimiter(),
378+ ),
359379 }
360380 }
361381
@@ -478,10 +498,10 @@ impl<'a> Parser<'a> {
478498 match self.peek_token().token {
479499 Token::EOF => break,
480500
481- // end of statement
482- Token::Word(word ) => {
483- if expecting_statement_delimiter && word.keyword == Keyword::END {
484- break ;
501+ // don't expect a semicolon statement delimiter after a newline when not otherwise required
502+ Token::Whitespace(Whitespace::Newline ) => {
503+ if !self.options.require_semicolon_stmt_delimiter {
504+ expecting_statement_delimiter = false ;
485505 }
486506 }
487507 _ => {}
@@ -493,7 +513,7 @@ impl<'a> Parser<'a> {
493513
494514 let statement = self.parse_statement()?;
495515 stmts.push(statement);
496- expecting_statement_delimiter = true ;
516+ expecting_statement_delimiter = self.options.require_semicolon_stmt_delimiter ;
497517 }
498518 Ok(stmts)
499519 }
@@ -4516,6 +4536,18 @@ impl<'a> Parser<'a> {
45164536 return Ok(vec![]);
45174537 }
45184538
4539+ if end_token == Token::SemiColon
4540+ && self
4541+ .dialect
4542+ .supports_statements_without_semicolon_delimiter()
4543+ {
4544+ if let Token::Word(ref kw) = self.peek_token().token {
4545+ if kw.keyword != Keyword::NoKeyword {
4546+ return Ok(vec![]);
4547+ }
4548+ }
4549+ }
4550+
45194551 if self.options.trailing_commas && self.peek_tokens() == [Token::Comma, end_token] {
45204552 let _ = self.consume_token(&Token::Comma);
45214553 return Ok(vec![]);
@@ -4533,6 +4565,9 @@ impl<'a> Parser<'a> {
45334565 ) -> Result<Vec<Statement>, ParserError> {
45344566 let mut values = vec![];
45354567 loop {
4568+ // ignore empty statements (between successive statement delimiters)
4569+ while self.consume_token(&Token::SemiColon) {}
4570+
45364571 match &self.peek_nth_token_ref(0).token {
45374572 Token::EOF => break,
45384573 Token::Word(w) => {
@@ -4544,7 +4579,13 @@ impl<'a> Parser<'a> {
45444579 }
45454580
45464581 values.push(self.parse_statement()?);
4547- self.expect_token(&Token::SemiColon)?;
4582+
4583+ if self.options.require_semicolon_stmt_delimiter {
4584+ self.expect_token(&Token::SemiColon)?;
4585+ }
4586+
4587+ // ignore empty statements (between successive statement delimiters)
4588+ while self.consume_token(&Token::SemiColon) {}
45484589 }
45494590 Ok(values)
45504591 }
@@ -16370,7 +16411,28 @@ impl<'a> Parser<'a> {
1637016411
1637116412 /// Parse [Statement::Return]
1637216413 fn parse_return(&mut self) -> Result<Statement, ParserError> {
16373- match self.maybe_parse(|p| p.parse_expr())? {
16414+ let rs = self.maybe_parse(|p| {
16415+ let expr = p.parse_expr()?;
16416+
16417+ match &expr {
16418+ Expr::Value(_)
16419+ | Expr::Function(_)
16420+ | Expr::UnaryOp { .. }
16421+ | Expr::BinaryOp { .. }
16422+ | Expr::Case { .. }
16423+ | Expr::Cast { .. }
16424+ | Expr::Convert { .. }
16425+ | Expr::Subquery(_) => Ok(expr),
16426+ // todo: how to retstrict to variables?
16427+ Expr::Identifier(id) if id.value.starts_with('@') => Ok(expr),
16428+ _ => parser_err!(
16429+ "Non-returnable expression found following RETURN",
16430+ p.peek_token().span.start
16431+ ),
16432+ }
16433+ })?;
16434+
16435+ match rs {
1637416436 Some(expr) => Ok(Statement::Return(ReturnStatement {
1637516437 value: Some(ReturnStatementValue::Expr(expr)),
1637616438 })),
0 commit comments