Skip to content

Commit 2b28275

Browse files
committed
Extract common logic to look back for a newline to a helper
1 parent cfecd33 commit 2b28275

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
@@ -22,7 +22,7 @@ use crate::ast::{
2222
use crate::dialect::Dialect;
2323
use crate::keywords::{self, Keyword};
2424
use crate::parser::{Parser, ParserError};
25-
use crate::tokenizer::{Token, Whitespace};
25+
use crate::tokenizer::Token;
2626
#[cfg(not(feature = "std"))]
2727
use alloc::{vec, vec::Vec};
2828

@@ -119,26 +119,14 @@ impl Dialect for MsSqlDialect {
119119
}
120120

121121
fn is_column_alias(&self, kw: &Keyword, parser: &mut Parser) -> bool {
122-
// if:
123-
// - keyword is `GO`, and
124-
// - looking backwards there's only (any) whitespace preceded by a newline
125-
// then: `GO` iSN'T a column alias
126-
if kw == &Keyword::GO {
127-
let mut look_back_count = 2;
128-
loop {
129-
let prev_index = parser.index().saturating_sub(look_back_count);
130-
if prev_index == 0 {
131-
break;
132-
}
133-
let prev_token = parser.token_at(prev_index);
134-
match prev_token.token {
135-
Token::Whitespace(ref w) => match w {
136-
Whitespace::Newline => return false,
137-
_ => look_back_count += 1,
138-
},
139-
_ => break,
140-
};
141-
}
122+
// if we find maybe whitespace then a newline looking backward, then `GO` ISN'T a column alias
123+
// if we can't find a newline then we assume that `GO` IS a column alias
124+
if kw == &Keyword::GO
125+
&& parser
126+
.expect_previously_only_whitespace_until_newline()
127+
.is_ok()
128+
{
129+
return false;
142130
}
143131

144132
!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
@@ -4065,6 +4065,44 @@ impl<'a> Parser<'a> {
40654065
)
40664066
}
40674067

4068+
/// Look backwards in the token stream and expect that there was only whitespace tokens until the previous newline
4069+
pub fn expect_previously_only_whitespace_until_newline(&mut self) -> Result<(), ParserError> {
4070+
let mut look_back_count = 2;
4071+
loop {
4072+
let prev_index = self.index.saturating_sub(look_back_count);
4073+
if prev_index == 0 {
4074+
break;
4075+
}
4076+
let prev_token = self.token_at(prev_index);
4077+
match prev_token.token {
4078+
Token::Whitespace(ref w) => match w {
4079+
Whitespace::Newline => break,
4080+
// special consideration required for single line comments since that string includes the newline
4081+
Whitespace::SingleLineComment { comment, prefix: _ } => {
4082+
if comment.ends_with('\n') {
4083+
break;
4084+
}
4085+
look_back_count += 1;
4086+
}
4087+
_ => look_back_count += 1,
4088+
},
4089+
_ => {
4090+
let current_token = self.get_current_token();
4091+
if prev_token == current_token {
4092+
// if we are at the start of the statement, we can skip this check
4093+
break;
4094+
}
4095+
4096+
self.expected(
4097+
&format!("newline before current token ({})", current_token),
4098+
prev_token.clone(),
4099+
)?
4100+
}
4101+
};
4102+
}
4103+
Ok(())
4104+
}
4105+
40684106
/// If the current token is the `expected` keyword, consume it and returns
40694107
/// true. Otherwise, no tokens are consumed and returns false.
40704108
#[must_use]
@@ -15242,36 +15280,7 @@ impl<'a> Parser<'a> {
1524215280

1524315281
/// Parse [Statement::Go]
1524415282
fn parse_go(&mut self) -> Result<Statement, ParserError> {
15245-
// previous token should be a newline (skipping non-newline whitespace)
15246-
// see also, `previous_token`
15247-
let mut look_back_count = 2;
15248-
loop {
15249-
let prev_index = self.index.saturating_sub(look_back_count);
15250-
if prev_index == 0 {
15251-
break;
15252-
}
15253-
let prev_token = self.token_at(prev_index);
15254-
match prev_token.token {
15255-
Token::Whitespace(ref w) => match w {
15256-
Whitespace::Newline => break,
15257-
Whitespace::SingleLineComment { comment, prefix: _ } => {
15258-
if comment.ends_with('\n') {
15259-
break;
15260-
}
15261-
look_back_count += 1;
15262-
}
15263-
_ => look_back_count += 1,
15264-
},
15265-
_ => {
15266-
if prev_token == self.get_current_token() {
15267-
// if we are at the start of the statement, we can skip this check
15268-
break;
15269-
}
15270-
15271-
self.expected("newline before GO", prev_token.clone())?
15272-
}
15273-
};
15274-
}
15283+
self.expect_previously_only_whitespace_until_newline()?;
1527515284

1527615285
let count = loop {
1527715286
// 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
@@ -2253,7 +2253,7 @@ fn parse_mssql_go_keyword() {
22532253
let err = ms().parse_sql_statements(invalid_go_position);
22542254
assert_eq!(
22552255
err.unwrap_err().to_string(),
2256-
"sql parser error: Expected: newline before GO, found: ;"
2256+
"sql parser error: Expected: newline before current token (GO), found: ;"
22572257
);
22582258

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

0 commit comments

Comments
 (0)