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 b2f97738 Postgres: enhance NUMERIC/DECIMAL parsing to support negative
scale (#1990)
b2f97738 is described below
commit b2f977384c469477a06dd1d61489877c12fb9798
Author: Tyler White <50381805+indexs...@users.noreply.github.com>
AuthorDate: Sat Aug 9 02:33:34 2025 -0400
Postgres: enhance NUMERIC/DECIMAL parsing to support negative scale (#1990)
Co-authored-by: Ifeanyi Ubah <ify1...@yahoo.com>
---
src/ast/data_type.rs | 2 +-
src/parser/mod.rs | 79 +++++++++++++++++++++++++++++++++++++++++++++++++---
2 files changed, 76 insertions(+), 5 deletions(-)
diff --git a/src/ast/data_type.rs b/src/ast/data_type.rs
index b4a8af60..dde9e0b7 100644
--- a/src/ast/data_type.rs
+++ b/src/ast/data_type.rs
@@ -962,7 +962,7 @@ pub enum ExactNumberInfo {
/// Only precision information, e.g. `DECIMAL(10)`
Precision(u64),
/// Precision and scale information, e.g. `DECIMAL(10,2)`
- PrecisionAndScale(u64, u64),
+ PrecisionAndScale(u64, i64),
}
impl fmt::Display for ExactNumberInfo {
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index d6ace1eb..2c5f1b9e 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -11256,7 +11256,7 @@ impl<'a> Parser<'a> {
if self.consume_token(&Token::LParen) {
let precision = self.parse_literal_uint()?;
let scale = if self.consume_token(&Token::Comma) {
- Some(self.parse_literal_uint()?)
+ Some(self.parse_signed_integer()?)
} else {
None
};
@@ -11272,6 +11272,27 @@ impl<'a> Parser<'a> {
}
}
+ /// Parse an optionally signed integer literal.
+ fn parse_signed_integer(&mut self) -> Result<i64, ParserError> {
+ let is_negative = self.consume_token(&Token::Minus);
+
+ if !is_negative {
+ let _ = self.consume_token(&Token::Plus);
+ }
+
+ let current_token = self.peek_token_ref();
+ match ¤t_token.token {
+ Token::Number(s, _) => {
+ let s = s.clone();
+ let span_start = current_token.span.start;
+ self.advance_token();
+ let value = Self::parse::<i64>(s, span_start)?;
+ Ok(if is_negative { -value } else { value })
+ }
+ _ => self.expected_ref("number", current_token),
+ }
+ }
+
pub fn parse_optional_type_modifiers(&mut self) ->
Result<Option<Vec<String>>, ParserError> {
if self.consume_token(&Token::LParen) {
let mut modifiers = Vec::new();
@@ -17118,7 +17139,7 @@ mod tests {
use crate::ast::{
CharLengthUnits, CharacterLength, DataType, ExactNumberInfo,
ObjectName, TimezoneInfo,
};
- use crate::dialect::{AnsiDialect, GenericDialect};
+ use crate::dialect::{AnsiDialect, GenericDialect, PostgreSqlDialect};
use crate::test_utils::TestedDialects;
macro_rules! test_parse_data_type {
@@ -17324,8 +17345,11 @@ mod tests {
#[test]
fn test_ansii_exact_numeric_types() {
// Exact numeric types:
<https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type>
- let dialect =
- TestedDialects::new(vec![Box::new(GenericDialect {}),
Box::new(AnsiDialect {})]);
+ let dialect = TestedDialects::new(vec![
+ Box::new(GenericDialect {}),
+ Box::new(AnsiDialect {}),
+ Box::new(PostgreSqlDialect {}),
+ ]);
test_parse_data_type!(dialect, "NUMERIC",
DataType::Numeric(ExactNumberInfo::None));
@@ -17368,6 +17392,53 @@ mod tests {
"DEC(2,10)",
DataType::Dec(ExactNumberInfo::PrecisionAndScale(2, 10))
);
+
+ // Test negative scale values.
+ test_parse_data_type!(
+ dialect,
+ "NUMERIC(10,-2)",
+ DataType::Numeric(ExactNumberInfo::PrecisionAndScale(10, -2))
+ );
+
+ test_parse_data_type!(
+ dialect,
+ "DECIMAL(1000,-10)",
+ DataType::Decimal(ExactNumberInfo::PrecisionAndScale(1000,
-10))
+ );
+
+ test_parse_data_type!(
+ dialect,
+ "DEC(5,-1000)",
+ DataType::Dec(ExactNumberInfo::PrecisionAndScale(5, -1000))
+ );
+
+ test_parse_data_type!(
+ dialect,
+ "NUMERIC(10,-5)",
+ DataType::Numeric(ExactNumberInfo::PrecisionAndScale(10, -5))
+ );
+
+ test_parse_data_type!(
+ dialect,
+ "DECIMAL(20,-10)",
+ DataType::Decimal(ExactNumberInfo::PrecisionAndScale(20, -10))
+ );
+
+ test_parse_data_type!(
+ dialect,
+ "DEC(5,-2)",
+ DataType::Dec(ExactNumberInfo::PrecisionAndScale(5, -2))
+ );
+
+ dialect.run_parser_method("NUMERIC(10,+5)", |parser| {
+ let data_type = parser.parse_data_type().unwrap();
+ assert_eq!(
+ DataType::Numeric(ExactNumberInfo::PrecisionAndScale(10,
5)),
+ data_type
+ );
+ // Note: Explicit '+' sign is not preserved in output, which
is correct
+ assert_eq!("NUMERIC(10,5)", data_type.to_string());
+ });
}
#[test]
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscr...@datafusion.apache.org
For additional commands, e-mail: commits-h...@datafusion.apache.org