Skip to content

Commit d3a48f5

Browse files
committed
Extract common logic to look back for a newline to a helper
1 parent dcb6e5e commit d3a48f5

File tree

3 files changed

+49
-52
lines changed

3 files changed

+49
-52
lines changed

src/dialect/mssql.rs

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use crate::ast::{
2323
use crate::dialect::Dialect;
2424
use crate::keywords::{self, Keyword};
2525
use crate::parser::{Parser, ParserError};
26-
use crate::tokenizer::{Token, Whitespace};
26+
use crate::tokenizer::Token;
2727
#[cfg(not(feature = "std"))]
2828
use alloc::{vec, vec::Vec};
2929

@@ -129,26 +129,14 @@ impl Dialect for MsSqlDialect {
129129
}
130130

131131
fn is_column_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
132-
// if:
133-
// - keyword is `GO`, and
134-
// - looking backwards there's only (any) whitespace preceded by a newline
135-
// then: `GO` iSN'T a column alias
136-
if kw == &Keyword::GO {
137-
let mut look_back_count = 2;
138-
loop {
139-
let prev_index = parser.index().saturating_sub(look_back_count);
140-
if prev_index == 0 {
141-
break;
142-
}
143-
let prev_token = parser.token_at(prev_index);
144-
match prev_token.token {
145-
Token::Whitespace(ref w) => match w {
146-
Whitespace::Newline => return false,
147-
_ => look_back_count += 1,
148-
},
149-
_ => break,
150-
};
151-
}
132+
// if we find maybe whitespace then a newline looking backward, then `GO` ISN'T a column alias
133+
// if we can't find a newline then we assume that `GO` IS a column alias
134+
if kw == &Keyword::GO
135+
&& parser
136+
.expect_previously_only_whitespace_until_newline()
137+
.is_ok()
138+
{
139+
return false;
152140
}
153141

154142
!keywords::RESERVED_FOR_COLUMN_ALIAS.contains(kw) && !RESERVED_FOR_COLUMN_ALIAS.contains(kw)

src/parser/mod.rs

Lines changed: 39 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4238,6 +4238,44 @@ impl<'a> Parser<'a> {
42384238
)
42394239
}
42404240

4241+
/// Look backwards in the token stream and expect that there was only whitespace tokens until the previous newline
4242+
pub fn expect_previously_only_whitespace_until_newline(&mut self) -> Result<(), ParserError> {
4243+
let mut look_back_count = 2;
4244+
loop {
4245+
let prev_index = self.index.saturating_sub(look_back_count);
4246+
if prev_index == 0 {
4247+
break;
4248+
}
4249+
let prev_token = self.token_at(prev_index);
4250+
match prev_token.token {
4251+
Token::Whitespace(ref w) => match w {
4252+
Whitespace::Newline => break,
4253+
// special consideration required for single line comments since that string includes the newline
4254+
Whitespace::SingleLineComment { comment, prefix: _ } => {
4255+
if comment.ends_with('\n') {
4256+
break;
4257+
}
4258+
look_back_count += 1;
4259+
}
4260+
_ => look_back_count += 1,
4261+
},
4262+
_ => {
4263+
let current_token = self.get_current_token();
4264+
if prev_token == current_token {
4265+
// if we are at the start of the statement, we can skip this check
4266+
break;
4267+
}
4268+
4269+
self.expected(
4270+
&format!("newline before current token ({})", current_token),
4271+
prev_token.clone(),
4272+
)?
4273+
}
4274+
};
4275+
}
4276+
Ok(())
4277+
}
4278+
42414279
/// If the current token is the `expected` keyword, consume it and returns
42424280
/// true. Otherwise, no tokens are consumed and returns false.
42434281
#[must_use]
@@ -17354,36 +17392,7 @@ impl<'a> Parser<'a> {
1735417392

1735517393
/// Parse [Statement::Go]
1735617394
fn parse_go(&mut self) -> Result<Statement, ParserError> {
17357-
// previous token should be a newline (skipping non-newline whitespace)
17358-
// see also, `previous_token`
17359-
let mut look_back_count = 2;
17360-
loop {
17361-
let prev_index = self.index.saturating_sub(look_back_count);
17362-
if prev_index == 0 {
17363-
break;
17364-
}
17365-
let prev_token = self.token_at(prev_index);
17366-
match prev_token.token {
17367-
Token::Whitespace(ref w) => match w {
17368-
Whitespace::Newline => break,
17369-
Whitespace::SingleLineComment { comment, prefix: _ } => {
17370-
if comment.ends_with('\n') {
17371-
break;
17372-
}
17373-
look_back_count += 1;
17374-
}
17375-
_ => look_back_count += 1,
17376-
},
17377-
_ => {
17378-
if prev_token == self.get_current_token() {
17379-
// if we are at the start of the statement, we can skip this check
17380-
break;
17381-
}
17382-
17383-
self.expected("newline before GO", prev_token.clone())?
17384-
}
17385-
};
17386-
}
17395+
self.expect_previously_only_whitespace_until_newline()?;
1738717396

1738817397
let count = loop {
1738917398
// using this peek function because we want to halt this statement parsing upon newline

tests/sqlparser_mssql.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2619,7 +2619,7 @@ fn parse_mssql_go_keyword() {
26192619
let err = ms().parse_sql_statements(invalid_go_position);
26202620
assert_eq!(
26212621
err.unwrap_err().to_string(),
2622-
"sql parser error: Expected: newline before GO, found: ;"
2622+
"sql parser error: Expected: newline before current token (GO), found: ;"
26232623
);
26242624

26252625
let invalid_go_count = "SELECT 1\nGO x";

0 commit comments

Comments
 (0)