@@ -9636,16 +9636,21 @@ impl<'a> Parser<'a> {
96369636 Token::HexStringLiteral(ref s) => ok_value(Value::HexStringLiteral(s.to_string())),
96379637 Token::Placeholder(ref s) => ok_value(Value::Placeholder(s.to_string())),
96389638 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();
96429647 let ident = match next_token.token {
96439648 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)),
96459650 _ => self.expected("placeholder", next_token),
96469651 }?;
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) ))
96499654 }
96509655 unexpected => self.expected(
96519656 "a value",
@@ -17600,4 +17605,12 @@ mod tests {
1760017605 canonical,
1760117606 );
1760217607 }
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+ }
1760317616}
0 commit comments