This is an automated email from the ASF dual-hosted git repository.

iffyio pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new 6932f4ad Fix placeholder spans (#1979)
6932f4ad is described below

commit 6932f4ad65f442c5b44b3445a76afd8b02dc0fdb
Author: xitep <xi...@users.noreply.github.com>
AuthorDate: Fri Aug 1 12:40:33 2025 +0200

    Fix placeholder spans (#1979)
---
 src/ast/spans.rs  | 23 +++++++++++++++++++++++
 src/parser/mod.rs | 25 +++++++++++++++++++------
 2 files changed, 42 insertions(+), 6 deletions(-)

diff --git a/src/ast/spans.rs b/src/ast/spans.rs
index 00313c0e..58583660 100644
--- a/src/ast/spans.rs
+++ b/src/ast/spans.rs
@@ -2525,4 +2525,27 @@ pub mod tests {
             "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:?}"),
+        }
+    }
 }
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 3bf03605..9b8fa17a 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -9636,16 +9636,21 @@ impl<'a> Parser<'a> {
             Token::HexStringLiteral(ref s) => 
ok_value(Value::HexStringLiteral(s.to_string())),
             Token::Placeholder(ref s) => 
ok_value(Value::Placeholder(s.to_string())),
             tok @ Token::Colon | tok @ Token::AtSign => {
-                // Not calling self.parse_identifier(false)? because only in 
placeholder we want to check numbers as idfentifies
-                // This because snowflake allows numbers as placeholders
-                let next_token = self.next_token();
+                // 1. Not calling self.parse_identifier(false)?
+                //    because only in placeholder we want to check
+                //    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 {
                     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),
                 }?;
-                let placeholder = tok.to_string() + &ident.value;
-                ok_value(Value::Placeholder(placeholder))
+                Ok(Value::Placeholder(tok.to_string() + &ident.value)
+                    .with_span(Span::new(span.start, ident.span.end)))
             }
             unexpected => self.expected(
                 "a value",
@@ -17600,4 +17605,12 @@ mod tests {
             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());
+        }
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@datafusion.apache.org
For additional commands, e-mail: commits-h...@datafusion.apache.org

Reply via email to