Skip to content

Commit 7461d8b

Browse files
MySQL: CREATE INDEX: allow USING clause before ON (#2029)
1 parent c099883 commit 7461d8b

File tree

3 files changed

+55
-5
lines changed

3 files changed

+55
-5
lines changed

src/ast/ddl.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2361,6 +2361,8 @@ pub struct CreateIndex {
23612361
pub name: Option<ObjectName>,
23622362
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
23632363
pub table_name: ObjectName,
2364+
/// Index type used in the statement. Can also be found inside [`CreateIndex::index_options`]
2365+
/// depending on the position of the option within the statement.
23642366
pub using: Option<IndexType>,
23652367
pub columns: Vec<IndexColumn>,
23662368
pub unique: bool,

src/parser/mod.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7063,19 +7063,24 @@ impl<'a> Parser<'a> {
70637063
pub fn parse_create_index(&mut self, unique: bool) -> Result<Statement, ParserError> {
70647064
let concurrently = self.parse_keyword(Keyword::CONCURRENTLY);
70657065
let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
7066+
7067+
let mut using = None;
7068+
70667069
let index_name = if if_not_exists || !self.parse_keyword(Keyword::ON) {
70677070
let index_name = self.parse_object_name(false)?;
7071+
// MySQL allows `USING index_type` either before or after `ON table_name`
7072+
using = self.parse_optional_using_then_index_type()?;
70687073
self.expect_keyword_is(Keyword::ON)?;
70697074
Some(index_name)
70707075
} else {
70717076
None
70727077
};
7078+
70737079
let table_name = self.parse_object_name(false)?;
7074-
let using = if self.parse_keyword(Keyword::USING) {
7075-
Some(self.parse_index_type()?)
7076-
} else {
7077-
None
7078-
};
7080+
7081+
// MySQL allows having two `USING` clauses.
7082+
// In that case, the second clause overwrites the first.
7083+
using = self.parse_optional_using_then_index_type()?.or(using);
70797084

70807085
let columns = self.parse_parenthesized_index_column_list()?;
70817086

tests/sqlparser_common.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17252,6 +17252,49 @@ fn parse_invisible_column() {
1725217252
}
1725317253
}
1725417254

17255+
#[test]
17256+
fn parse_create_index_different_using_positions() {
17257+
let sql = "CREATE INDEX idx_name USING BTREE ON table_name (col1)";
17258+
let expected = "CREATE INDEX idx_name ON table_name USING BTREE (col1)";
17259+
match all_dialects().one_statement_parses_to(sql, expected) {
17260+
Statement::CreateIndex(CreateIndex {
17261+
name,
17262+
table_name,
17263+
using,
17264+
columns,
17265+
unique,
17266+
..
17267+
}) => {
17268+
assert_eq!(name.unwrap().to_string(), "idx_name");
17269+
assert_eq!(table_name.to_string(), "table_name");
17270+
assert_eq!(using, Some(IndexType::BTree));
17271+
assert_eq!(columns.len(), 1);
17272+
assert!(!unique);
17273+
}
17274+
_ => unreachable!(),
17275+
}
17276+
17277+
let sql = "CREATE INDEX idx_name USING BTREE ON table_name (col1) USING HASH";
17278+
let expected = "CREATE INDEX idx_name ON table_name USING BTREE (col1) USING HASH";
17279+
match all_dialects().one_statement_parses_to(sql, expected) {
17280+
Statement::CreateIndex(CreateIndex {
17281+
name,
17282+
table_name,
17283+
columns,
17284+
index_options,
17285+
..
17286+
}) => {
17287+
assert_eq!(name.unwrap().to_string(), "idx_name");
17288+
assert_eq!(table_name.to_string(), "table_name");
17289+
assert_eq!(columns.len(), 1);
17290+
assert!(index_options
17291+
.iter()
17292+
.any(|o| o == &IndexOption::Using(IndexType::Hash)));
17293+
}
17294+
_ => unreachable!(),
17295+
}
17296+
}
17297+
1725517298
#[test]
1725617299
fn test_parse_alter_user() {
1725717300
verified_stmt("ALTER USER u1");

0 commit comments

Comments
 (0)