Skip to content

Commit 98403c0

Browse files
authored
Allow parsing of mysql empty row inserts (#783)
1 parent 524b8a7 commit 98403c0

File tree

2 files changed

+81
-32
lines changed

2 files changed

+81
-32
lines changed

src/parser.rs

Lines changed: 46 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1433,7 +1433,7 @@ impl<'a> Parser<'a> {
14331433
///
14341434
/// [(1)]: Expr::MatchAgainst
14351435
pub fn parse_match_against(&mut self) -> Result<Expr, ParserError> {
1436-
let columns = self.parse_parenthesized_column_list(Mandatory)?;
1436+
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
14371437

14381438
self.expect_keyword(Keyword::AGAINST)?;
14391439

@@ -2419,7 +2419,7 @@ impl<'a> Parser<'a> {
24192419
// general that the arguments can be made to appear as column
24202420
// definitions in a traditional CREATE TABLE statement", but
24212421
// we don't implement that.
2422-
let module_args = self.parse_parenthesized_column_list(Optional)?;
2422+
let module_args = self.parse_parenthesized_column_list(Optional, false)?;
24232423
Ok(Statement::CreateVirtualTable {
24242424
name: table_name,
24252425
if_not_exists,
@@ -2698,12 +2698,12 @@ impl<'a> Parser<'a> {
26982698
// Many dialects support `OR ALTER` right after `CREATE`, but we don't (yet).
26992699
// ANSI SQL and Postgres support RECURSIVE here, but we don't support it either.
27002700
let name = self.parse_object_name()?;
2701-
let columns = self.parse_parenthesized_column_list(Optional)?;
2701+
let columns = self.parse_parenthesized_column_list(Optional, false)?;
27022702
let with_options = self.parse_options(Keyword::WITH)?;
27032703

27042704
let cluster_by = if self.parse_keyword(Keyword::CLUSTER) {
27052705
self.expect_keyword(Keyword::BY)?;
2706-
self.parse_parenthesized_column_list(Optional)?
2706+
self.parse_parenthesized_column_list(Optional, false)?
27072707
} else {
27082708
vec![]
27092709
};
@@ -3441,7 +3441,7 @@ impl<'a> Parser<'a> {
34413441
let foreign_table = self.parse_object_name()?;
34423442
// PostgreSQL allows omitting the column list and
34433443
// uses the primary key column of the foreign table by default
3444-
let referred_columns = self.parse_parenthesized_column_list(Optional)?;
3444+
let referred_columns = self.parse_parenthesized_column_list(Optional, false)?;
34453445
let mut on_delete = None;
34463446
let mut on_update = None;
34473447
loop {
@@ -3525,7 +3525,7 @@ impl<'a> Parser<'a> {
35253525
if is_primary {
35263526
self.expect_keyword(Keyword::KEY)?;
35273527
}
3528-
let columns = self.parse_parenthesized_column_list(Mandatory)?;
3528+
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
35293529
Ok(Some(TableConstraint::Unique {
35303530
name,
35313531
columns,
@@ -3534,10 +3534,10 @@ impl<'a> Parser<'a> {
35343534
}
35353535
Token::Word(w) if w.keyword == Keyword::FOREIGN => {
35363536
self.expect_keyword(Keyword::KEY)?;
3537-
let columns = self.parse_parenthesized_column_list(Mandatory)?;
3537+
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
35383538
self.expect_keyword(Keyword::REFERENCES)?;
35393539
let foreign_table = self.parse_object_name()?;
3540-
let referred_columns = self.parse_parenthesized_column_list(Mandatory)?;
3540+
let referred_columns = self.parse_parenthesized_column_list(Mandatory, false)?;
35413541
let mut on_delete = None;
35423542
let mut on_update = None;
35433543
loop {
@@ -3582,7 +3582,7 @@ impl<'a> Parser<'a> {
35823582
} else {
35833583
None
35843584
};
3585-
let columns = self.parse_parenthesized_column_list(Mandatory)?;
3585+
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
35863586

35873587
Ok(Some(TableConstraint::Index {
35883588
display_as_key,
@@ -3617,7 +3617,7 @@ impl<'a> Parser<'a> {
36173617

36183618
let opt_index_name = self.maybe_parse(|parser| parser.parse_identifier());
36193619

3620-
let columns = self.parse_parenthesized_column_list(Mandatory)?;
3620+
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
36213621

36223622
Ok(Some(TableConstraint::FulltextOrSpatial {
36233623
fulltext,
@@ -3864,7 +3864,7 @@ impl<'a> Parser<'a> {
38643864
/// Parse a copy statement
38653865
pub fn parse_copy(&mut self) -> Result<Statement, ParserError> {
38663866
let table_name = self.parse_object_name()?;
3867-
let columns = self.parse_parenthesized_column_list(Optional)?;
3867+
let columns = self.parse_parenthesized_column_list(Optional, false)?;
38683868
let to = match self.parse_one_of_keywords(&[Keyword::FROM, Keyword::TO]) {
38693869
Some(Keyword::FROM) => false,
38703870
Some(Keyword::TO) => true,
@@ -3950,13 +3950,13 @@ impl<'a> Parser<'a> {
39503950
Some(Keyword::QUOTE) => CopyOption::Quote(self.parse_literal_char()?),
39513951
Some(Keyword::ESCAPE) => CopyOption::Escape(self.parse_literal_char()?),
39523952
Some(Keyword::FORCE_QUOTE) => {
3953-
CopyOption::ForceQuote(self.parse_parenthesized_column_list(Mandatory)?)
3953+
CopyOption::ForceQuote(self.parse_parenthesized_column_list(Mandatory, false)?)
39543954
}
39553955
Some(Keyword::FORCE_NOT_NULL) => {
3956-
CopyOption::ForceNotNull(self.parse_parenthesized_column_list(Mandatory)?)
3956+
CopyOption::ForceNotNull(self.parse_parenthesized_column_list(Mandatory, false)?)
39573957
}
39583958
Some(Keyword::FORCE_NULL) => {
3959-
CopyOption::ForceNull(self.parse_parenthesized_column_list(Mandatory)?)
3959+
CopyOption::ForceNull(self.parse_parenthesized_column_list(Mandatory, false)?)
39603960
}
39613961
Some(Keyword::ENCODING) => CopyOption::Encoding(self.parse_literal_string()?),
39623962
_ => self.expected("option", self.peek_token())?,
@@ -4454,7 +4454,7 @@ impl<'a> Parser<'a> {
44544454
) -> Result<Option<TableAlias>, ParserError> {
44554455
match self.parse_optional_alias(reserved_kwds)? {
44564456
Some(name) => {
4457-
let columns = self.parse_parenthesized_column_list(Optional)?;
4457+
let columns = self.parse_parenthesized_column_list(Optional, false)?;
44584458
Ok(Some(TableAlias { name, columns }))
44594459
}
44604460
None => Ok(None),
@@ -4505,11 +4505,17 @@ impl<'a> Parser<'a> {
45054505
pub fn parse_parenthesized_column_list(
45064506
&mut self,
45074507
optional: IsOptional,
4508+
allow_empty: bool,
45084509
) -> Result<Vec<Ident>, ParserError> {
45094510
if self.consume_token(&Token::LParen) {
4510-
let cols = self.parse_comma_separated(Parser::parse_identifier)?;
4511-
self.expect_token(&Token::RParen)?;
4512-
Ok(cols)
4511+
if allow_empty && self.peek_token().token == Token::RParen {
4512+
self.next_token();
4513+
Ok(vec![])
4514+
} else {
4515+
let cols = self.parse_comma_separated(Parser::parse_identifier)?;
4516+
self.expect_token(&Token::RParen)?;
4517+
Ok(cols)
4518+
}
45134519
} else if optional == Optional {
45144520
Ok(vec![])
45154521
} else {
@@ -4811,7 +4817,7 @@ impl<'a> Parser<'a> {
48114817
from: None,
48124818
}
48134819
} else {
4814-
let columns = self.parse_parenthesized_column_list(Optional)?;
4820+
let columns = self.parse_parenthesized_column_list(Optional, false)?;
48154821
self.expect_keyword(Keyword::AS)?;
48164822
self.expect_token(&Token::LParen)?;
48174823
let query = Box::new(self.parse_query()?);
@@ -4848,7 +4854,8 @@ impl<'a> Parser<'a> {
48484854
self.expect_token(&Token::RParen)?;
48494855
SetExpr::Query(Box::new(subquery))
48504856
} else if self.parse_keyword(Keyword::VALUES) {
4851-
SetExpr::Values(self.parse_values()?)
4857+
let is_mysql = dialect_of!(self is MySqlDialect);
4858+
SetExpr::Values(self.parse_values(is_mysql)?)
48524859
} else if self.parse_keyword(Keyword::TABLE) {
48534860
SetExpr::Table(Box::new(self.parse_as_table()?))
48544861
} else {
@@ -5645,7 +5652,7 @@ impl<'a> Parser<'a> {
56455652
let constraint = self.parse_expr()?;
56465653
Ok(JoinConstraint::On(constraint))
56475654
} else if self.parse_keyword(Keyword::USING) {
5648-
let columns = self.parse_parenthesized_column_list(Mandatory)?;
5655+
let columns = self.parse_parenthesized_column_list(Mandatory, false)?;
56495656
Ok(JoinConstraint::Using(columns))
56505657
} else {
56515658
Ok(JoinConstraint::None)
@@ -5770,7 +5777,7 @@ impl<'a> Parser<'a> {
57705777
]) {
57715778
let columns = match kw {
57725779
Keyword::INSERT | Keyword::REFERENCES | Keyword::SELECT | Keyword::UPDATE => {
5773-
let columns = self.parse_parenthesized_column_list(Optional)?;
5780+
let columns = self.parse_parenthesized_column_list(Optional, false)?;
57745781
if columns.is_empty() {
57755782
None
57765783
} else {
@@ -5856,7 +5863,8 @@ impl<'a> Parser<'a> {
58565863
// Hive lets you put table here regardless
58575864
let table = self.parse_keyword(Keyword::TABLE);
58585865
let table_name = self.parse_object_name()?;
5859-
let columns = self.parse_parenthesized_column_list(Optional)?;
5866+
let is_mysql = dialect_of!(self is MySqlDialect);
5867+
let columns = self.parse_parenthesized_column_list(Optional, is_mysql)?;
58605868

58615869
let partitioned = if self.parse_keyword(Keyword::PARTITION) {
58625870
self.expect_token(&Token::LParen)?;
@@ -5868,7 +5876,7 @@ impl<'a> Parser<'a> {
58685876
};
58695877

58705878
// Hive allows you to specify columns after partitions as well if you want.
5871-
let after_columns = self.parse_parenthesized_column_list(Optional)?;
5879+
let after_columns = self.parse_parenthesized_column_list(Optional, false)?;
58725880

58735881
let source = Box::new(self.parse_query()?);
58745882
let on = if self.parse_keyword(Keyword::ON) {
@@ -5878,7 +5886,7 @@ impl<'a> Parser<'a> {
58785886
Some(ConflictTarget::OnConstraint(self.parse_object_name()?))
58795887
} else if self.peek_token() == Token::LParen {
58805888
Some(ConflictTarget::Columns(
5881-
self.parse_parenthesized_column_list(IsOptional::Mandatory)?,
5889+
self.parse_parenthesized_column_list(IsOptional::Mandatory, false)?,
58825890
))
58835891
} else {
58845892
None
@@ -6091,7 +6099,7 @@ impl<'a> Parser<'a> {
60916099
&mut self,
60926100
) -> Result<Option<ExceptSelectItem>, ParserError> {
60936101
let opt_except = if self.parse_keyword(Keyword::EXCEPT) {
6094-
let idents = self.parse_parenthesized_column_list(Mandatory)?;
6102+
let idents = self.parse_parenthesized_column_list(Mandatory, false)?;
60956103
match &idents[..] {
60966104
[] => {
60976105
return self.expected(
@@ -6236,7 +6244,7 @@ impl<'a> Parser<'a> {
62366244
})
62376245
}
62386246

6239-
pub fn parse_values(&mut self) -> Result<Values, ParserError> {
6247+
pub fn parse_values(&mut self, allow_empty: bool) -> Result<Values, ParserError> {
62406248
let mut explicit_row = false;
62416249

62426250
let rows = self.parse_comma_separated(|parser| {
@@ -6245,9 +6253,14 @@ impl<'a> Parser<'a> {
62456253
}
62466254

62476255
parser.expect_token(&Token::LParen)?;
6248-
let exprs = parser.parse_comma_separated(Parser::parse_expr)?;
6249-
parser.expect_token(&Token::RParen)?;
6250-
Ok(exprs)
6256+
if allow_empty && parser.peek_token().token == Token::RParen {
6257+
parser.next_token();
6258+
Ok(vec![])
6259+
} else {
6260+
let exprs = parser.parse_comma_separated(Parser::parse_expr)?;
6261+
parser.expect_token(&Token::RParen)?;
6262+
Ok(exprs)
6263+
}
62516264
})?;
62526265
Ok(Values { explicit_row, rows })
62536266
}
@@ -6413,9 +6426,10 @@ impl<'a> Parser<'a> {
64136426
"INSERT in MATCHED merge clause".to_string(),
64146427
));
64156428
}
6416-
let columns = self.parse_parenthesized_column_list(Optional)?;
6429+
let is_mysql = dialect_of!(self is MySqlDialect);
6430+
let columns = self.parse_parenthesized_column_list(Optional, is_mysql)?;
64176431
self.expect_keyword(Keyword::VALUES)?;
6418-
let values = self.parse_values()?;
6432+
let values = self.parse_values(is_mysql)?;
64196433
MergeClause::NotMatched {
64206434
predicate,
64216435
columns,

tests/sqlparser_mysql.rs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -692,6 +692,41 @@ fn parse_simple_insert() {
692692
}
693693
}
694694

695+
#[test]
696+
fn parse_empty_row_insert() {
697+
let sql = "INSERT INTO tb () VALUES (), ()";
698+
699+
match mysql().one_statement_parses_to(sql, "INSERT INTO tb VALUES (), ()") {
700+
Statement::Insert {
701+
table_name,
702+
columns,
703+
source,
704+
on,
705+
..
706+
} => {
707+
assert_eq!(ObjectName(vec![Ident::new("tb")]), table_name);
708+
assert!(columns.is_empty());
709+
assert!(on.is_none());
710+
assert_eq!(
711+
Box::new(Query {
712+
with: None,
713+
body: Box::new(SetExpr::Values(Values {
714+
explicit_row: false,
715+
rows: vec![vec![], vec![]]
716+
})),
717+
order_by: vec![],
718+
limit: None,
719+
offset: None,
720+
fetch: None,
721+
locks: vec![],
722+
}),
723+
source
724+
);
725+
}
726+
_ => unreachable!(),
727+
}
728+
}
729+
695730
#[test]
696731
fn parse_insert_with_on_duplicate_update() {
697732
let sql = "INSERT INTO permission_groups (name, description, perm_create, perm_read, perm_update, perm_delete) VALUES ('accounting_manager', 'Some description about the group', true, true, true, true) ON DUPLICATE KEY UPDATE description = VALUES(description), perm_create = VALUES(perm_create), perm_read = VALUES(perm_read), perm_update = VALUES(perm_update), perm_delete = VALUES(perm_delete)";

0 commit comments

Comments
 (0)