@@ -266,6 +266,22 @@ impl ParserOptions {
266266 self.unescape = unescape;
267267 self
268268 }
269+
270+ /// Set if semicolon statement delimiters are required.
271+ ///
272+ /// If this option is `true`, the following SQL will not parse. If the option is `false`, the SQL will parse.
273+ ///
274+ /// ```sql
275+ /// SELECT 1
276+ /// SELECT 2
277+ /// ```
278+ pub fn with_require_semicolon_stmt_delimiter(
279+ mut self,
280+ require_semicolon_stmt_delimiter: bool,
281+ ) -> Self {
282+ self.require_semicolon_stmt_delimiter = require_semicolon_stmt_delimiter;
283+ self
284+ }
269285}
270286
271287#[derive(Copy, Clone)]
@@ -362,7 +378,11 @@ impl<'a> Parser<'a> {
362378 state: ParserState::Normal,
363379 dialect,
364380 recursion_counter: RecursionCounter::new(DEFAULT_REMAINING_DEPTH),
365- options: ParserOptions::new().with_trailing_commas(dialect.supports_trailing_commas()),
381+ options: ParserOptions::new()
382+ .with_trailing_commas(dialect.supports_trailing_commas())
383+ .with_require_semicolon_stmt_delimiter(
384+ !dialect.supports_statements_without_semicolon_delimiter(),
385+ ),
366386 }
367387 }
368388
@@ -485,10 +505,10 @@ impl<'a> Parser<'a> {
485505 match self.peek_token().token {
486506 Token::EOF => break,
487507
488- // end of statement
489- Token::Word(word ) => {
490- if expecting_statement_delimiter && word.keyword == Keyword::END {
491- break ;
508+ // don't expect a semicolon statement delimiter after a newline when not otherwise required
509+ Token::Whitespace(Whitespace::Newline ) => {
510+ if !self.options.require_semicolon_stmt_delimiter {
511+ expecting_statement_delimiter = false ;
492512 }
493513 }
494514 _ => {}
@@ -500,7 +520,7 @@ impl<'a> Parser<'a> {
500520
501521 let statement = self.parse_statement()?;
502522 stmts.push(statement);
503- expecting_statement_delimiter = true ;
523+ expecting_statement_delimiter = self.options.require_semicolon_stmt_delimiter ;
504524 }
505525 Ok(stmts)
506526 }
@@ -4541,6 +4561,18 @@ impl<'a> Parser<'a> {
45414561 return Ok(vec![]);
45424562 }
45434563
4564+ if end_token == Token::SemiColon
4565+ && self
4566+ .dialect
4567+ .supports_statements_without_semicolon_delimiter()
4568+ {
4569+ if let Token::Word(ref kw) = self.peek_token().token {
4570+ if kw.keyword != Keyword::NoKeyword {
4571+ return Ok(vec![]);
4572+ }
4573+ }
4574+ }
4575+
45444576 if self.options.trailing_commas && self.peek_tokens() == [Token::Comma, end_token] {
45454577 let _ = self.consume_token(&Token::Comma);
45464578 return Ok(vec![]);
@@ -4558,6 +4590,9 @@ impl<'a> Parser<'a> {
45584590 ) -> Result<Vec<Statement>, ParserError> {
45594591 let mut values = vec![];
45604592 loop {
4593+ // ignore empty statements (between successive statement delimiters)
4594+ while self.consume_token(&Token::SemiColon) {}
4595+
45614596 match &self.peek_nth_token_ref(0).token {
45624597 Token::EOF => break,
45634598 Token::Word(w) => {
@@ -4569,7 +4604,13 @@ impl<'a> Parser<'a> {
45694604 }
45704605
45714606 values.push(self.parse_statement()?);
4572- self.expect_token(&Token::SemiColon)?;
4607+
4608+ if self.options.require_semicolon_stmt_delimiter {
4609+ self.expect_token(&Token::SemiColon)?;
4610+ }
4611+
4612+ // ignore empty statements (between successive statement delimiters)
4613+ while self.consume_token(&Token::SemiColon) {}
45734614 }
45744615 Ok(values)
45754616 }
@@ -16464,7 +16505,28 @@ impl<'a> Parser<'a> {
1646416505
1646516506 /// Parse [Statement::Return]
1646616507 fn parse_return(&mut self) -> Result<Statement, ParserError> {
16467- match self.maybe_parse(|p| p.parse_expr())? {
16508+ let rs = self.maybe_parse(|p| {
16509+ let expr = p.parse_expr()?;
16510+
16511+ match &expr {
16512+ Expr::Value(_)
16513+ | Expr::Function(_)
16514+ | Expr::UnaryOp { .. }
16515+ | Expr::BinaryOp { .. }
16516+ | Expr::Case { .. }
16517+ | Expr::Cast { .. }
16518+ | Expr::Convert { .. }
16519+ | Expr::Subquery(_) => Ok(expr),
16520+ // todo: how to retstrict to variables?
16521+ Expr::Identifier(id) if id.value.starts_with('@') => Ok(expr),
16522+ _ => parser_err!(
16523+ "Non-returnable expression found following RETURN",
16524+ p.peek_token().span.start
16525+ ),
16526+ }
16527+ })?;
16528+
16529+ match rs {
1646816530 Some(expr) => Ok(Statement::Return(ReturnStatement {
1646916531 value: Some(ReturnStatementValue::Expr(expr)),
1647016532 })),
0 commit comments