From 1b3778e2d59d349d61ed22335102bdae34a4777f Mon Sep 17 00:00:00 2001 From: AugustoFKL <75763288+AugustoFKL@users.noreply.github.com> Date: Mon, 31 Oct 2022 16:22:34 -0300 Subject: [PATCH] feature!: added NUMERIC and DEC ANSI data types, and now the DECIMAL (#695) type prints DECIMAL instead of NUMERIC. BREAKING CHANGE: enum DATA TYPE variants changed, changing any API that uses it. --- src/ast/data_type.rs | 20 ++++++++++++++++++-- src/parser.rs | 40 ++++++++++++++++++++++++++++++++++++--- tests/sqlparser_common.rs | 33 +++++++++----------------------- tests/sqlparser_hive.rs | 3 +-- 4 files changed, 65 insertions(+), 31 deletions(-) diff --git a/src/ast/data_type.rs b/src/ast/data_type.rs index a6676116..e906383f 100644 --- a/src/ast/data_type.rs +++ b/src/ast/data_type.rs @@ -67,8 +67,18 @@ pub enum DataType { /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#binary-large-object-string-type /// [Oracle]: https://docs.oracle.com/javadb/10.8.3.0/ref/rrefblob.html Blob(Option), - /// Decimal type with optional precision and scale e.g. DECIMAL(10,2) + /// Numeric type with optional precision and scale e.g. NUMERIC(10,2), [standard][1] + /// + /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type + Numeric(ExactNumberInfo), + /// Decimal type with optional precision and scale e.g. DECIMAL(10,2), [standard][1] + /// + /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type Decimal(ExactNumberInfo), + /// Dec type with optional precision and scale e.g. DEC(10,2), [standard][1] + /// + /// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type + Dec(ExactNumberInfo), /// Floating point with optional precision e.g. FLOAT(8) Float(Option), /// Tiny integer with optional display width e.g. TINYINT or TINYINT(3) @@ -165,9 +175,15 @@ impl fmt::Display for DataType { format_type_with_optional_length(f, "VARBINARY", size, false) } DataType::Blob(size) => format_type_with_optional_length(f, "BLOB", size, false), - DataType::Decimal(info) => { + DataType::Numeric(info) => { write!(f, "NUMERIC{}", info) } + DataType::Decimal(info) => { + write!(f, "DECIMAL{}", info) + } + DataType::Dec(info) => { + write!(f, "DEC{}", info) + } DataType::Float(size) => format_type_with_optional_length(f, "FLOAT", size, false), DataType::TinyInt(zerofill) => { format_type_with_optional_length(f, "TINYINT", zerofill, false) diff --git a/src/parser.rs b/src/parser.rs index bd74e577..0f3f639c 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3645,7 +3645,13 @@ impl<'a> Parser<'a> { Keyword::STRING => Ok(DataType::String), Keyword::TEXT => Ok(DataType::Text), Keyword::BYTEA => Ok(DataType::Bytea), - Keyword::NUMERIC | Keyword::DECIMAL | Keyword::DEC => Ok(DataType::Decimal( + Keyword::NUMERIC => Ok(DataType::Numeric( + self.parse_exact_number_optional_precision_scale()?, + )), + Keyword::DECIMAL => Ok(DataType::Decimal( + self.parse_exact_number_optional_precision_scale()?, + )), + Keyword::DEC => Ok(DataType::Dec( self.parse_exact_number_optional_precision_scale()?, )), Keyword::ENUM => Ok(DataType::Enum(self.parse_string_values()?)), @@ -5784,19 +5790,47 @@ mod tests { dialects: vec![Box::new(GenericDialect {}), Box::new(AnsiDialect {})], }; - test_parse_data_type!(dialect, "NUMERIC", DataType::Decimal(ExactNumberInfo::None)); + test_parse_data_type!(dialect, "NUMERIC", DataType::Numeric(ExactNumberInfo::None)); test_parse_data_type!( dialect, "NUMERIC(2)", - DataType::Decimal(ExactNumberInfo::Precision(2)) + DataType::Numeric(ExactNumberInfo::Precision(2)) ); test_parse_data_type!( dialect, "NUMERIC(2,10)", + DataType::Numeric(ExactNumberInfo::PrecisionAndScale(2, 10)) + ); + + test_parse_data_type!(dialect, "DECIMAL", DataType::Decimal(ExactNumberInfo::None)); + + test_parse_data_type!( + dialect, + "DECIMAL(2)", + DataType::Decimal(ExactNumberInfo::Precision(2)) + ); + + test_parse_data_type!( + dialect, + "DECIMAL(2,10)", DataType::Decimal(ExactNumberInfo::PrecisionAndScale(2, 10)) ); + + test_parse_data_type!(dialect, "DEC", DataType::Dec(ExactNumberInfo::None)); + + test_parse_data_type!( + dialect, + "DEC(2)", + DataType::Dec(ExactNumberInfo::Precision(2)) + ); + + test_parse_data_type!( + dialect, + "DEC(2,10)", + DataType::Dec(ExactNumberInfo::PrecisionAndScale(2, 10)) + ); } #[test] diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 7e9ecf9b..f6dfe159 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -18,10 +18,8 @@ //! sqlparser regardless of the chosen dialect (i.e. it doesn't conflict with //! dialect-specific parsing rules). -#[macro_use] -mod test_utils; - use matches::assert_matches; + use sqlparser::ast::SelectItem::UnnamedExpr; use sqlparser::ast::*; use sqlparser::dialect::{ @@ -30,12 +28,14 @@ use sqlparser::dialect::{ }; use sqlparser::keywords::ALL_KEYWORDS; use sqlparser::parser::{Parser, ParserError}; - use test_utils::{ all_dialects, assert_eq_vec, expr_from_projection, join, number, only, table, table_alias, TestedDialects, }; +#[macro_use] +mod test_utils; + #[test] fn parse_insert_values() { let row = vec![ @@ -1628,15 +1628,9 @@ fn parse_cast() { verified_stmt("SELECT CAST(id AS NUMERIC) FROM customer"); - one_statement_parses_to( - "SELECT CAST(id AS DEC) FROM customer", - "SELECT CAST(id AS NUMERIC) FROM customer", - ); + verified_stmt("SELECT CAST(id AS DEC) FROM customer"); - one_statement_parses_to( - "SELECT CAST(id AS DECIMAL) FROM customer", - "SELECT CAST(id AS NUMERIC) FROM customer", - ); + verified_stmt("SELECT CAST(id AS DECIMAL) FROM customer"); let sql = "SELECT CAST(id AS NVARCHAR(50)) FROM customer"; let select = verified_only_select(sql); @@ -1720,22 +1714,13 @@ fn parse_try_cast() { }, expr_from_projection(only(&select.projection)) ); - one_statement_parses_to( - "SELECT TRY_CAST(id AS BIGINT) FROM customer", - "SELECT TRY_CAST(id AS BIGINT) FROM customer", - ); + verified_stmt("SELECT TRY_CAST(id AS BIGINT) FROM customer"); verified_stmt("SELECT TRY_CAST(id AS NUMERIC) FROM customer"); - one_statement_parses_to( - "SELECT TRY_CAST(id AS DEC) FROM customer", - "SELECT TRY_CAST(id AS NUMERIC) FROM customer", - ); + verified_stmt("SELECT TRY_CAST(id AS DEC) FROM customer"); - one_statement_parses_to( - "SELECT TRY_CAST(id AS DECIMAL) FROM customer", - "SELECT TRY_CAST(id AS NUMERIC) FROM customer", - ); + verified_stmt("SELECT TRY_CAST(id AS DECIMAL) FROM customer"); } #[test] diff --git a/tests/sqlparser_hive.rs b/tests/sqlparser_hive.rs index 8839cea2..c4df6b5d 100644 --- a/tests/sqlparser_hive.rs +++ b/tests/sqlparser_hive.rs @@ -156,8 +156,7 @@ fn long_numerics() { #[test] fn decimal_precision() { let query = "SELECT CAST(a AS DECIMAL(18,2)) FROM db.table"; - let expected = "SELECT CAST(a AS NUMERIC(18,2)) FROM db.table"; - hive().one_statement_parses_to(query, expected); + hive().verified_stmt(query); } #[test]