Skip to content

Commit 3f70716

Browse files
committed
Parse SIGNED INTEGER type in MySQL CAST
MySQL doesn't have the same set of possible CAST types as for e.g. column definitions. For example, it raises a syntax error for `CAST(1 AS INTEGER SIGNED)` and instead expects `CAST(1 AS SIGNED INTEGER)`. We retain the current somewhat permissive datatype parsing behavior (e.g. allowing `CAST(1 AS BIGINT)` even though MySQL would raise a syntax error), and add datatypes for this specific case (`SIGNED [INTEGER]` and `UNSIGNED [INTEGER]`). To keep the naming consistent across datatypes, we also rename `UnsignedInt` to `IntUnsigned` and similar for other unsigned datatypes. This means they display in the same way they are written, i.e. `IntUnsigned = INT UNSIGNED` instead of `UnsignedInt = INT UNSIGNED`. Closes apache#1589
1 parent 648efd7 commit 3f70716

File tree

5 files changed

+101
-35
lines changed

5 files changed

+101
-35
lines changed

src/ast/data_type.rs

Lines changed: 51 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -132,27 +132,27 @@ pub enum DataType {
132132
/// Tiny integer with optional display width e.g. TINYINT or TINYINT(3)
133133
TinyInt(Option<u64>),
134134
/// Unsigned tiny integer with optional display width e.g. TINYINT UNSIGNED or TINYINT(3) UNSIGNED
135-
UnsignedTinyInt(Option<u64>),
135+
TinyIntUnsigned(Option<u64>),
136136
/// Int2 as alias for SmallInt in [postgresql]
137137
/// Note: Int2 mean 2 bytes in postgres (not 2 bits)
138138
/// Int2 with optional display width e.g. INT2 or INT2(5)
139139
///
140140
/// [postgresql]: https://www.postgresql.org/docs/15/datatype.html
141141
Int2(Option<u64>),
142-
/// Unsigned Int2 with optional display width e.g. INT2 Unsigned or INT2(5) Unsigned
143-
UnsignedInt2(Option<u64>),
142+
/// Unsigned Int2 with optional display width e.g. INT2 UNSIGNED or INT2(5) UNSIGNED
143+
Int2Unsigned(Option<u64>),
144144
/// Small integer with optional display width e.g. SMALLINT or SMALLINT(5)
145145
SmallInt(Option<u64>),
146146
/// Unsigned small integer with optional display width e.g. SMALLINT UNSIGNED or SMALLINT(5) UNSIGNED
147-
UnsignedSmallInt(Option<u64>),
147+
SmallIntUnsigned(Option<u64>),
148148
/// MySQL medium integer ([1]) with optional display width e.g. MEDIUMINT or MEDIUMINT(5)
149149
///
150150
/// [1]: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html
151151
MediumInt(Option<u64>),
152152
/// Unsigned medium integer ([1]) with optional display width e.g. MEDIUMINT UNSIGNED or MEDIUMINT(5) UNSIGNED
153153
///
154154
/// [1]: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html
155-
UnsignedMediumInt(Option<u64>),
155+
MediumIntUnsigned(Option<u64>),
156156
/// Int with optional display width e.g. INT or INT(11)
157157
Int(Option<u64>),
158158
/// Int4 as alias for Integer in [postgresql]
@@ -197,11 +197,11 @@ pub enum DataType {
197197
/// Integer with optional display width e.g. INTEGER or INTEGER(11)
198198
Integer(Option<u64>),
199199
/// Unsigned int with optional display width e.g. INT UNSIGNED or INT(11) UNSIGNED
200-
UnsignedInt(Option<u64>),
200+
IntUnsigned(Option<u64>),
201201
/// Unsigned int4 with optional display width e.g. INT4 UNSIGNED or INT4(11) UNSIGNED
202-
UnsignedInt4(Option<u64>),
202+
Int4Unsigned(Option<u64>),
203203
/// Unsigned integer with optional display width e.g. INTEGER UNSIGNED or INTEGER(11) UNSIGNED
204-
UnsignedInteger(Option<u64>),
204+
IntegerUnsigned(Option<u64>),
205205
/// Unsigned integer type in [clickhouse]
206206
/// Note: UInt8 mean 8 bits in [clickhouse]
207207
///
@@ -235,9 +235,29 @@ pub enum DataType {
235235
/// Big integer with optional display width e.g. BIGINT or BIGINT(20)
236236
BigInt(Option<u64>),
237237
/// Unsigned big integer with optional display width e.g. BIGINT UNSIGNED or BIGINT(20) UNSIGNED
238-
UnsignedBigInt(Option<u64>),
238+
BigIntUnsigned(Option<u64>),
239239
/// Unsigned Int8 with optional display width e.g. INT8 UNSIGNED or INT8(11) UNSIGNED
240-
UnsignedInt8(Option<u64>),
240+
Int8Unsigned(Option<u64>),
241+
/// Signed integer as used in [MySQL CAST] target types, without optional `INTEGER` suffix:
242+
/// `SIGNED`
243+
///
244+
/// [MySQL CAST]: https://dev.mysql.com/doc/refman/8.4/en/cast-functions.html
245+
Signed,
246+
/// Signed integer as used in [MySQL CAST] target types, with optional `INTEGER` suffix:
247+
/// `SIGNED INTEGER`
248+
///
249+
/// [MySQL CAST]: https://dev.mysql.com/doc/refman/8.4/en/cast-functions.html
250+
SignedInteger,
251+
/// Signed integer as used in [MySQL CAST] target types, without optional `INTEGER` suffix:
252+
/// `SIGNED`
253+
///
254+
/// [MySQL CAST]: https://dev.mysql.com/doc/refman/8.4/en/cast-functions.html
255+
Unsigned,
256+
/// Unsigned integer as used in [MySQL CAST] target types, with optional `INTEGER` suffix:
257+
/// `UNSIGNED INTEGER`
258+
///
259+
/// [MySQL CAST]: https://dev.mysql.com/doc/refman/8.4/en/cast-functions.html
260+
UnsignedInteger,
241261
/// Float4 as alias for Real in [postgresql]
242262
///
243263
/// [postgresql]: https://www.postgresql.org/docs/15/datatype.html
@@ -433,29 +453,29 @@ impl fmt::Display for DataType {
433453
DataType::TinyInt(zerofill) => {
434454
format_type_with_optional_length(f, "TINYINT", zerofill, false)
435455
}
436-
DataType::UnsignedTinyInt(zerofill) => {
456+
DataType::TinyIntUnsigned(zerofill) => {
437457
format_type_with_optional_length(f, "TINYINT", zerofill, true)
438458
}
439459
DataType::Int2(zerofill) => {
440460
format_type_with_optional_length(f, "INT2", zerofill, false)
441461
}
442-
DataType::UnsignedInt2(zerofill) => {
462+
DataType::Int2Unsigned(zerofill) => {
443463
format_type_with_optional_length(f, "INT2", zerofill, true)
444464
}
445465
DataType::SmallInt(zerofill) => {
446466
format_type_with_optional_length(f, "SMALLINT", zerofill, false)
447467
}
448-
DataType::UnsignedSmallInt(zerofill) => {
468+
DataType::SmallIntUnsigned(zerofill) => {
449469
format_type_with_optional_length(f, "SMALLINT", zerofill, true)
450470
}
451471
DataType::MediumInt(zerofill) => {
452472
format_type_with_optional_length(f, "MEDIUMINT", zerofill, false)
453473
}
454-
DataType::UnsignedMediumInt(zerofill) => {
474+
DataType::MediumIntUnsigned(zerofill) => {
455475
format_type_with_optional_length(f, "MEDIUMINT", zerofill, true)
456476
}
457477
DataType::Int(zerofill) => format_type_with_optional_length(f, "INT", zerofill, false),
458-
DataType::UnsignedInt(zerofill) => {
478+
DataType::IntUnsigned(zerofill) => {
459479
format_type_with_optional_length(f, "INT", zerofill, true)
460480
}
461481
DataType::Int4(zerofill) => {
@@ -479,22 +499,22 @@ impl fmt::Display for DataType {
479499
DataType::Int256 => {
480500
write!(f, "Int256")
481501
}
482-
DataType::UnsignedInt4(zerofill) => {
502+
DataType::Int4Unsigned(zerofill) => {
483503
format_type_with_optional_length(f, "INT4", zerofill, true)
484504
}
485505
DataType::Integer(zerofill) => {
486506
format_type_with_optional_length(f, "INTEGER", zerofill, false)
487507
}
488-
DataType::UnsignedInteger(zerofill) => {
508+
DataType::IntegerUnsigned(zerofill) => {
489509
format_type_with_optional_length(f, "INTEGER", zerofill, true)
490510
}
491511
DataType::BigInt(zerofill) => {
492512
format_type_with_optional_length(f, "BIGINT", zerofill, false)
493513
}
494-
DataType::UnsignedBigInt(zerofill) => {
514+
DataType::BigIntUnsigned(zerofill) => {
495515
format_type_with_optional_length(f, "BIGINT", zerofill, true)
496516
}
497-
DataType::UnsignedInt8(zerofill) => {
517+
DataType::Int8Unsigned(zerofill) => {
498518
format_type_with_optional_length(f, "INT8", zerofill, true)
499519
}
500520
DataType::UInt8 => {
@@ -515,6 +535,18 @@ impl fmt::Display for DataType {
515535
DataType::UInt256 => {
516536
write!(f, "UInt256")
517537
}
538+
DataType::Signed => {
539+
write!(f, "SIGNED")
540+
}
541+
DataType::SignedInteger => {
542+
write!(f, "SIGNED INTEGER")
543+
}
544+
DataType::Unsigned => {
545+
write!(f, "UNSIGNED")
546+
}
547+
DataType::UnsignedInteger => {
548+
write!(f, "UNSIGNED INTEGER")
549+
}
518550
DataType::Real => write!(f, "REAL"),
519551
DataType::Float4 => write!(f, "FLOAT4"),
520552
DataType::Float32 => write!(f, "Float32"),

src/ast/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -814,8 +814,9 @@ pub enum Expr {
814814
kind: CastKind,
815815
expr: Box<Expr>,
816816
data_type: DataType,
817-
// Optional CAST(string_expression AS type FORMAT format_string_expression) as used by BigQuery
818-
// https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#formatting_syntax
817+
/// Optional CAST(string_expression AS type FORMAT format_string_expression) as used by [BigQuery]
818+
///
819+
/// [BigQuery]: https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#formatting_syntax
819820
format: Option<CastFormat>,
820821
},
821822
/// AT a timestamp to a different timezone e.g. `FROM_UNIXTIME(0) AT TIME ZONE 'UTC-06:00'`

src/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ define_keywords!(
790790
SHARE,
791791
SHARING,
792792
SHOW,
793+
SIGNED,
793794
SIMILAR,
794795
SKIP,
795796
SLOW,

src/parser/mod.rs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8867,55 +8867,55 @@ impl<'a> Parser<'a> {
88678867
Keyword::TINYINT => {
88688868
let optional_precision = self.parse_optional_precision();
88698869
if self.parse_keyword(Keyword::UNSIGNED) {
8870-
Ok(DataType::UnsignedTinyInt(optional_precision?))
8870+
Ok(DataType::TinyIntUnsigned(optional_precision?))
88718871
} else {
88728872
Ok(DataType::TinyInt(optional_precision?))
88738873
}
88748874
}
88758875
Keyword::INT2 => {
88768876
let optional_precision = self.parse_optional_precision();
88778877
if self.parse_keyword(Keyword::UNSIGNED) {
8878-
Ok(DataType::UnsignedInt2(optional_precision?))
8878+
Ok(DataType::Int2Unsigned(optional_precision?))
88798879
} else {
88808880
Ok(DataType::Int2(optional_precision?))
88818881
}
88828882
}
88838883
Keyword::SMALLINT => {
88848884
let optional_precision = self.parse_optional_precision();
88858885
if self.parse_keyword(Keyword::UNSIGNED) {
8886-
Ok(DataType::UnsignedSmallInt(optional_precision?))
8886+
Ok(DataType::SmallIntUnsigned(optional_precision?))
88878887
} else {
88888888
Ok(DataType::SmallInt(optional_precision?))
88898889
}
88908890
}
88918891
Keyword::MEDIUMINT => {
88928892
let optional_precision = self.parse_optional_precision();
88938893
if self.parse_keyword(Keyword::UNSIGNED) {
8894-
Ok(DataType::UnsignedMediumInt(optional_precision?))
8894+
Ok(DataType::MediumIntUnsigned(optional_precision?))
88958895
} else {
88968896
Ok(DataType::MediumInt(optional_precision?))
88978897
}
88988898
}
88998899
Keyword::INT => {
89008900
let optional_precision = self.parse_optional_precision();
89018901
if self.parse_keyword(Keyword::UNSIGNED) {
8902-
Ok(DataType::UnsignedInt(optional_precision?))
8902+
Ok(DataType::IntUnsigned(optional_precision?))
89038903
} else {
89048904
Ok(DataType::Int(optional_precision?))
89058905
}
89068906
}
89078907
Keyword::INT4 => {
89088908
let optional_precision = self.parse_optional_precision();
89098909
if self.parse_keyword(Keyword::UNSIGNED) {
8910-
Ok(DataType::UnsignedInt4(optional_precision?))
8910+
Ok(DataType::Int4Unsigned(optional_precision?))
89118911
} else {
89128912
Ok(DataType::Int4(optional_precision?))
89138913
}
89148914
}
89158915
Keyword::INT8 => {
89168916
let optional_precision = self.parse_optional_precision();
89178917
if self.parse_keyword(Keyword::UNSIGNED) {
8918-
Ok(DataType::UnsignedInt8(optional_precision?))
8918+
Ok(DataType::Int8Unsigned(optional_precision?))
89198919
} else {
89208920
Ok(DataType::Int8(optional_precision?))
89218921
}
@@ -8928,15 +8928,15 @@ impl<'a> Parser<'a> {
89288928
Keyword::INTEGER => {
89298929
let optional_precision = self.parse_optional_precision();
89308930
if self.parse_keyword(Keyword::UNSIGNED) {
8931-
Ok(DataType::UnsignedInteger(optional_precision?))
8931+
Ok(DataType::IntegerUnsigned(optional_precision?))
89328932
} else {
89338933
Ok(DataType::Integer(optional_precision?))
89348934
}
89358935
}
89368936
Keyword::BIGINT => {
89378937
let optional_precision = self.parse_optional_precision();
89388938
if self.parse_keyword(Keyword::UNSIGNED) {
8939-
Ok(DataType::UnsignedBigInt(optional_precision?))
8939+
Ok(DataType::BigIntUnsigned(optional_precision?))
89408940
} else {
89418941
Ok(DataType::BigInt(optional_precision?))
89428942
}
@@ -9142,6 +9142,20 @@ impl<'a> Parser<'a> {
91429142
let columns = self.parse_returns_table_columns()?;
91439143
Ok(DataType::Table(columns))
91449144
}
9145+
Keyword::SIGNED => {
9146+
if self.parse_keyword(Keyword::INTEGER) {
9147+
Ok(DataType::SignedInteger)
9148+
} else {
9149+
Ok(DataType::Signed)
9150+
}
9151+
}
9152+
Keyword::UNSIGNED => {
9153+
if self.parse_keyword(Keyword::INTEGER) {
9154+
Ok(DataType::UnsignedInteger)
9155+
} else {
9156+
Ok(DataType::Unsigned)
9157+
}
9158+
}
91459159
_ => {
91469160
self.prev_token();
91479161
let type_name = self.parse_object_name(false)?;

tests/sqlparser_mysql.rs

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1359,27 +1359,27 @@ fn parse_create_table_unsigned() {
13591359
vec![
13601360
ColumnDef {
13611361
name: Ident::new("bar_tinyint"),
1362-
data_type: DataType::UnsignedTinyInt(Some(3)),
1362+
data_type: DataType::TinyIntUnsigned(Some(3)),
13631363
options: vec![],
13641364
},
13651365
ColumnDef {
13661366
name: Ident::new("bar_smallint"),
1367-
data_type: DataType::UnsignedSmallInt(Some(5)),
1367+
data_type: DataType::SmallIntUnsigned(Some(5)),
13681368
options: vec![],
13691369
},
13701370
ColumnDef {
13711371
name: Ident::new("bar_mediumint"),
1372-
data_type: DataType::UnsignedMediumInt(Some(13)),
1372+
data_type: DataType::MediumIntUnsigned(Some(13)),
13731373
options: vec![],
13741374
},
13751375
ColumnDef {
13761376
name: Ident::new("bar_int"),
1377-
data_type: DataType::UnsignedInt(Some(11)),
1377+
data_type: DataType::IntUnsigned(Some(11)),
13781378
options: vec![],
13791379
},
13801380
ColumnDef {
13811381
name: Ident::new("bar_bigint"),
1382-
data_type: DataType::UnsignedBigInt(Some(20)),
1382+
data_type: DataType::BigIntUnsigned(Some(20)),
13831383
options: vec![],
13841384
},
13851385
],
@@ -3339,3 +3339,21 @@ fn parse_drop_trigger() {
33393339
}
33403340
);
33413341
}
3342+
3343+
#[test]
3344+
fn parse_cast_integers() {
3345+
mysql().verified_expr("CAST(foo AS UNSIGNED)");
3346+
mysql().verified_expr("CAST(foo AS SIGNED)");
3347+
mysql().verified_expr("CAST(foo AS UNSIGNED INTEGER)");
3348+
mysql().verified_expr("CAST(foo AS SIGNED INTEGER)");
3349+
3350+
mysql()
3351+
.run_parser_method("CAST(foo AS UNSIGNED(3))", |p| p.parse_expr())
3352+
.expect_err("CAST doesn't allow display width");
3353+
mysql()
3354+
.run_parser_method("CAST(foo AS UNSIGNED(3) INTEGER)", |p| p.parse_expr())
3355+
.expect_err("CAST doesn't allow display width");
3356+
mysql()
3357+
.run_parser_method("CAST(foo AS UNSIGNED INTEGER(3))", |p| p.parse_expr())
3358+
.expect_err("CAST doesn't allow display width");
3359+
}

0 commit comments

Comments
 (0)