@@ -475,6 +475,12 @@ impl<'a> Parser<'a> {
475475 if expecting_statement_delimiter && word.keyword == Keyword::END {
476476 break;
477477 }
478+ // Treat batch delimiter as an end of statement
479+ if expecting_statement_delimiter && dialect_of!(self is MsSqlDialect) {
480+ if let Some(Statement::Go(GoStatement { count: _ })) = stmts.last() {
481+ expecting_statement_delimiter = false;
482+ }
483+ }
478484 }
479485 _ => {}
480486 }
@@ -617,6 +623,7 @@ impl<'a> Parser<'a> {
617623 }
618624 // `COMMENT` is snowflake specific https://docs.snowflake.com/en/sql-reference/sql/comment
619625 Keyword::COMMENT if self.dialect.supports_comment_on() => self.parse_comment(),
626+ Keyword::GO => self.parse_go(),
620627 _ => self.expected("an SQL statement", next_token),
621628 },
622629 Token::LParen => {
@@ -15017,6 +15024,49 @@ impl<'a> Parser<'a> {
1501715024 }
1501815025 }
1501915026
15027+ /// Parse [Statement::Go]
15028+ fn parse_go(&mut self) -> Result<Statement, ParserError> {
15029+ // previous token should be a newline (skipping non-newline whitespace)
15030+ // see also, `previous_token`
15031+ let mut look_back_count = 2;
15032+ loop {
15033+ let prev_token = self.token_at(self.index.saturating_sub(look_back_count));
15034+ match prev_token.token {
15035+ Token::Whitespace(ref w) => match w {
15036+ Whitespace::Newline => break,
15037+ _ => look_back_count += 1,
15038+ },
15039+ _ => self.expected("newline before GO", prev_token.clone())?,
15040+ };
15041+ }
15042+
15043+ let count = loop {
15044+ // using this peek function because we want to halt this statement parsing upon newline
15045+ let next_token = self.peek_token_no_skip();
15046+ match next_token.token {
15047+ Token::EOF => break None::<u64>,
15048+ Token::Whitespace(ref w) => match w {
15049+ Whitespace::Newline => break None,
15050+ _ => _ = self.next_token_no_skip(),
15051+ },
15052+ Token::Number(s, _) => {
15053+ let value = Some(Self::parse::<u64>(s, next_token.span.start)?);
15054+ self.advance_token();
15055+ break value;
15056+ },
15057+ _ => self.expected("literal int or newline", next_token)?,
15058+ };
15059+ };
15060+
15061+ if self.peek_token().token == Token::SemiColon {
15062+ parser_err!("GO may not end with a semicolon", self.peek_token().span.start)?;
15063+ }
15064+
15065+ Ok(Statement::Go(GoStatement {
15066+ count,
15067+ }))
15068+ }
15069+
1502015070 /// Consume the parser and return its underlying token buffer
1502115071 pub fn into_tokens(self) -> Vec<TokenWithSpan> {
1502215072 self.tokens
0 commit comments