MySQL: CREATE INDEX: allow USING clause before ON (#2029)
Some checks are pending
license / Release Audit Tool (RAT) (push) Waiting to run
Rust / codestyle (push) Waiting to run
Rust / lint (push) Waiting to run
Rust / benchmark-lint (push) Waiting to run
Rust / compile (push) Waiting to run
Rust / docs (push) Waiting to run
Rust / compile-no-std (push) Waiting to run
Rust / test (beta) (push) Waiting to run
Rust / test (nightly) (push) Waiting to run
Rust / test (stable) (push) Waiting to run

This commit is contained in:
Mohamed Abdeen 2025-09-26 11:46:18 +01:00 committed by GitHub
parent c0998832a2
commit 7461d8bd02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 55 additions and 5 deletions

View file

@ -2361,6 +2361,8 @@ pub struct CreateIndex {
pub name: Option<ObjectName>,
#[cfg_attr(feature = "visitor", visit(with = "visit_relation"))]
pub table_name: ObjectName,
/// Index type used in the statement. Can also be found inside [`CreateIndex::index_options`]
/// depending on the position of the option within the statement.
pub using: Option<IndexType>,
pub columns: Vec<IndexColumn>,
pub unique: bool,

View file

@ -7063,19 +7063,24 @@ impl<'a> Parser<'a> {
pub fn parse_create_index(&mut self, unique: bool) -> Result<Statement, ParserError> {
let concurrently = self.parse_keyword(Keyword::CONCURRENTLY);
let if_not_exists = self.parse_keywords(&[Keyword::IF, Keyword::NOT, Keyword::EXISTS]);
let mut using = None;
let index_name = if if_not_exists || !self.parse_keyword(Keyword::ON) {
let index_name = self.parse_object_name(false)?;
// MySQL allows `USING index_type` either before or after `ON table_name`
using = self.parse_optional_using_then_index_type()?;
self.expect_keyword_is(Keyword::ON)?;
Some(index_name)
} else {
None
};
let table_name = self.parse_object_name(false)?;
let using = if self.parse_keyword(Keyword::USING) {
Some(self.parse_index_type()?)
} else {
None
};
// MySQL allows having two `USING` clauses.
// In that case, the second clause overwrites the first.
using = self.parse_optional_using_then_index_type()?.or(using);
let columns = self.parse_parenthesized_index_column_list()?;

View file

@ -17252,6 +17252,49 @@ fn parse_invisible_column() {
}
}
#[test]
fn parse_create_index_different_using_positions() {
let sql = "CREATE INDEX idx_name USING BTREE ON table_name (col1)";
let expected = "CREATE INDEX idx_name ON table_name USING BTREE (col1)";
match all_dialects().one_statement_parses_to(sql, expected) {
Statement::CreateIndex(CreateIndex {
name,
table_name,
using,
columns,
unique,
..
}) => {
assert_eq!(name.unwrap().to_string(), "idx_name");
assert_eq!(table_name.to_string(), "table_name");
assert_eq!(using, Some(IndexType::BTree));
assert_eq!(columns.len(), 1);
assert!(!unique);
}
_ => unreachable!(),
}
let sql = "CREATE INDEX idx_name USING BTREE ON table_name (col1) USING HASH";
let expected = "CREATE INDEX idx_name ON table_name USING BTREE (col1) USING HASH";
match all_dialects().one_statement_parses_to(sql, expected) {
Statement::CreateIndex(CreateIndex {
name,
table_name,
columns,
index_options,
..
}) => {
assert_eq!(name.unwrap().to_string(), "idx_name");
assert_eq!(table_name.to_string(), "table_name");
assert_eq!(columns.len(), 1);
assert!(index_options
.iter()
.any(|o| o == &IndexOption::Using(IndexType::Hash)));
}
_ => unreachable!(),
}
}
#[test]
fn test_parse_alter_user() {
verified_stmt("ALTER USER u1");