Skip to content

Commit de4dbc5

Browse files
authored
Parse SIGNED INTEGER type in MySQL CAST (#1739)
1 parent 648efd7 commit de4dbc5

File tree

5 files changed

+101
-35
lines changed

5 files changed

+101
-35
lines changed

src/ast/data_type.rs

+51-19
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

+3-2
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

+1
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

+23-9
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

+23-5
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)