Skip to content

Commit 4507be8

Browse files
authored
Merge branch 'main' into ast-visitor
2 parents 1d09ff4 + c2d6825 commit 4507be8

10 files changed

+205
-14
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,29 @@ Given that the parser produces a typed AST, any changes to the AST will technica
88
## [Unreleased]
99
Check https://github.com/sqlparser-rs/sqlparser-rs/commits/main for undocumented changes.
1010

11+
## [0.24.0] 2022-09-29
12+
13+
### Added
14+
15+
* Support `MILLENNIUM` (2 Ns) (#633) - Thanks @sarahyurick
16+
* Support `MEDIUMINT` (#630) - Thanks @AugustoFKL
17+
* Support `DOUBLE PRECISION` (#629) - Thanks @AugustoFKL
18+
* Support precision in `CLOB`, `BINARY`, `VARBINARY`, `BLOB` data type (#618) - Thanks @ding-young
19+
* Support `CREATE ROLE` and `DROP ROLE` (#598) - Thanks @blx
20+
* Support full range of sqlite prepared statement placeholders (#604) - Thanks @lovasoa
21+
* Support National string literal with lower case `n` (#612) - Thanks @mskrzypkows
22+
* Support SHOW FUNCTIONS (#620) - Thanks @joocer
23+
* Support `set time zone to 'some-timezone'` (#617) - Thanks @waitingkuo
24+
25+
### Changed
26+
* Move `Value::Interval` to `Expr::Interval` (#609) - Thanks @ding-young
27+
* Update `criterion` dev-requirement from 0.3 to 0.4 in /sqlparser_bench (#611) - Thanks @dependabot
28+
* Box `Query` in `Cte` (#572) - Thanks @MazterQyou
29+
30+
### Other
31+
* Disambiguate CREATE ROLE ... USER and GROUP (#628) - Thanks @alamb
32+
* Add test for optional WITH in CREATE ROLE (#627) - Thanks @alamb
33+
1134
## [0.23.0] 2022-09-08
1235

1336
### Added

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "sqlparser"
33
description = "Extensible SQL Lexer and Parser with support for ANSI SQL:2011"
4-
version = "0.23.0"
4+
version = "0.24.0"
55
authors = ["Andy Grove <[email protected]>"]
66
homepage = "https://github.com/sqlparser-rs/sqlparser-rs"
77
documentation = "https://docs.rs/sqlparser/"

src/ast/data_type.rs

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,14 @@ pub enum DataType {
6060
SmallInt(#[cfg_attr(feature = "derive-visitor", drive(skip))] Option<u64>),
6161
/// Unsigned small integer with optional display width e.g. SMALLINT UNSIGNED or SMALLINT(5) UNSIGNED
6262
UnsignedSmallInt(#[cfg_attr(feature = "derive-visitor", drive(skip))] Option<u64>),
63+
/// MySQL medium integer ([1]) with optional display width e.g. MEDIUMINT or MEDIUMINT(5)
64+
///
65+
/// [1]: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html
66+
MediumInt(#[cfg_attr(feature = "derive-visitor", drive(skip))] Option<u64>),
67+
/// Unsigned medium integer ([1]) with optional display width e.g. MEDIUMINT UNSIGNED or MEDIUMINT(5) UNSIGNED
68+
///
69+
/// [1]: https://dev.mysql.com/doc/refman/8.0/en/integer-types.html
70+
UnsignedMediumInt(#[cfg_attr(feature = "derive-visitor", drive(skip))] Option<u64>),
6371
/// Integer with optional display width e.g. INT or INT(11)
6472
Int(#[cfg_attr(feature = "derive-visitor", drive(skip))] Option<u64>),
6573
/// Integer with optional display width e.g. INTEGER or INTEGER(11)
@@ -74,8 +82,13 @@ pub enum DataType {
7482
UnsignedBigInt(#[cfg_attr(feature = "derive-visitor", drive(skip))] Option<u64>),
7583
/// Floating point e.g. REAL
7684
Real,
77-
/// Double e.g. DOUBLE PRECISION
85+
/// Double
7886
Double,
87+
/// Double PRECISION e.g. [standard], [postgresql]
88+
///
89+
/// [standard]: https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#approximate-numeric-type
90+
/// [postgresql]: https://www.postgresql.org/docs/current/datatype-numeric.html
91+
DoublePrecision,
7992
/// Boolean
8093
Boolean,
8194
/// Date
@@ -143,6 +156,12 @@ impl fmt::Display for DataType {
143156
DataType::UnsignedSmallInt(zerofill) => {
144157
format_type_with_optional_length(f, "SMALLINT", zerofill, true)
145158
}
159+
DataType::MediumInt(zerofill) => {
160+
format_type_with_optional_length(f, "MEDIUMINT", zerofill, false)
161+
}
162+
DataType::UnsignedMediumInt(zerofill) => {
163+
format_type_with_optional_length(f, "MEDIUMINT", zerofill, true)
164+
}
146165
DataType::Int(zerofill) => format_type_with_optional_length(f, "INT", zerofill, false),
147166
DataType::UnsignedInt(zerofill) => {
148167
format_type_with_optional_length(f, "INT", zerofill, true)
@@ -161,6 +180,7 @@ impl fmt::Display for DataType {
161180
}
162181
DataType::Real => write!(f, "REAL"),
163182
DataType::Double => write!(f, "DOUBLE"),
183+
DataType::DoublePrecision => write!(f, "DOUBLE PRECISION"),
164184
DataType::Boolean => write!(f, "BOOLEAN"),
165185
DataType::Date => write!(f, "DATE"),
166186
DataType::Time => write!(f, "TIME"),

src/ast/mod.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1191,6 +1191,7 @@ pub enum Statement {
11911191
if_not_exists: bool,
11921192
},
11931193
/// CREATE ROLE
1194+
/// See [postgres](https://www.postgresql.org/docs/current/sql-createrole.html)
11941195
CreateRole {
11951196
names: Vec<ObjectName>,
11961197
#[cfg_attr(feature = "derive-visitor", drive(skip))]
@@ -1214,7 +1215,9 @@ pub enum Statement {
12141215
connection_limit: Option<Expr>,
12151216
valid_until: Option<Expr>,
12161217
in_role: Vec<Ident>,
1218+
in_group: Vec<Ident>,
12171219
role: Vec<Ident>,
1220+
user: Vec<Ident>,
12181221
admin: Vec<Ident>,
12191222
// MSSQL
12201223
authorization_owner: Option<ObjectName>,
@@ -2130,7 +2133,9 @@ impl fmt::Display for Statement {
21302133
connection_limit,
21312134
valid_until,
21322135
in_role,
2136+
in_group,
21332137
role,
2138+
user,
21342139
admin,
21352140
authorization_owner,
21362141
} => {
@@ -2189,9 +2194,15 @@ impl fmt::Display for Statement {
21892194
if !in_role.is_empty() {
21902195
write!(f, " IN ROLE {}", display_comma_separated(in_role))?;
21912196
}
2197+
if !in_group.is_empty() {
2198+
write!(f, " IN GROUP {}", display_comma_separated(in_group))?;
2199+
}
21922200
if !role.is_empty() {
21932201
write!(f, " ROLE {}", display_comma_separated(role))?;
21942202
}
2203+
if !user.is_empty() {
2204+
write!(f, " USER {}", display_comma_separated(user))?;
2205+
}
21952206
if !admin.is_empty() {
21962207
write!(f, " ADMIN {}", display_comma_separated(admin))?;
21972208
}

src/ast/value.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ pub enum DateTimeField {
9696
Julian,
9797
Microseconds,
9898
Millenium,
99+
Millennium,
99100
Milliseconds,
100101
Quarter,
101102
Timezone,
@@ -123,6 +124,7 @@ impl fmt::Display for DateTimeField {
123124
DateTimeField::Julian => "JULIAN",
124125
DateTimeField::Microseconds => "MICROSECONDS",
125126
DateTimeField::Millenium => "MILLENIUM",
127+
DateTimeField::Millennium => "MILLENNIUM",
126128
DateTimeField::Milliseconds => "MILLISECONDS",
127129
DateTimeField::Quarter => "QUARTER",
128130
DateTimeField::Timezone => "TIMEZONE",

src/keywords.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,12 +329,14 @@ define_keywords!(
329329
MATCHED,
330330
MATERIALIZED,
331331
MAX,
332+
MEDIUMINT,
332333
MEMBER,
333334
MERGE,
334335
METADATA,
335336
METHOD,
336337
MICROSECONDS,
337338
MILLENIUM,
339+
MILLENNIUM,
338340
MILLISECONDS,
339341
MIN,
340342
MINUTE,

src/parser.rs

Lines changed: 67 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1065,6 +1065,7 @@ impl<'a> Parser<'a> {
10651065
Keyword::JULIAN => Ok(DateTimeField::Julian),
10661066
Keyword::MICROSECONDS => Ok(DateTimeField::Microseconds),
10671067
Keyword::MILLENIUM => Ok(DateTimeField::Millenium),
1068+
Keyword::MILLENNIUM => Ok(DateTimeField::Millennium),
10681069
Keyword::MILLISECONDS => Ok(DateTimeField::Milliseconds),
10691070
Keyword::QUARTER => Ok(DateTimeField::Quarter),
10701071
Keyword::TIMEZONE => Ok(DateTimeField::Timezone),
@@ -1144,6 +1145,7 @@ impl<'a> Parser<'a> {
11441145
Keyword::JULIAN,
11451146
Keyword::MICROSECONDS,
11461147
Keyword::MILLENIUM,
1148+
Keyword::MILLENNIUM,
11471149
Keyword::MILLISECONDS,
11481150
Keyword::QUARTER,
11491151
Keyword::TIMEZONE,
@@ -2109,7 +2111,9 @@ impl<'a> Parser<'a> {
21092111
let mut connection_limit = None;
21102112
let mut valid_until = None;
21112113
let mut in_role = vec![];
2112-
let mut roles = vec![];
2114+
let mut in_group = vec![];
2115+
let mut role = vec![];
2116+
let mut user = vec![];
21132117
let mut admin = vec![];
21142118

21152119
while let Some(keyword) = self.parse_one_of_keywords(&optional_keywords) {
@@ -2209,22 +2213,37 @@ impl<'a> Parser<'a> {
22092213
}
22102214
}
22112215
Keyword::IN => {
2212-
if self.parse_keyword(Keyword::ROLE) || self.parse_keyword(Keyword::GROUP) {
2216+
if self.parse_keyword(Keyword::ROLE) {
22132217
if !in_role.is_empty() {
2214-
parser_err!("Found multiple IN ROLE or IN GROUP")
2218+
parser_err!("Found multiple IN ROLE")
22152219
} else {
22162220
in_role = self.parse_comma_separated(Parser::parse_identifier)?;
22172221
Ok(())
22182222
}
2223+
} else if self.parse_keyword(Keyword::GROUP) {
2224+
if !in_group.is_empty() {
2225+
parser_err!("Found multiple IN GROUP")
2226+
} else {
2227+
in_group = self.parse_comma_separated(Parser::parse_identifier)?;
2228+
Ok(())
2229+
}
22192230
} else {
22202231
self.expected("ROLE or GROUP after IN", self.peek_token())
22212232
}
22222233
}
2223-
Keyword::ROLE | Keyword::USER => {
2224-
if !roles.is_empty() {
2225-
parser_err!("Found multiple ROLE or USER")
2234+
Keyword::ROLE => {
2235+
if !role.is_empty() {
2236+
parser_err!("Found multiple ROLE")
2237+
} else {
2238+
role = self.parse_comma_separated(Parser::parse_identifier)?;
2239+
Ok(())
2240+
}
2241+
}
2242+
Keyword::USER => {
2243+
if !user.is_empty() {
2244+
parser_err!("Found multiple USER")
22262245
} else {
2227-
roles = self.parse_comma_separated(Parser::parse_identifier)?;
2246+
user = self.parse_comma_separated(Parser::parse_identifier)?;
22282247
Ok(())
22292248
}
22302249
}
@@ -2254,7 +2273,9 @@ impl<'a> Parser<'a> {
22542273
connection_limit,
22552274
valid_until,
22562275
in_role,
2257-
role: roles,
2276+
in_group,
2277+
role,
2278+
user,
22582279
admin,
22592280
authorization_owner,
22602281
})
@@ -3319,8 +3340,11 @@ impl<'a> Parser<'a> {
33193340
Keyword::FLOAT => Ok(DataType::Float(self.parse_optional_precision()?)),
33203341
Keyword::REAL => Ok(DataType::Real),
33213342
Keyword::DOUBLE => {
3322-
let _ = self.parse_keyword(Keyword::PRECISION);
3323-
Ok(DataType::Double)
3343+
if self.parse_keyword(Keyword::PRECISION) {
3344+
Ok(DataType::DoublePrecision)
3345+
} else {
3346+
Ok(DataType::Double)
3347+
}
33243348
}
33253349
Keyword::TINYINT => {
33263350
let optional_precision = self.parse_optional_precision();
@@ -3338,6 +3362,14 @@ impl<'a> Parser<'a> {
33383362
Ok(DataType::SmallInt(optional_precision?))
33393363
}
33403364
}
3365+
Keyword::MEDIUMINT => {
3366+
let optional_precision = self.parse_optional_precision();
3367+
if self.parse_keyword(Keyword::UNSIGNED) {
3368+
Ok(DataType::UnsignedMediumInt(optional_precision?))
3369+
} else {
3370+
Ok(DataType::MediumInt(optional_precision?))
3371+
}
3372+
}
33413373
Keyword::INT => {
33423374
let optional_precision = self.parse_optional_precision();
33433375
if self.parse_keyword(Keyword::UNSIGNED) {
@@ -3371,6 +3403,10 @@ impl<'a> Parser<'a> {
33713403
Ok(DataType::Char(self.parse_optional_precision()?))
33723404
}
33733405
}
3406+
Keyword::CLOB => Ok(DataType::Clob(self.parse_precision()?)),
3407+
Keyword::BINARY => Ok(DataType::Binary(self.parse_precision()?)),
3408+
Keyword::VARBINARY => Ok(DataType::Varbinary(self.parse_precision()?)),
3409+
Keyword::BLOB => Ok(DataType::Blob(self.parse_precision()?)),
33743410
Keyword::UUID => Ok(DataType::Uuid),
33753411
Keyword::DATE => Ok(DataType::Date),
33763412
Keyword::DATETIME => Ok(DataType::Datetime),
@@ -3584,6 +3620,13 @@ impl<'a> Parser<'a> {
35843620
}
35853621
}
35863622

3623+
pub fn parse_precision(&mut self) -> Result<u64, ParserError> {
3624+
self.expect_token(&Token::LParen)?;
3625+
let n = self.parse_literal_uint()?;
3626+
self.expect_token(&Token::RParen)?;
3627+
Ok(n)
3628+
}
3629+
35873630
pub fn parse_optional_precision(&mut self) -> Result<Option<u64>, ParserError> {
35883631
if self.consume_token(&Token::LParen) {
35893632
let n = self.parse_literal_uint()?;
@@ -5211,4 +5254,18 @@ mod tests {
52115254
assert_eq!(ast.to_string(), sql.to_string());
52125255
});
52135256
}
5257+
5258+
// TODO add tests for all data types? https://github.com/sqlparser-rs/sqlparser-rs/issues/2
5259+
#[test]
5260+
fn test_parse_data_type() {
5261+
test_parse_data_type("DOUBLE PRECISION", "DOUBLE PRECISION");
5262+
test_parse_data_type("DOUBLE", "DOUBLE");
5263+
5264+
fn test_parse_data_type(input: &str, expected: &str) {
5265+
all_dialects().run_parser_method(input, |parser| {
5266+
let data_type = parser.parse_data_type().unwrap().to_string();
5267+
assert_eq!(data_type, expected);
5268+
});
5269+
}
5270+
}
52145271
}

tests/sqlparser_common.rs

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,11 @@ fn parse_cast() {
16231623
expr_from_projection(only(&select.projection))
16241624
);
16251625

1626+
one_statement_parses_to(
1627+
"SELECT CAST(id AS MEDIUMINT) FROM customer",
1628+
"SELECT CAST(id AS MEDIUMINT) FROM customer",
1629+
);
1630+
16261631
one_statement_parses_to(
16271632
"SELECT CAST(id AS BIGINT) FROM customer",
16281633
"SELECT CAST(id AS BIGINT) FROM customer",
@@ -1649,6 +1654,46 @@ fn parse_cast() {
16491654
},
16501655
expr_from_projection(only(&select.projection))
16511656
);
1657+
1658+
let sql = "SELECT CAST(id AS CLOB(50)) FROM customer";
1659+
let select = verified_only_select(sql);
1660+
assert_eq!(
1661+
&Expr::Cast {
1662+
expr: Box::new(Expr::Identifier(Ident::new("id"))),
1663+
data_type: DataType::Clob(50)
1664+
},
1665+
expr_from_projection(only(&select.projection))
1666+
);
1667+
1668+
let sql = "SELECT CAST(id AS BINARY(50)) FROM customer";
1669+
let select = verified_only_select(sql);
1670+
assert_eq!(
1671+
&Expr::Cast {
1672+
expr: Box::new(Expr::Identifier(Ident::new("id"))),
1673+
data_type: DataType::Binary(50)
1674+
},
1675+
expr_from_projection(only(&select.projection))
1676+
);
1677+
1678+
let sql = "SELECT CAST(id AS VARBINARY(50)) FROM customer";
1679+
let select = verified_only_select(sql);
1680+
assert_eq!(
1681+
&Expr::Cast {
1682+
expr: Box::new(Expr::Identifier(Ident::new("id"))),
1683+
data_type: DataType::Varbinary(50)
1684+
},
1685+
expr_from_projection(only(&select.projection))
1686+
);
1687+
1688+
let sql = "SELECT CAST(id AS BLOB(50)) FROM customer";
1689+
let select = verified_only_select(sql);
1690+
assert_eq!(
1691+
&Expr::Cast {
1692+
expr: Box::new(Expr::Identifier(Ident::new("id"))),
1693+
data_type: DataType::Blob(50)
1694+
},
1695+
expr_from_projection(only(&select.projection))
1696+
);
16521697
}
16531698

16541699
#[test]
@@ -1710,6 +1755,7 @@ fn parse_extract() {
17101755
verified_stmt("SELECT EXTRACT(JULIAN FROM d)");
17111756
verified_stmt("SELECT EXTRACT(MICROSECONDS FROM d)");
17121757
verified_stmt("SELECT EXTRACT(MILLENIUM FROM d)");
1758+
verified_stmt("SELECT EXTRACT(MILLENNIUM FROM d)");
17131759
verified_stmt("SELECT EXTRACT(MILLISECONDS FROM d)");
17141760
verified_stmt("SELECT EXTRACT(QUARTER FROM d)");
17151761
verified_stmt("SELECT EXTRACT(TIMEZONE FROM d)");

0 commit comments

Comments
 (0)