Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 44 additions & 3 deletions src/ast/data_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,11 @@ pub enum DataType {
///
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
Decimal(ExactNumberInfo),
/// [MySQL] unsigned decimal with optional precision and scale, e.g. DECIMAL UNSIGNED or DECIMAL(10,2) UNSIGNED.
/// Note: Using UNSIGNED with DECIMAL is deprecated in recent versions of MySQL.
///
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
DecimalUnsigned(ExactNumberInfo),
/// [BigNumeric] type used in BigQuery.
///
/// [BigNumeric]: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#bignumeric_literals
Expand All @@ -143,8 +148,19 @@ pub enum DataType {
///
/// [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<u64>),
/// [MySQL] unsigned decimal (DEC alias) with optional precision and scale, e.g. DEC UNSIGNED or DEC(10,2) UNSIGNED.
/// Note: Using UNSIGNED with DEC is deprecated in recent versions of MySQL.
///
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
DecUnsigned(ExactNumberInfo),
/// Floating point with optional precision and scale, e.g. FLOAT, FLOAT(8), or FLOAT(8,2).
Float(ExactNumberInfo),
/// [MySQL] unsigned floating point with optional precision and scale, e.g.
/// FLOAT UNSIGNED, FLOAT(10) UNSIGNED or FLOAT(10,2) UNSIGNED.
/// Note: Using UNSIGNED with FLOAT is deprecated in recent versions of MySQL.
///
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
FloatUnsigned(ExactNumberInfo),
/// Tiny integer with optional display width, e.g. TINYINT or TINYINT(3).
TinyInt(Option<u64>),
/// Unsigned tiny integer with optional display width,
Expand Down Expand Up @@ -302,17 +318,32 @@ pub enum DataType {
Float64,
/// Floating point, e.g. REAL.
Real,
/// [MySQL] unsigned real, e.g. REAL UNSIGNED.
/// Note: Using UNSIGNED with REAL is deprecated in recent versions of MySQL.
///
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
RealUnsigned,
/// Float8 is an alias for Double in [PostgreSQL].
///
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html
Float8,
/// Double
Double(ExactNumberInfo),
/// [MySQL] unsigned double precision with optional precision, e.g. DOUBLE UNSIGNED or DOUBLE(10,2) UNSIGNED.
/// Note: Using UNSIGNED with DOUBLE is deprecated in recent versions of MySQL.
///
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
DoubleUnsigned(ExactNumberInfo),
/// Double Precision, see [SQL Standard], [PostgreSQL].
///
/// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#approximate-numeric-type
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype-numeric.html
DoublePrecision,
/// [MySQL] unsigned double precision, e.g. DOUBLE PRECISION UNSIGNED.
/// Note: Using UNSIGNED with DOUBLE PRECISION is deprecated in recent versions of MySQL.
///
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
DoublePrecisionUnsigned,
/// Bool is an alias for Boolean, see [PostgreSQL].
///
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html
Expand Down Expand Up @@ -497,12 +528,19 @@ impl fmt::Display for DataType {
DataType::Decimal(info) => {
write!(f, "DECIMAL{info}")
}
DataType::DecimalUnsigned(info) => {
write!(f, "DECIMAL{info} UNSIGNED")
}
DataType::Dec(info) => {
write!(f, "DEC{info}")
}
DataType::DecUnsigned(info) => {
write!(f, "DEC{info} UNSIGNED")
}
DataType::BigNumeric(info) => write!(f, "BIGNUMERIC{info}"),
DataType::BigDecimal(info) => write!(f, "BIGDECIMAL{info}"),
DataType::Float(size) => format_type_with_optional_length(f, "FLOAT", size, false),
DataType::Float(info) => write!(f, "FLOAT{info}"),
DataType::FloatUnsigned(info) => write!(f, "FLOAT{info} UNSIGNED"),
DataType::TinyInt(zerofill) => {
format_type_with_optional_length(f, "TINYINT", zerofill, false)
}
Expand Down Expand Up @@ -616,12 +654,15 @@ impl fmt::Display for DataType {
write!(f, "UNSIGNED INTEGER")
}
DataType::Real => write!(f, "REAL"),
DataType::RealUnsigned => write!(f, "REAL UNSIGNED"),
DataType::Float4 => write!(f, "FLOAT4"),
DataType::Float32 => write!(f, "Float32"),
DataType::Float64 => write!(f, "FLOAT64"),
DataType::Double(info) => write!(f, "DOUBLE{info}"),
DataType::DoubleUnsigned(info) => write!(f, "DOUBLE{info} UNSIGNED"),
DataType::Float8 => write!(f, "FLOAT8"),
DataType::DoublePrecision => write!(f, "DOUBLE PRECISION"),
DataType::DoublePrecisionUnsigned => write!(f, "DOUBLE PRECISION UNSIGNED"),
DataType::Bool => write!(f, "BOOL"),
DataType::Boolean => write!(f, "BOOLEAN"),
DataType::Date => write!(f, "DATE"),
Expand Down
58 changes: 46 additions & 12 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10181,19 +10181,41 @@ impl<'a> Parser<'a> {
Token::Word(w) => match w.keyword {
Keyword::BOOLEAN => Ok(DataType::Boolean),
Keyword::BOOL => Ok(DataType::Bool),
Keyword::FLOAT => Ok(DataType::Float(self.parse_optional_precision()?)),
Keyword::REAL => Ok(DataType::Real),
Keyword::FLOAT => {
let precision = self.parse_exact_number_optional_precision_scale()?;

if self.parse_keyword(Keyword::UNSIGNED) {
Ok(DataType::FloatUnsigned(precision))
} else {
Ok(DataType::Float(precision))
}
}
Keyword::REAL => {
if self.parse_keyword(Keyword::UNSIGNED) {
Ok(DataType::RealUnsigned)
} else {
Ok(DataType::Real)
}
}
Keyword::FLOAT4 => Ok(DataType::Float4),
Keyword::FLOAT32 => Ok(DataType::Float32),
Keyword::FLOAT64 => Ok(DataType::Float64),
Keyword::FLOAT8 => Ok(DataType::Float8),
Keyword::DOUBLE => {
if self.parse_keyword(Keyword::PRECISION) {
Ok(DataType::DoublePrecision)
if self.parse_keyword(Keyword::UNSIGNED) {
Ok(DataType::DoublePrecisionUnsigned)
} else {
Ok(DataType::DoublePrecision)
}
} else {
Ok(DataType::Double(
self.parse_exact_number_optional_precision_scale()?,
))
let precision = self.parse_exact_number_optional_precision_scale()?;

if self.parse_keyword(Keyword::UNSIGNED) {
Ok(DataType::DoubleUnsigned(precision))
} else {
Ok(DataType::Double(precision))
}
}
}
Keyword::TINYINT => {
Expand Down Expand Up @@ -10420,12 +10442,24 @@ impl<'a> Parser<'a> {
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::DECIMAL => {
let precision = self.parse_exact_number_optional_precision_scale()?;

if self.parse_keyword(Keyword::UNSIGNED) {
Ok(DataType::DecimalUnsigned(precision))
} else {
Ok(DataType::Decimal(precision))
}
}
Keyword::DEC => {
let precision = self.parse_exact_number_optional_precision_scale()?;

if self.parse_keyword(Keyword::UNSIGNED) {
Ok(DataType::DecUnsigned(precision))
} else {
Ok(DataType::Dec(precision))
}
}
Keyword::BIGNUMERIC => Ok(DataType::BigNumeric(
self.parse_exact_number_optional_precision_scale()?,
)),
Expand Down
92 changes: 92 additions & 0 deletions tests/sqlparser_mysql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,98 @@ fn parse_signed_data_types() {
.expect_err("SIGNED suffix should not be allowed");
}

#[test]
fn parse_deprecated_mysql_unsigned_data_types() {
let sql = "CREATE TABLE foo (bar_decimal DECIMAL UNSIGNED, bar_decimal_prec DECIMAL(10) UNSIGNED, bar_decimal_scale DECIMAL(10,2) UNSIGNED, bar_dec DEC UNSIGNED, bar_dec_prec DEC(10) UNSIGNED, bar_dec_scale DEC(10,2) UNSIGNED, bar_float FLOAT UNSIGNED, bar_float_prec FLOAT(10) UNSIGNED, bar_float_scale FLOAT(10,2) UNSIGNED, bar_double DOUBLE UNSIGNED, bar_double_prec DOUBLE(10) UNSIGNED, bar_double_scale DOUBLE(10,2) UNSIGNED, bar_real REAL UNSIGNED, bar_double_precision DOUBLE PRECISION UNSIGNED)";
match mysql().verified_stmt(sql) {
Statement::CreateTable(CreateTable { name, columns, .. }) => {
assert_eq!(name.to_string(), "foo");
assert_eq!(
vec![
ColumnDef {
name: Ident::new("bar_decimal"),
data_type: DataType::DecimalUnsigned(ExactNumberInfo::None),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_decimal_prec"),
data_type: DataType::DecimalUnsigned(ExactNumberInfo::Precision(10)),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_decimal_scale"),
data_type: DataType::DecimalUnsigned(ExactNumberInfo::PrecisionAndScale(
10, 2
)),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_dec"),
data_type: DataType::DecUnsigned(ExactNumberInfo::None),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_dec_prec"),
data_type: DataType::DecUnsigned(ExactNumberInfo::Precision(10)),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_dec_scale"),
data_type: DataType::DecUnsigned(ExactNumberInfo::PrecisionAndScale(10, 2)),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_float"),
data_type: DataType::FloatUnsigned(ExactNumberInfo::None),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_float_prec"),
data_type: DataType::FloatUnsigned(ExactNumberInfo::Precision(10)),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_float_scale"),
data_type: DataType::FloatUnsigned(ExactNumberInfo::PrecisionAndScale(
10, 2
)),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_double"),
data_type: DataType::DoubleUnsigned(ExactNumberInfo::None),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_double_prec"),
data_type: DataType::DoubleUnsigned(ExactNumberInfo::Precision(10)),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_double_scale"),
data_type: DataType::DoubleUnsigned(ExactNumberInfo::PrecisionAndScale(
10, 2
)),
options: vec![],
},
ColumnDef {
name: Ident::new("bar_real"),
data_type: DataType::RealUnsigned,
options: vec![],
},
ColumnDef {
name: Ident::new("bar_double_precision"),
data_type: DataType::DoublePrecisionUnsigned,
options: vec![],
},
],
columns
);
}
_ => unreachable!(),
}
}

#[test]
fn parse_simple_insert() {
let sql = r"INSERT INTO tasks (title, priority) VALUES ('Test Some Inserts', 1), ('Test Entry 2', 2), ('Test Entry 3', 3)";
Expand Down