@@ -9667,16 +9667,21 @@ impl<'a> Parser<'a> {
96679667 Token::HexStringLiteral(ref s) => ok_value(Value::HexStringLiteral(s.to_string())),
96689668 Token::Placeholder(ref s) => ok_value(Value::Placeholder(s.to_string())),
96699669 tok @ Token::Colon | tok @ Token::AtSign => {
9670- // Not calling self.parse_identifier(false)? because only in placeholder we want to check numbers as idfentifies
9671- // This because snowflake allows numbers as placeholders
9672- let next_token = self.next_token();
9670+ // 1. Not calling self.parse_identifier(false)?
9671+ // because only in placeholder we want to check
9672+ // numbers as idfentifies. This because snowflake
9673+ // allows numbers as placeholders
9674+ // 2. Not calling self.next_token() to enforce `tok`
9675+ // be followed immediately by a word/number, ie.
9676+ // without any whitespace in between
9677+ let next_token = self.next_token_no_skip().unwrap_or(&EOF_TOKEN).clone();
96739678 let ident = match next_token.token {
96749679 Token::Word(w) => Ok(w.into_ident(next_token.span)),
9675- Token::Number(w, false) => Ok(Ident::new( w)),
9680+ Token::Number(w, false) => Ok(Ident::with_span(next_token.span, w)),
96769681 _ => self.expected("placeholder", next_token),
96779682 }?;
9678- let placeholder = tok.to_string() + &ident.value;
9679- ok_value(Value::Placeholder(placeholder ))
9683+ Ok(Value::Placeholder( tok.to_string() + &ident.value)
9684+ .with_span(Span::new(span.start, ident.span.end) ))
96809685 }
96819686 unexpected => self.expected(
96829687 "a value",
@@ -17632,4 +17637,12 @@ mod tests {
1763217637 canonical,
1763317638 );
1763417639 }
17640+
17641+ #[test]
17642+ fn test_placeholder_invalid_whitespace() {
17643+ for w in [" ", "/*invalid*/"] {
17644+ let sql = format!("\nSELECT\n :{w}fooBar");
17645+ assert!(Parser::parse_sql(&GenericDialect, &sql).is_err());
17646+ }
17647+ }
1763517648}
0 commit comments