@@ -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,56 @@ 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+ _ => {
15040+ if prev_token == self.get_current_token() {
15041+ // if we are at the start of the statement, we can skip this check
15042+ break;
15043+ }
15044+
15045+ self.expected("newline before GO", prev_token.clone())?
15046+ },
15047+ };
15048+ }
15049+
15050+ let count = loop {
15051+ // using this peek function because we want to halt this statement parsing upon newline
15052+ let next_token = self.peek_token_no_skip();
15053+ match next_token.token {
15054+ Token::EOF => break None::<u64>,
15055+ Token::Whitespace(ref w) => match w {
15056+ Whitespace::Newline => break None,
15057+ _ => _ = self.next_token_no_skip(),
15058+ },
15059+ Token::Number(s, _) => {
15060+ let value = Some(Self::parse::<u64>(s, next_token.span.start)?);
15061+ self.advance_token();
15062+ break value;
15063+ },
15064+ _ => self.expected("literal int or newline", next_token)?,
15065+ };
15066+ };
15067+
15068+ if self.peek_token().token == Token::SemiColon {
15069+ parser_err!("GO may not end with a semicolon", self.peek_token().span.start)?;
15070+ }
15071+
15072+ Ok(Statement::Go(GoStatement {
15073+ count,
15074+ }))
15075+ }
15076+
1502015077 /// Consume the parser and return its underlying token buffer
1502115078 pub fn into_tokens(self) -> Vec<TokenWithSpan> {
1502215079 self.tokens
0 commit comments