diff --git a/src/ast/data_type.rs b/src/ast/data_type.rs index c994645ba..2f844d50e 100644 --- a/src/ast/data_type.rs +++ b/src/ast/data_type.rs @@ -33,8 +33,11 @@ pub enum DataType { Nvarchar(Option), /// Uuid type Uuid, - /// Large character object e.g. CLOB(1000) - Clob(u64), + /// Large character object with optional length e.g. CLOB, CLOB(1000), [standard], [Oracle] + /// + /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#character-large-object-type + /// [Oracle]: https://docs.oracle.com/javadb/10.10.1.2/ref/rrefclob.html + Clob(Option), /// Fixed-length binary type with optional length e.g. [standard], [MS SQL Server] /// /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#binary-string-type @@ -45,8 +48,11 @@ pub enum DataType { /// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#binary-string-type /// [MS SQL Server]: https://learn.microsoft.com/pt-br/sql/t-sql/data-types/binary-and-varbinary-transact-sql?view=sql-server-ver16 Varbinary(Option), - /// Large binary object e.g. BLOB(1000) - Blob(u64), + /// Large binary object with optional length e.g. BLOB, BLOB(1000), [standard], [Oracle] + /// + /// [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) Decimal(Option, Option), /// Floating point with optional precision e.g. FLOAT(8) @@ -131,12 +137,12 @@ impl fmt::Display for DataType { format_type_with_optional_length(f, "NVARCHAR", size, false) } DataType::Uuid => write!(f, "UUID"), - DataType::Clob(size) => write!(f, "CLOB({})", size), + DataType::Clob(size) => format_type_with_optional_length(f, "CLOB", size, false), DataType::Binary(size) => format_type_with_optional_length(f, "BINARY", size, false), DataType::Varbinary(size) => { format_type_with_optional_length(f, "VARBINARY", size, false) } - DataType::Blob(size) => write!(f, "BLOB({})", size), + DataType::Blob(size) => format_type_with_optional_length(f, "BLOB", size, false), DataType::Decimal(precision, scale) => { if let Some(scale) = scale { write!(f, "NUMERIC({},{})", precision.unwrap(), scale) diff --git a/src/parser.rs b/src/parser.rs index 09419cc29..9ac5f89c6 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -3403,10 +3403,10 @@ impl<'a> Parser<'a> { Ok(DataType::Char(self.parse_optional_precision()?)) } } - Keyword::CLOB => Ok(DataType::Clob(self.parse_precision()?)), + Keyword::CLOB => Ok(DataType::Clob(self.parse_optional_precision()?)), Keyword::BINARY => Ok(DataType::Binary(self.parse_optional_precision()?)), Keyword::VARBINARY => Ok(DataType::Varbinary(self.parse_optional_precision()?)), - Keyword::BLOB => Ok(DataType::Blob(self.parse_precision()?)), + Keyword::BLOB => Ok(DataType::Blob(self.parse_optional_precision()?)), Keyword::UUID => Ok(DataType::Uuid), Keyword::DATE => Ok(DataType::Date), Keyword::DATETIME => Ok(DataType::Datetime), @@ -5258,6 +5258,10 @@ mod tests { // TODO add tests for all data types? https://github.com/sqlparser-rs/sqlparser-rs/issues/2 #[test] fn test_parse_data_type() { + test_parse_data_type("BLOB", "BLOB"); + test_parse_data_type("BLOB(50)", "BLOB(50)"); + test_parse_data_type("CLOB", "CLOB"); + test_parse_data_type("CLOB(50)", "CLOB(50)"); test_parse_data_type("DOUBLE PRECISION", "DOUBLE PRECISION"); test_parse_data_type("DOUBLE", "DOUBLE"); test_parse_data_type("VARBINARY", "VARBINARY"); diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 391eff134..956a62297 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -1655,12 +1655,22 @@ fn parse_cast() { expr_from_projection(only(&select.projection)) ); + let sql = "SELECT CAST(id AS CLOB) FROM customer"; + let select = verified_only_select(sql); + assert_eq!( + &Expr::Cast { + expr: Box::new(Expr::Identifier(Ident::new("id"))), + data_type: DataType::Clob(None) + }, + expr_from_projection(only(&select.projection)) + ); + let sql = "SELECT CAST(id AS CLOB(50)) FROM customer"; let select = verified_only_select(sql); assert_eq!( &Expr::Cast { expr: Box::new(Expr::Identifier(Ident::new("id"))), - data_type: DataType::Clob(50) + data_type: DataType::Clob(Some(50)) }, expr_from_projection(only(&select.projection)) ); @@ -1685,12 +1695,22 @@ fn parse_cast() { expr_from_projection(only(&select.projection)) ); + let sql = "SELECT CAST(id AS BLOB) FROM customer"; + let select = verified_only_select(sql); + assert_eq!( + &Expr::Cast { + expr: Box::new(Expr::Identifier(Ident::new("id"))), + data_type: DataType::Blob(None) + }, + expr_from_projection(only(&select.projection)) + ); + let sql = "SELECT CAST(id AS BLOB(50)) FROM customer"; let select = verified_only_select(sql); assert_eq!( &Expr::Cast { expr: Box::new(Expr::Identifier(Ident::new("id"))), - data_type: DataType::Blob(50) + data_type: DataType::Blob(Some(50)) }, expr_from_projection(only(&select.projection)) );