Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit ea7f902

Browse files
MySQL: Add support for unsigned numeric types (#2031)
1 parent f642dd5 commit ea7f902

File tree

3 files changed

+182
-15
lines changed

3 files changed

+182
-15
lines changed

‎src/ast/data_type.rs‎

Lines changed: 44 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ pub enum DataType {
131131
///
132132
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
133133
Decimal(ExactNumberInfo),
134+
/// [MySQL] unsigned decimal with optional precision and scale, e.g. DECIMAL UNSIGNED or DECIMAL(10,2) UNSIGNED.
135+
/// Note: Using UNSIGNED with DECIMAL is deprecated in recent versions of MySQL.
136+
///
137+
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
138+
DecimalUnsigned(ExactNumberInfo),
134139
/// [BigNumeric] type used in BigQuery.
135140
///
136141
/// [BigNumeric]: https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#bignumeric_literals
@@ -143,8 +148,19 @@ pub enum DataType {
143148
///
144149
/// [1]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#exact-numeric-type
145150
Dec(ExactNumberInfo),
146-
/// Floating point with optional precision, e.g. FLOAT(8).
147-
Float(Option<u64>),
151+
/// [MySQL] unsigned decimal (DEC alias) with optional precision and scale, e.g. DEC UNSIGNED or DEC(10,2) UNSIGNED.
152+
/// Note: Using UNSIGNED with DEC is deprecated in recent versions of MySQL.
153+
///
154+
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
155+
DecUnsigned(ExactNumberInfo),
156+
/// Floating point with optional precision and scale, e.g. FLOAT, FLOAT(8), or FLOAT(8,2).
157+
Float(ExactNumberInfo),
158+
/// [MySQL] unsigned floating point with optional precision and scale, e.g.
159+
/// FLOAT UNSIGNED, FLOAT(10) UNSIGNED or FLOAT(10,2) UNSIGNED.
160+
/// Note: Using UNSIGNED with FLOAT is deprecated in recent versions of MySQL.
161+
///
162+
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
163+
FloatUnsigned(ExactNumberInfo),
148164
/// Tiny integer with optional display width, e.g. TINYINT or TINYINT(3).
149165
TinyInt(Option<u64>),
150166
/// Unsigned tiny integer with optional display width,
@@ -302,17 +318,32 @@ pub enum DataType {
302318
Float64,
303319
/// Floating point, e.g. REAL.
304320
Real,
321+
/// [MySQL] unsigned real, e.g. REAL UNSIGNED.
322+
/// Note: Using UNSIGNED with REAL is deprecated in recent versions of MySQL.
323+
///
324+
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
325+
RealUnsigned,
305326
/// Float8 is an alias for Double in [PostgreSQL].
306327
///
307328
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html
308329
Float8,
309330
/// Double
310331
Double(ExactNumberInfo),
332+
/// [MySQL] unsigned double precision with optional precision, e.g. DOUBLE UNSIGNED or DOUBLE(10,2) UNSIGNED.
333+
/// Note: Using UNSIGNED with DOUBLE is deprecated in recent versions of MySQL.
334+
///
335+
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
336+
DoubleUnsigned(ExactNumberInfo),
311337
/// Double Precision, see [SQL Standard], [PostgreSQL].
312338
///
313339
/// [SQL Standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#approximate-numeric-type
314340
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype-numeric.html
315341
DoublePrecision,
342+
/// [MySQL] unsigned double precision, e.g. DOUBLE PRECISION UNSIGNED.
343+
/// Note: Using UNSIGNED with DOUBLE PRECISION is deprecated in recent versions of MySQL.
344+
///
345+
/// [MySQL]: https://dev.mysql.com/doc/refman/8.4/en/numeric-type-syntax.html
346+
DoublePrecisionUnsigned,
316347
/// Bool is an alias for Boolean, see [PostgreSQL].
317348
///
318349
/// [PostgreSQL]: https://www.postgresql.org/docs/current/datatype.html
@@ -497,12 +528,19 @@ impl fmt::Display for DataType {
497528
DataType::Decimal(info) => {
498529
write!(f, "DECIMAL{info}")
499530
}
531+
DataType::DecimalUnsigned(info) => {
532+
write!(f, "DECIMAL{info} UNSIGNED")
533+
}
500534
DataType::Dec(info) => {
501535
write!(f, "DEC{info}")
502536
}
537+
DataType::DecUnsigned(info) => {
538+
write!(f, "DEC{info} UNSIGNED")
539+
}
503540
DataType::BigNumeric(info) => write!(f, "BIGNUMERIC{info}"),
504541
DataType::BigDecimal(info) => write!(f, "BIGDECIMAL{info}"),
505-
DataType::Float(size) => format_type_with_optional_length(f, "FLOAT", size, false),
542+
DataType::Float(info) => write!(f, "FLOAT{info}"),
543+
DataType::FloatUnsigned(info) => write!(f, "FLOAT{info} UNSIGNED"),
506544
DataType::TinyInt(zerofill) => {
507545
format_type_with_optional_length(f, "TINYINT", zerofill, false)
508546
}
@@ -616,12 +654,15 @@ impl fmt::Display for DataType {
616654
write!(f, "UNSIGNED INTEGER")
617655
}
618656
DataType::Real => write!(f, "REAL"),
657+
DataType::RealUnsigned => write!(f, "REAL UNSIGNED"),
619658
DataType::Float4 => write!(f, "FLOAT4"),
620659
DataType::Float32 => write!(f, "Float32"),
621660
DataType::Float64 => write!(f, "FLOAT64"),
622661
DataType::Double(info) => write!(f, "DOUBLE{info}"),
662+
DataType::DoubleUnsigned(info) => write!(f, "DOUBLE{info} UNSIGNED"),
623663
DataType::Float8 => write!(f, "FLOAT8"),
624664
DataType::DoublePrecision => write!(f, "DOUBLE PRECISION"),
665+
DataType::DoublePrecisionUnsigned => write!(f, "DOUBLE PRECISION UNSIGNED"),
625666
DataType::Bool => write!(f, "BOOL"),
626667
DataType::Boolean => write!(f, "BOOLEAN"),
627668
DataType::Date => write!(f, "DATE"),

‎src/parser/mod.rs‎

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10181,19 +10181,41 @@ impl<'a> Parser<'a> {
1018110181
Token::Word(w) => match w.keyword {
1018210182
Keyword::BOOLEAN => Ok(DataType::Boolean),
1018310183
Keyword::BOOL => Ok(DataType::Bool),
10184-
Keyword::FLOAT => Ok(DataType::Float(self.parse_optional_precision()?)),
10185-
Keyword::REAL => Ok(DataType::Real),
10184+
Keyword::FLOAT => {
10185+
let precision = self.parse_exact_number_optional_precision_scale()?;
10186+
10187+
if self.parse_keyword(Keyword::UNSIGNED) {
10188+
Ok(DataType::FloatUnsigned(precision))
10189+
} else {
10190+
Ok(DataType::Float(precision))
10191+
}
10192+
}
10193+
Keyword::REAL => {
10194+
if self.parse_keyword(Keyword::UNSIGNED) {
10195+
Ok(DataType::RealUnsigned)
10196+
} else {
10197+
Ok(DataType::Real)
10198+
}
10199+
}
1018610200
Keyword::FLOAT4 => Ok(DataType::Float4),
1018710201
Keyword::FLOAT32 => Ok(DataType::Float32),
1018810202
Keyword::FLOAT64 => Ok(DataType::Float64),
1018910203
Keyword::FLOAT8 => Ok(DataType::Float8),
1019010204
Keyword::DOUBLE => {
1019110205
if self.parse_keyword(Keyword::PRECISION) {
10192-
Ok(DataType::DoublePrecision)
10206+
if self.parse_keyword(Keyword::UNSIGNED) {
10207+
Ok(DataType::DoublePrecisionUnsigned)
10208+
} else {
10209+
Ok(DataType::DoublePrecision)
10210+
}
1019310211
} else {
10194-
Ok(DataType::Double(
10195-
self.parse_exact_number_optional_precision_scale()?,
10196-
))
10212+
let precision = self.parse_exact_number_optional_precision_scale()?;
10213+
10214+
if self.parse_keyword(Keyword::UNSIGNED) {
10215+
Ok(DataType::DoubleUnsigned(precision))
10216+
} else {
10217+
Ok(DataType::Double(precision))
10218+
}
1019710219
}
1019810220
}
1019910221
Keyword::TINYINT => {
@@ -10420,12 +10442,24 @@ impl<'a> Parser<'a> {
1042010442
Keyword::NUMERIC => Ok(DataType::Numeric(
1042110443
self.parse_exact_number_optional_precision_scale()?,
1042210444
)),
10423-
Keyword::DECIMAL => Ok(DataType::Decimal(
10424-
self.parse_exact_number_optional_precision_scale()?,
10425-
)),
10426-
Keyword::DEC => Ok(DataType::Dec(
10427-
self.parse_exact_number_optional_precision_scale()?,
10428-
)),
10445+
Keyword::DECIMAL => {
10446+
let precision = self.parse_exact_number_optional_precision_scale()?;
10447+
10448+
if self.parse_keyword(Keyword::UNSIGNED) {
10449+
Ok(DataType::DecimalUnsigned(precision))
10450+
} else {
10451+
Ok(DataType::Decimal(precision))
10452+
}
10453+
}
10454+
Keyword::DEC => {
10455+
let precision = self.parse_exact_number_optional_precision_scale()?;
10456+
10457+
if self.parse_keyword(Keyword::UNSIGNED) {
10458+
Ok(DataType::DecUnsigned(precision))
10459+
} else {
10460+
Ok(DataType::Dec(precision))
10461+
}
10462+
}
1042910463
Keyword::BIGNUMERIC => Ok(DataType::BigNumeric(
1043010464
self.parse_exact_number_optional_precision_scale()?,
1043110465
)),

‎tests/sqlparser_mysql.rs‎

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1757,6 +1757,98 @@ fn parse_signed_data_types() {
17571757
.expect_err("SIGNED suffix should not be allowed");
17581758
}
17591759

1760+
#[test]
1761+
fn parse_deprecated_mysql_unsigned_data_types() {
1762+
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)";
1763+
match mysql().verified_stmt(sql) {
1764+
Statement::CreateTable(CreateTable { name, columns, .. }) => {
1765+
assert_eq!(name.to_string(), "foo");
1766+
assert_eq!(
1767+
vec![
1768+
ColumnDef {
1769+
name: Ident::new("bar_decimal"),
1770+
data_type: DataType::DecimalUnsigned(ExactNumberInfo::None),
1771+
options: vec![],
1772+
},
1773+
ColumnDef {
1774+
name: Ident::new("bar_decimal_prec"),
1775+
data_type: DataType::DecimalUnsigned(ExactNumberInfo::Precision(10)),
1776+
options: vec![],
1777+
},
1778+
ColumnDef {
1779+
name: Ident::new("bar_decimal_scale"),
1780+
data_type: DataType::DecimalUnsigned(ExactNumberInfo::PrecisionAndScale(
1781+
10, 2
1782+
)),
1783+
options: vec![],
1784+
},
1785+
ColumnDef {
1786+
name: Ident::new("bar_dec"),
1787+
data_type: DataType::DecUnsigned(ExactNumberInfo::None),
1788+
options: vec![],
1789+
},
1790+
ColumnDef {
1791+
name: Ident::new("bar_dec_prec"),
1792+
data_type: DataType::DecUnsigned(ExactNumberInfo::Precision(10)),
1793+
options: vec![],
1794+
},
1795+
ColumnDef {
1796+
name: Ident::new("bar_dec_scale"),
1797+
data_type: DataType::DecUnsigned(ExactNumberInfo::PrecisionAndScale(10, 2)),
1798+
options: vec![],
1799+
},
1800+
ColumnDef {
1801+
name: Ident::new("bar_float"),
1802+
data_type: DataType::FloatUnsigned(ExactNumberInfo::None),
1803+
options: vec![],
1804+
},
1805+
ColumnDef {
1806+
name: Ident::new("bar_float_prec"),
1807+
data_type: DataType::FloatUnsigned(ExactNumberInfo::Precision(10)),
1808+
options: vec![],
1809+
},
1810+
ColumnDef {
1811+
name: Ident::new("bar_float_scale"),
1812+
data_type: DataType::FloatUnsigned(ExactNumberInfo::PrecisionAndScale(
1813+
10, 2
1814+
)),
1815+
options: vec![],
1816+
},
1817+
ColumnDef {
1818+
name: Ident::new("bar_double"),
1819+
data_type: DataType::DoubleUnsigned(ExactNumberInfo::None),
1820+
options: vec![],
1821+
},
1822+
ColumnDef {
1823+
name: Ident::new("bar_double_prec"),
1824+
data_type: DataType::DoubleUnsigned(ExactNumberInfo::Precision(10)),
1825+
options: vec![],
1826+
},
1827+
ColumnDef {
1828+
name: Ident::new("bar_double_scale"),
1829+
data_type: DataType::DoubleUnsigned(ExactNumberInfo::PrecisionAndScale(
1830+
10, 2
1831+
)),
1832+
options: vec![],
1833+
},
1834+
ColumnDef {
1835+
name: Ident::new("bar_real"),
1836+
data_type: DataType::RealUnsigned,
1837+
options: vec![],
1838+
},
1839+
ColumnDef {
1840+
name: Ident::new("bar_double_precision"),
1841+
data_type: DataType::DoublePrecisionUnsigned,
1842+
options: vec![],
1843+
},
1844+
],
1845+
columns
1846+
);
1847+
}
1848+
_ => unreachable!(),
1849+
}
1850+
}
1851+
17601852
#[test]
17611853
fn parse_simple_insert() {
17621854
let sql = r"INSERT INTO tasks (title, priority) VALUES ('Test Some Inserts', 1), ('Test Entry 2', 2), ('Test Entry 3', 3)";

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /