Skip to content

Commit 8b4973f

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 e3fbfd9 commit 8b4973f

File tree

2 files changed

+63
-6
lines changed

2 files changed

+63
-6
lines changed

src/parser/mod.rs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7061,19 +7061,27 @@ impl<'a> Parser<'a> {
70617061
pub fn parse_create_index(&mut self, unique: bool) -> Result<Statement, ParserError> {
70627062
let concurrently = self.parse_keyword(Keyword::CONCURRENTLY);
70637063
let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
7064+
7065+
let mut using = None;
7066+
70647067
let index_name = if if_not_exists || !self.parse_keyword(Keyword::ON) {
70657068
let index_name = self.parse_object_name(false)?;
7069+
// MySQL allows `USING index_type` either before or after `ON table_name`
7070+
using = self.parse_using_index_type_clause()?;
70667071
self.expect_keyword_is(Keyword::ON)?;
70677072
Some(index_name)
70687073
} else {
70697074
None
70707075
};
7076+
70717077
let table_name = self.parse_object_name(false)?;
7072-
let using = if self.parse_keyword(Keyword::USING) {
7073-
Some(self.parse_index_type()?)
7074-
} else {
7075-
None
7076-
};
7078+
7079+
if let Some(second_using) = self.parse_using_index_type_clause()? {
7080+
if using.is_some() {
7081+
return Err(ParserError::ParserError("USING already specified".into()));
7082+
}
7083+
using = Some(second_using);
7084+
}
70777085

70787086
let columns = self.parse_parenthesized_index_column_list()?;
70797087

@@ -8588,6 +8596,14 @@ impl<'a> Parser<'a> {
85888596
}
85898597
}
85908598

8599+
pub fn parse_using_index_type_clause(&mut self) -> Result<Option<IndexType>, ParserError> {
8600+
if self.parse_keyword(Keyword::USING) {
8601+
Ok(Some(self.parse_index_type()?))
8602+
} else {
8603+
Ok(None)
8604+
}
8605+
}
8606+
85918607
pub fn parse_index_type(&mut self) -> Result<IndexType, ParserError> {
85928608
Ok(if self.parse_keyword(Keyword::BTREE) {
85938609
IndexType::BTree

tests/sqlparser_common.rs

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17138,7 +17138,7 @@ fn test_parse_semantic_view_table_factor() {
1713817138
}
1713917139

1714017140
let ast_sql = r#"SELECT * FROM SEMANTIC_VIEW(
17141-
my_model
17141+
my_model
1714217142
DIMENSIONS DATE_PART('year', date_col), region_name
1714317143
METRICS orders.revenue, orders.count
1714417144
WHERE active = true
@@ -17193,3 +17193,44 @@ fn parse_adjacent_string_literal_concatenation() {
1719317193
let sql = "SELECT * FROM t WHERE col = 'Hello' \n ' ' \t 'World!'";
1719417194
dialects.one_statement_parses_to(sql, r"SELECT * FROM t WHERE col = 'Hello World!'");
1719517195
}
17196+
17197+
#[test]
17198+
fn parse_create_index_using_before_on() {
17199+
let sql = "CREATE INDEX idx_name USING BTREE ON table_name (col1)";
17200+
match all_dialects().parse_sql_statements(sql).unwrap()[0].clone() {
17201+
Statement::CreateIndex(CreateIndex {
17202+
name,
17203+
table_name,
17204+
using,
17205+
columns,
17206+
unique,
17207+
..
17208+
}) => {
17209+
assert_eq!(name.unwrap().to_string(), "idx_name");
17210+
assert_eq!(table_name.to_string(), "table_name");
17211+
assert_eq!(using, Some(IndexType::BTree));
17212+
assert_eq!(columns.len(), 1);
17213+
assert!(!unique);
17214+
}
17215+
_ => unreachable!(),
17216+
}
17217+
17218+
let sql = "CREATE UNIQUE INDEX idx_name USING HASH ON table_name (col1, col2)";
17219+
match all_dialects().parse_sql_statements(sql).unwrap()[0].clone() {
17220+
Statement::CreateIndex(CreateIndex {
17221+
name,
17222+
table_name,
17223+
using,
17224+
columns,
17225+
unique,
17226+
..
17227+
}) => {
17228+
assert_eq!(name.unwrap().to_string(), "idx_name");
17229+
assert_eq!(table_name.to_string(), "table_name");
17230+
assert_eq!(using, Some(IndexType::Hash));
17231+
assert_eq!(columns.len(), 2);
17232+
assert!(unique);
17233+
}
17234+
_ => unreachable!(),
17235+
}
17236+
}

0 commit comments

Comments
 (0)