@@ -9636,16 +9636,21 @@ impl<'a> Parser<'a> {
9636
9636
Token::HexStringLiteral(ref s) => ok_value(Value::HexStringLiteral(s.to_string())),
9637
9637
Token::Placeholder(ref s) => ok_value(Value::Placeholder(s.to_string())),
9638
9638
tok @ Token::Colon | tok @ Token::AtSign => {
9639
- // Not calling self.parse_identifier(false)? because only in placeholder we want to check numbers as idfentifies
9640
- // This because snowflake allows numbers as placeholders
9641
- let next_token = self.next_token();
9639
+ // 1. Not calling self.parse_identifier(false)?
9640
+ // because only in placeholder we want to check
9641
+ // numbers as idfentifies. This because snowflake
9642
+ // allows numbers as placeholders
9643
+ // 2. Not calling self.next_token() to enforce `tok`
9644
+ // be followed immediately by a word/number, ie.
9645
+ // without any whitespace in between
9646
+ let next_token = self.next_token_no_skip().unwrap_or(&EOF_TOKEN).clone();
9642
9647
let ident = match next_token.token {
9643
9648
Token::Word(w) => Ok(w.into_ident(next_token.span)),
9644
- Token::Number(w, false) => Ok(Ident::new( w)),
9649
+ Token::Number(w, false) => Ok(Ident::with_span(next_token.span, w)),
9645
9650
_ => self.expected("placeholder", next_token),
9646
9651
}?;
9647
- let placeholder = tok.to_string() + &ident.value;
9648
- ok_value(Value::Placeholder(placeholder ))
9652
+ Ok(Value::Placeholder( tok.to_string() + &ident.value)
9653
+ .with_span(Span::new(span.start, ident.span.end) ))
9649
9654
}
9650
9655
unexpected => self.expected(
9651
9656
"a value",
@@ -17600,4 +17605,12 @@ mod tests {
17600
17605
canonical,
17601
17606
);
17602
17607
}
17608
+
17609
+ #[test]
17610
+ fn test_placeholder_invalid_whitespace() {
17611
+ for w in [" ", "/*invalid*/"] {
17612
+ let sql = format!("\nSELECT\n :{w}fooBar");
17613
+ assert!(Parser::parse_sql(&GenericDialect, &sql).is_err());
17614
+ }
17615
+ }
17603
17616
}
0 commit comments