mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-09-27 07:59:11 +00:00
Fix placeholder spans (#1979)
This commit is contained in:
parent
f5f51eb6f1
commit
6932f4ad65
2 changed files with 42 additions and 6 deletions
|
@ -2525,4 +2525,27 @@ pub mod tests {
|
||||||
"CASE 1 WHEN 2 THEN 3 ELSE 4 END"
|
"CASE 1 WHEN 2 THEN 3 ELSE 4 END"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_placeholder_span() {
|
||||||
|
let sql = "\nSELECT\n :fooBar";
|
||||||
|
let r = Parser::parse_sql(&GenericDialect, sql).unwrap();
|
||||||
|
assert_eq!(1, r.len());
|
||||||
|
match &r[0] {
|
||||||
|
Statement::Query(q) => {
|
||||||
|
let col = &q.body.as_select().unwrap().projection[0];
|
||||||
|
match col {
|
||||||
|
SelectItem::UnnamedExpr(Expr::Value(ValueWithSpan {
|
||||||
|
value: Value::Placeholder(s),
|
||||||
|
span,
|
||||||
|
})) => {
|
||||||
|
assert_eq!(":fooBar", s);
|
||||||
|
assert_eq!(&Span::new((3, 3).into(), (3, 10).into()), span);
|
||||||
|
}
|
||||||
|
_ => panic!("expected unnamed expression; got {col:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stmt => panic!("expected query; got {stmt:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9636,16 +9636,21 @@ impl<'a> Parser<'a> {
|
||||||
Token::HexStringLiteral(ref s) => ok_value(Value::HexStringLiteral(s.to_string())),
|
Token::HexStringLiteral(ref s) => ok_value(Value::HexStringLiteral(s.to_string())),
|
||||||
Token::Placeholder(ref s) => ok_value(Value::Placeholder(s.to_string())),
|
Token::Placeholder(ref s) => ok_value(Value::Placeholder(s.to_string())),
|
||||||
tok @ Token::Colon | tok @ Token::AtSign => {
|
tok @ Token::Colon | tok @ Token::AtSign => {
|
||||||
// Not calling self.parse_identifier(false)? because only in placeholder we want to check numbers as idfentifies
|
// 1. Not calling self.parse_identifier(false)?
|
||||||
// This because snowflake allows numbers as placeholders
|
// because only in placeholder we want to check
|
||||||
let next_token = self.next_token();
|
// numbers as idfentifies. This because snowflake
|
||||||
|
// allows numbers as placeholders
|
||||||
|
// 2. Not calling self.next_token() to enforce `tok`
|
||||||
|
// be followed immediately by a word/number, ie.
|
||||||
|
// without any whitespace in between
|
||||||
|
let next_token = self.next_token_no_skip().unwrap_or(&EOF_TOKEN).clone();
|
||||||
let ident = match next_token.token {
|
let ident = match next_token.token {
|
||||||
Token::Word(w) => Ok(w.into_ident(next_token.span)),
|
Token::Word(w) => Ok(w.into_ident(next_token.span)),
|
||||||
Token::Number(w, false) => Ok(Ident::new(w)),
|
Token::Number(w, false) => Ok(Ident::with_span(next_token.span, w)),
|
||||||
_ => self.expected("placeholder", next_token),
|
_ => self.expected("placeholder", next_token),
|
||||||
}?;
|
}?;
|
||||||
let placeholder = tok.to_string() + &ident.value;
|
Ok(Value::Placeholder(tok.to_string() + &ident.value)
|
||||||
ok_value(Value::Placeholder(placeholder))
|
.with_span(Span::new(span.start, ident.span.end)))
|
||||||
}
|
}
|
||||||
unexpected => self.expected(
|
unexpected => self.expected(
|
||||||
"a value",
|
"a value",
|
||||||
|
@ -17600,4 +17605,12 @@ mod tests {
|
||||||
canonical,
|
canonical,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_placeholder_invalid_whitespace() {
|
||||||
|
for w in [" ", "/*invalid*/"] {
|
||||||
|
let sql = format!("\nSELECT\n :{w}fooBar");
|
||||||
|
assert!(Parser::parse_sql(&GenericDialect, &sql).is_err());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue