@@ -288,6 +288,22 @@ impl ParserOptions {
288288 self.unescape = unescape;
289289 self
290290 }
291+
292+ /// Set if semicolon statement delimiters are required.
293+ ///
294+ /// If this option is `true`, the following SQL will not parse. If the option is `false`, the SQL will parse.
295+ ///
296+ /// ```sql
297+ /// SELECT 1
298+ /// SELECT 2
299+ /// ```
300+ pub fn with_require_semicolon_stmt_delimiter(
301+ mut self,
302+ require_semicolon_stmt_delimiter: bool,
303+ ) -> Self {
304+ self.require_semicolon_stmt_delimiter = require_semicolon_stmt_delimiter;
305+ self
306+ }
291307}
292308
293309#[derive(Copy, Clone)]
@@ -384,7 +400,11 @@ impl<'a> Parser<'a> {
384400 state: ParserState::Normal,
385401 dialect,
386402 recursion_counter: RecursionCounter::new(DEFAULT_REMAINING_DEPTH),
387- options: ParserOptions::new().with_trailing_commas(dialect.supports_trailing_commas()),
403+ options: ParserOptions::new()
404+ .with_trailing_commas(dialect.supports_trailing_commas())
405+ .with_require_semicolon_stmt_delimiter(
406+ !dialect.supports_statements_without_semicolon_delimiter(),
407+ ),
388408 }
389409 }
390410
@@ -506,13 +526,18 @@ impl<'a> Parser<'a> {
506526
507527 match &self.peek_token_ref().token {
508528 Token::EOF => break,
509-
510529 // end of statement
511530 Token::Word(word) => {
512531 if expecting_statement_delimiter && word.keyword == Keyword::END {
513532 break;
514533 }
515534 }
535+ // don't expect a semicolon statement delimiter after a newline when not otherwise required
536+ Token::Whitespace(Whitespace::Newline) => {
537+ if !self.options.require_semicolon_stmt_delimiter {
538+ expecting_statement_delimiter = false;
539+ }
540+ }
516541 _ => {}
517542 }
518543
@@ -522,7 +547,7 @@ impl<'a> Parser<'a> {
522547
523548 let statement = self.parse_statement()?;
524549 stmts.push(statement);
525- expecting_statement_delimiter = true ;
550+ expecting_statement_delimiter = self.options.require_semicolon_stmt_delimiter ;
526551 }
527552 Ok(stmts)
528553 }
@@ -4970,6 +4995,14 @@ impl<'a> Parser<'a> {
49704995 return Ok(vec![]);
49714996 }
49724997
4998+ if end_token == Token::SemiColon && !self.options.require_semicolon_stmt_delimiter {
4999+ if let Token::Word(ref kw) = self.peek_token().token {
5000+ if kw.keyword != Keyword::NoKeyword {
5001+ return Ok(vec![]);
5002+ }
5003+ }
5004+ }
5005+
49735006 if self.options.trailing_commas && self.peek_tokens() == [Token::Comma, end_token] {
49745007 let _ = self.consume_token(&Token::Comma);
49755008 return Ok(vec![]);
@@ -4987,6 +5020,9 @@ impl<'a> Parser<'a> {
49875020 ) -> Result<Vec<Statement>, ParserError> {
49885021 let mut values = vec![];
49895022 loop {
5023+ // ignore empty statements (between successive statement delimiters)
5024+ while self.consume_token(&Token::SemiColon) {}
5025+
49905026 match &self.peek_nth_token_ref(0).token {
49915027 Token::EOF => break,
49925028 Token::Word(w) => {
@@ -4998,7 +5034,13 @@ impl<'a> Parser<'a> {
49985034 }
49995035
50005036 values.push(self.parse_statement()?);
5001- self.expect_token(&Token::SemiColon)?;
5037+
5038+ if self.options.require_semicolon_stmt_delimiter {
5039+ self.expect_token(&Token::SemiColon)?;
5040+ }
5041+
5042+ // ignore empty statements (between successive statement delimiters)
5043+ while self.consume_token(&Token::SemiColon) {}
50025044 }
50035045 Ok(values)
50045046 }
@@ -19571,7 +19613,28 @@ impl<'a> Parser<'a> {
1957119613
1957219614 /// Parse [Statement::Return]
1957319615 fn parse_return(&mut self) -> Result<Statement, ParserError> {
19574- match self.maybe_parse(|p| p.parse_expr())? {
19616+ let rs = self.maybe_parse(|p| {
19617+ let expr = p.parse_expr()?;
19618+
19619+ match &expr {
19620+ Expr::Value(_)
19621+ | Expr::Function(_)
19622+ | Expr::UnaryOp { .. }
19623+ | Expr::BinaryOp { .. }
19624+ | Expr::Case { .. }
19625+ | Expr::Cast { .. }
19626+ | Expr::Convert { .. }
19627+ | Expr::Subquery(_) => Ok(expr),
19628+ // todo: how to restrict to variables?
19629+ Expr::Identifier(id) if id.value.starts_with('@') => Ok(expr),
19630+ _ => parser_err!(
19631+ "Non-returnable expression found following RETURN",
19632+ p.peek_token().span.start
19633+ ),
19634+ }
19635+ })?;
19636+
19637+ match rs {
1957519638 Some(expr) => Ok(Statement::Return(ReturnStatement {
1957619639 value: Some(ReturnStatementValue::Expr(expr)),
1957719640 })),
0 commit comments