@@ -271,6 +271,22 @@ impl ParserOptions {
271271 self.unescape = unescape;
272272 self
273273 }
274+
275+ /// Set if semicolon statement delimiters are required.
276+ ///
277+ /// If this option is `true`, the following SQL will not parse. If the option is `false`, the SQL will parse.
278+ ///
279+ /// ```sql
280+ /// SELECT 1
281+ /// SELECT 2
282+ /// ```
283+ pub fn with_require_semicolon_stmt_delimiter(
284+ mut self,
285+ require_semicolon_stmt_delimiter: bool,
286+ ) -> Self {
287+ self.require_semicolon_stmt_delimiter = require_semicolon_stmt_delimiter;
288+ self
289+ }
274290}
275291
276292#[derive(Copy, Clone)]
@@ -367,7 +383,11 @@ impl<'a> Parser<'a> {
367383 state: ParserState::Normal,
368384 dialect,
369385 recursion_counter: RecursionCounter::new(DEFAULT_REMAINING_DEPTH),
370- options: ParserOptions::new().with_trailing_commas(dialect.supports_trailing_commas()),
386+ options: ParserOptions::new()
387+ .with_trailing_commas(dialect.supports_trailing_commas())
388+ .with_require_semicolon_stmt_delimiter(
389+ !dialect.supports_statements_without_semicolon_delimiter(),
390+ ),
371391 }
372392 }
373393
@@ -489,13 +509,18 @@ impl<'a> Parser<'a> {
489509
490510 match self.peek_token().token {
491511 Token::EOF => break,
492-
493512 // end of statement
494513 Token::Word(word) => {
495514 if expecting_statement_delimiter && word.keyword == Keyword::END {
496515 break;
497516 }
498517 }
518+ // don't expect a semicolon statement delimiter after a newline when not otherwise required
519+ Token::Whitespace(Whitespace::Newline) => {
520+ if !self.options.require_semicolon_stmt_delimiter {
521+ expecting_statement_delimiter = false;
522+ }
523+ }
499524 _ => {}
500525 }
501526
@@ -505,7 +530,7 @@ impl<'a> Parser<'a> {
505530
506531 let statement = self.parse_statement()?;
507532 stmts.push(statement);
508- expecting_statement_delimiter = true ;
533+ expecting_statement_delimiter = self.options.require_semicolon_stmt_delimiter ;
509534 }
510535 Ok(stmts)
511536 }
@@ -4615,6 +4640,14 @@ impl<'a> Parser<'a> {
46154640 return Ok(vec![]);
46164641 }
46174642
4643+ if end_token == Token::SemiColon && !self.options.require_semicolon_stmt_delimiter {
4644+ if let Token::Word(ref kw) = self.peek_token().token {
4645+ if kw.keyword != Keyword::NoKeyword {
4646+ return Ok(vec![]);
4647+ }
4648+ }
4649+ }
4650+
46184651 if self.options.trailing_commas && self.peek_tokens() == [Token::Comma, end_token] {
46194652 let _ = self.consume_token(&Token::Comma);
46204653 return Ok(vec![]);
@@ -4632,6 +4665,9 @@ impl<'a> Parser<'a> {
46324665 ) -> Result<Vec<Statement>, ParserError> {
46334666 let mut values = vec![];
46344667 loop {
4668+ // ignore empty statements (between successive statement delimiters)
4669+ while self.consume_token(&Token::SemiColon) {}
4670+
46354671 match &self.peek_nth_token_ref(0).token {
46364672 Token::EOF => break,
46374673 Token::Word(w) => {
@@ -4643,7 +4679,13 @@ impl<'a> Parser<'a> {
46434679 }
46444680
46454681 values.push(self.parse_statement()?);
4646- self.expect_token(&Token::SemiColon)?;
4682+
4683+ if self.options.require_semicolon_stmt_delimiter {
4684+ self.expect_token(&Token::SemiColon)?;
4685+ }
4686+
4687+ // ignore empty statements (between successive statement delimiters)
4688+ while self.consume_token(&Token::SemiColon) {}
46474689 }
46484690 Ok(values)
46494691 }
@@ -17271,7 +17313,28 @@ impl<'a> Parser<'a> {
1727117313
1727217314 /// Parse [Statement::Return]
1727317315 fn parse_return(&mut self) -> Result<Statement, ParserError> {
17274- match self.maybe_parse(|p| p.parse_expr())? {
17316+ let rs = self.maybe_parse(|p| {
17317+ let expr = p.parse_expr()?;
17318+
17319+ match &expr {
17320+ Expr::Value(_)
17321+ | Expr::Function(_)
17322+ | Expr::UnaryOp { .. }
17323+ | Expr::BinaryOp { .. }
17324+ | Expr::Case { .. }
17325+ | Expr::Cast { .. }
17326+ | Expr::Convert { .. }
17327+ | Expr::Subquery(_) => Ok(expr),
17328+ // todo: how to retstrict to variables?
17329+ Expr::Identifier(id) if id.value.starts_with('@') => Ok(expr),
17330+ _ => parser_err!(
17331+ "Non-returnable expression found following RETURN",
17332+ p.peek_token().span.start
17333+ ),
17334+ }
17335+ })?;
17336+
17337+ match rs {
1727517338 Some(expr) => Ok(Statement::Return(ReturnStatement {
1727617339 value: Some(ReturnStatementValue::Expr(expr)),
1727717340 })),
0 commit comments