Skip to content

Commit 91abdcb

Browse files
MySQL: allow USING clause before ON in CREATE INDEX
MySQL allows specifying the index type `USING index_type` before the `ON` clause in `CREATE INDEX` statements. This PR allows the `CREATE INDEX` parser to accept both positions of the `USING` clause, regardless of the dialect. docs: https://dev.mysql.com/doc/refman/8.4/en/create-index.html
1 parent 6506814 commit 91abdcb

2 files changed

Lines changed: 62 additions & 5 deletions

File tree

src/parser/mod.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6876,19 +6876,27 @@ impl<'a> Parser<'a> {
68766876
pub fn parse_create_index(&mut self, unique: bool) -> Result<Statement, ParserError> {
68776877
let concurrently = self.parse_keyword(Keyword::CONCURRENTLY);
68786878
let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
6879+
6880+
let mut using = None;
6881+
68796882
let index_name = if if_not_exists || !self.parse_keyword(Keyword::ON) {
68806883
let index_name = self.parse_object_name(false)?;
6884+
// MySQL allows `USING index_type` either before or after `ON table_name`
6885+
using = self.parse_using_index_type_clause()?;
68816886
self.expect_keyword_is(Keyword::ON)?;
68826887
Some(index_name)
68836888
} else {
68846889
None
68856890
};
6891+
68866892
let table_name = self.parse_object_name(false)?;
6887-
let using = if self.parse_keyword(Keyword::USING) {
6888-
Some(self.parse_index_type()?)
6889-
} else {
6890-
None
6891-
};
6893+
6894+
if let Some(second_using) = self.parse_using_index_type_clause()? {
6895+
if using.is_some() {
6896+
return Err(ParserError::ParserError("USING already specified".into()));
6897+
}
6898+
using = Some(second_using);
6899+
}
68926900

68936901
let columns = self.parse_parenthesized_index_column_list()?;
68946902

@@ -8303,6 +8311,14 @@ impl<'a> Parser<'a> {
83038311
}
83048312
}
83058313

8314+
pub fn parse_using_index_type_clause(&mut self) -> Result<Option<IndexType>, ParserError> {
8315+
if self.parse_keyword(Keyword::USING) {
8316+
Ok(Some(self.parse_index_type()?))
8317+
} else {
8318+
Ok(None)
8319+
}
8320+
}
8321+
83068322
pub fn parse_index_type(&mut self) -> Result<IndexType, ParserError> {
83078323
Ok(if self.parse_keyword(Keyword::BTREE) {
83088324
IndexType::BTree

tests/sqlparser_common.rs

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16156,3 +16156,44 @@ fn test_identifier_unicode_start() {
1615616156
]);
1615716157
let _ = dialects.verified_stmt(sql);
1615816158
}
16159+
16160+
#[test]
16161+
fn parse_create_index_using_before_on() {
16162+
let sql = "CREATE INDEX idx_name USING BTREE ON table_name (col1)";
16163+
match all_dialects().parse_sql_statements(sql).unwrap()[0].clone() {
16164+
Statement::CreateIndex(CreateIndex {
16165+
name,
16166+
table_name,
16167+
using,
16168+
columns,
16169+
unique,
16170+
..
16171+
}) => {
16172+
assert_eq!(name.unwrap().to_string(), "idx_name");
16173+
assert_eq!(table_name.to_string(), "table_name");
16174+
assert_eq!(using, Some(IndexType::BTree));
16175+
assert_eq!(columns.len(), 1);
16176+
assert!(!unique);
16177+
}
16178+
_ => unreachable!(),
16179+
}
16180+
16181+
let sql = "CREATE UNIQUE INDEX idx_name USING HASH ON table_name (col1, col2)";
16182+
match all_dialects().parse_sql_statements(sql).unwrap()[0].clone() {
16183+
Statement::CreateIndex(CreateIndex {
16184+
name,
16185+
table_name,
16186+
using,
16187+
columns,
16188+
unique,
16189+
..
16190+
}) => {
16191+
assert_eq!(name.unwrap().to_string(), "idx_name");
16192+
assert_eq!(table_name.to_string(), "table_name");
16193+
assert_eq!(using, Some(IndexType::Hash));
16194+
assert_eq!(columns.len(), 2);
16195+
assert!(unique);
16196+
}
16197+
_ => unreachable!(),
16198+
}
16199+
}

0 commit comments

Comments
 (0)