Skip to content

Commit 3587914

Browse files
MohamedAbdeen21ayman-sigma
authored andcommitted
MySQL: CREATE INDEX: allow USING clause before ON (apache#2029)
1 parent e4be28e commit 3587914

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
@@ -7094,19 +7094,24 @@ impl<'a> Parser<'a> {
70947094
pub fn parse_create_index(&mut self, unique: bool) -> Result<Statement, ParserError> {
70957095
let concurrently = self.parse_keyword(Keyword::CONCURRENTLY);
70967096
let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
7097+
7098+
let mut using = None;
7099+
70977100
let index_name = if if_not_exists || !self.parse_keyword(Keyword::ON) {
70987101
let index_name = self.parse_object_name(false)?;
7102+
// MySQL allows `USING index_type` either before or after `ON table_name`
7103+
using = self.parse_optional_using_then_index_type()?;
70997104
self.expect_keyword_is(Keyword::ON)?;
71007105
Some(index_name)
71017106
} else {
71027107
None
71037108
};
7109+
71047110
let table_name = self.parse_object_name(false)?;
7105-
let using = if self.parse_keyword(Keyword::USING) {
7106-
Some(self.parse_index_type()?)
7107-
} else {
7108-
None
7109-
};
7111+
7112+
// MySQL allows having two `USING` clauses.
7113+
// In that case, the second clause overwrites the first.
7114+
using = self.parse_optional_using_then_index_type()?.or(using);
71107115

71117116
let columns = self.parse_parenthesized_index_column_list()?;
71127117

tests/sqlparser_common.rs

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17278,6 +17278,49 @@ fn parse_invisible_column() {
1727817278
}
1727917279
}
1728017280

17281+
#[test]
17282+
fn parse_create_index_different_using_positions() {
17283+
let sql = "CREATE INDEX idx_name USING BTREE ON table_name (col1)";
17284+
let expected = "CREATE INDEX idx_name ON table_name USING BTREE (col1)";
17285+
match all_dialects().one_statement_parses_to(sql, expected) {
17286+
Statement::CreateIndex(CreateIndex {
17287+
name,
17288+
table_name,
17289+
using,
17290+
columns,
17291+
unique,
17292+
..
17293+
}) => {
17294+
assert_eq!(name.unwrap().to_string(), "idx_name");
17295+
assert_eq!(table_name.to_string(), "table_name");
17296+
assert_eq!(using, Some(IndexType::BTree));
17297+
assert_eq!(columns.len(), 1);
17298+
assert!(!unique);
17299+
}
17300+
_ => unreachable!(),
17301+
}
17302+
17303+
let sql = "CREATE INDEX idx_name USING BTREE ON table_name (col1) USING HASH";
17304+
let expected = "CREATE INDEX idx_name ON table_name USING BTREE (col1) USING HASH";
17305+
match all_dialects().one_statement_parses_to(sql, expected) {
17306+
Statement::CreateIndex(CreateIndex {
17307+
name,
17308+
table_name,
17309+
columns,
17310+
index_options,
17311+
..
17312+
}) => {
17313+
assert_eq!(name.unwrap().to_string(), "idx_name");
17314+
assert_eq!(table_name.to_string(), "table_name");
17315+
assert_eq!(columns.len(), 1);
17316+
assert!(index_options
17317+
.iter()
17318+
.any(|o| o == &IndexOption::Using(IndexType::Hash)));
17319+
}
17320+
_ => unreachable!(),
17321+
}
17322+
}
17323+
1728117324
#[test]
1728217325
fn test_parse_alter_user() {
1728317326
verified_stmt("ALTER USER u1");

0 commit comments

Comments
 (0)