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

github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new a478fb17b3 fix: Correctly process numeric literals with underscores 
(#24046)
a478fb17b3 is described below

commit a478fb17b31477c38bb7707bd18d13de0364ea3f
Author: Nuno Faria <[email protected]>
AuthorDate: Sat Aug 8 12:01:00 2026 +0100

    fix: Correctly process numeric literals with underscores (#24046)
    
    ## Which issue does this PR close?
    
    - Closes #23877.
    
    ## Rationale for this change
    
    Be able to use numeric literals with underscores as separators, which
    are valid in some dialects like Postgres.
    
    ## What changes are included in this PR?
    
    The `parse_sql_number` method now removes underscores from numbers first
    before passing to the Rust parser.
    
    ## Are these changes tested?
    
    Yes.
    
    ## Are there any user-facing changes?
    
    No.
---
 datafusion/sql/src/expr/mod.rs              | 28 ++++++++++++++++++++++++++++
 datafusion/sql/src/expr/value.rs            | 23 ++++++++++++++++++++---
 datafusion/sqllogictest/test_files/expr.slt | 15 +++++++++++++++
 3 files changed, 63 insertions(+), 3 deletions(-)

diff --git a/datafusion/sql/src/expr/mod.rs b/datafusion/sql/src/expr/mod.rs
index c2e4822f76..b1de4e95fd 100644
--- a/datafusion/sql/src/expr/mod.rs
+++ b/datafusion/sql/src/expr/mod.rs
@@ -1593,4 +1593,32 @@ mod tests {
 
         assert!(matches!(expr, Expr::Alias(_)));
     }
+
+    #[test]
+    fn test_parse_numbers_with_underscores() {
+        use datafusion_common::ScalarValue::*;
+
+        let context_provider = TestContextProvider::new();
+        let sql_to_rel = SqlToRel::new(&context_provider);
+
+        // (input, positive result, negative result)
+        let test_cases = [
+            ("1_000", Int64(Some(1000)), Int64(Some(-1000))),
+            ("100_000", Int64(Some(100000)), Int64(Some(-100000))),
+            ("1_2_3_4", Int64(Some(1234)), Int64(Some(-1234))),
+            ("0_0", Int64(Some(0)), Int64(Some(-0))),
+            ("1_23.4_56", Float64(Some(123.456)), Float64(Some(-123.456))),
+        ];
+
+        for (literal, out_positive, out_negative) in test_cases {
+            assert_eq!(
+                sql_to_rel.parse_sql_number(literal, false).unwrap(),
+                Expr::Literal(out_positive, None)
+            );
+            assert_eq!(
+                sql_to_rel.parse_sql_number(literal, true).unwrap(),
+                Expr::Literal(out_negative, None)
+            );
+        }
+    }
 }
diff --git a/datafusion/sql/src/expr/value.rs b/datafusion/sql/src/expr/value.rs
index 13a47f545c..1307e917e4 100644
--- a/datafusion/sql/src/expr/value.rs
+++ b/datafusion/sql/src/expr/value.rs
@@ -74,10 +74,27 @@ impl<S: ContextProvider> SqlToRel<'_, S> {
         unsigned_number: &str,
         negative: bool,
     ) -> Result<Expr> {
-        let signed_number: Cow<str> = if negative {
-            Cow::Owned(format!("-{unsigned_number}"))
-        } else {
+        // remove underscores, since the Rust parser used here does not 
support them
+        let signed_number = if !negative && !unsigned_number.contains('_') {
             Cow::Borrowed(unsigned_number)
+        } else {
+            let mut signed_number =
+                String::with_capacity(unsigned_number.len() + 
usize::from(negative));
+            if negative {
+                signed_number.push('-');
+            }
+            unsigned_number.bytes().for_each(|b| {
+                if b != b'_' {
+                    signed_number.push(b as char);
+                }
+            });
+            Cow::Owned(signed_number)
+        };
+
+        let unsigned_number = if negative {
+            &signed_number[1..]
+        } else {
+            &signed_number
         };
 
         // Try to parse as i64 first, then u64 if negative is false, then 
decimal or f64
diff --git a/datafusion/sqllogictest/test_files/expr.slt 
b/datafusion/sqllogictest/test_files/expr.slt
index ba4e4d03b3..32113890aa 100644
--- a/datafusion/sqllogictest/test_files/expr.slt
+++ b/datafusion/sqllogictest/test_files/expr.slt
@@ -2665,3 +2665,18 @@ false
 
 statement ok
 drop table t;
+
+
+# Test numeric literals with underscore separators
+# (https://github.com/apache/datafusion/issues/23877)
+
+statement ok
+set datafusion.sql_parser.dialect = 'postgres'
+
+query IIIRI
+select 1_000, 1_2_3_4, -1_2_3_4, 1_2.3_4, 0_0
+----
+1000 1234 -1234 12.34 0
+
+statement ok
+reset datafusion.sql_parser.dialect


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to