add create index and drop index support

This commit is contained in:
mashuai 2020-05-15 21:55:25 +08:00
parent 2644bc4ac7
commit 5aacc5ebcd
4 changed files with 98 additions and 3 deletions

View file

@ -476,6 +476,15 @@ pub enum Statement {
file_format: Option<FileFormat>, file_format: Option<FileFormat>,
location: Option<String>, location: Option<String>,
}, },
/// CREATE INDEX
CreateIndex {
/// index name
name: ObjectName,
table_name: ObjectName,
columns: Vec<Ident>,
unique: bool,
if_not_exists: bool,
},
/// ALTER TABLE /// ALTER TABLE
AlterTable { AlterTable {
/// Table name /// Table name
@ -655,6 +664,28 @@ impl fmt::Display for Statement {
} }
Ok(()) Ok(())
} }
Statement::CreateIndex {
name,
table_name,
columns,
unique,
if_not_exists,
} => {
write!(
f,
"CREATE{}INDEX{}{} ON {}({}",
if *unique { " UNIQUE " } else { " " },
if *if_not_exists {
" IF NOT EXISTS "
} else {
" "
},
name,
table_name,
display_separated(columns, ",")
)?;
write!(f, ");")
}
Statement::AlterTable { name, operation } => { Statement::AlterTable { name, operation } => {
write!(f, "ALTER TABLE {} {}", name, operation) write!(f, "ALTER TABLE {} {}", name, operation)
} }
@ -819,6 +850,7 @@ impl FromStr for FileFormat {
pub enum ObjectType { pub enum ObjectType {
Table, Table,
View, View,
Index,
} }
impl fmt::Display for ObjectType { impl fmt::Display for ObjectType {
@ -826,6 +858,7 @@ impl fmt::Display for ObjectType {
f.write_str(match self { f.write_str(match self {
ObjectType::Table => "TABLE", ObjectType::Table => "TABLE",
ObjectType::View => "VIEW", ObjectType::View => "VIEW",
ObjectType::Index => "INDEX",
}) })
} }
} }

View file

@ -420,7 +420,8 @@ define_keywords!(
WORK, WORK,
YEAR, YEAR,
ZONE, ZONE,
END_EXEC = "END-EXEC" END_EXEC = "END-EXEC",
INDEX
); );
/// These keywords can't be used as a table alias, so that `FROM table_name alias` /// These keywords can't be used as a table alias, so that `FROM table_name alias`

View file

@ -855,13 +855,17 @@ impl Parser {
pub fn parse_create(&mut self) -> Result<Statement, ParserError> { pub fn parse_create(&mut self) -> Result<Statement, ParserError> {
if self.parse_keyword("TABLE") { if self.parse_keyword("TABLE") {
self.parse_create_table() self.parse_create_table()
} else if self.parse_keyword("INDEX") {
self.parse_create_index(false)
} else if self.parse_keywords(vec!["UNIQUE", "INDEX"]) {
self.parse_create_index(true)
} else if self.parse_keyword("MATERIALIZED") || self.parse_keyword("VIEW") { } else if self.parse_keyword("MATERIALIZED") || self.parse_keyword("VIEW") {
self.prev_token(); self.prev_token();
self.parse_create_view() self.parse_create_view()
} else if self.parse_keyword("EXTERNAL") { } else if self.parse_keyword("EXTERNAL") {
self.parse_create_external_table() self.parse_create_external_table()
} else { } else {
self.expected("TABLE or VIEW after CREATE", self.peek_token()) self.expected("TABLE, VIEW or INDEX after CREATE", self.peek_token())
} }
} }
@ -912,8 +916,10 @@ impl Parser {
ObjectType::Table ObjectType::Table
} else if self.parse_keyword("VIEW") { } else if self.parse_keyword("VIEW") {
ObjectType::View ObjectType::View
} else if self.parse_keyword("INDEX") {
ObjectType::Index
} else { } else {
return self.expected("TABLE or VIEW after DROP", self.peek_token()); return self.expected("TABLE, VIEW or INDEX after DROP", self.peek_token());
}; };
// Many dialects support the non standard `IF EXISTS` clause and allow // Many dialects support the non standard `IF EXISTS` clause and allow
// specifying multiple objects to delete in a single statement // specifying multiple objects to delete in a single statement
@ -932,6 +938,23 @@ impl Parser {
}) })
} }
pub fn parse_create_index(&mut self, unique: bool) -> Result<Statement, ParserError> {
let if_not_exists = self.parse_keywords(vec!["IF", "NOT", "EXISTS"]);
let index_name = self.parse_object_name()?;
self.expect_keyword("ON")?;
let table_name = self.parse_object_name()?;
self.expect_token(&Token::LParen)?;
let columns = self.parse_comma_separated(Parser::parse_identifier)?;
self.expect_token(&Token::RParen)?;
Ok(Statement::CreateIndex {
name: index_name,
table_name,
columns,
unique,
if_not_exists,
})
}
pub fn parse_create_table(&mut self) -> Result<Statement, ParserError> { pub fn parse_create_table(&mut self) -> Result<Statement, ParserError> {
let if_not_exists = self.parse_keywords(vec!["IF", "NOT", "EXISTS"]); let if_not_exists = self.parse_keywords(vec!["IF", "NOT", "EXISTS"]);
let table_name = self.parse_object_name()?; let table_name = self.parse_object_name()?;

View file

@ -2631,6 +2631,44 @@ fn ensure_multiple_dialects_are_tested() {
let _ = parse_sql_statements("SELECT @foo"); let _ = parse_sql_statements("SELECT @foo");
} }
#[test]
fn parse_create_index() {
let sql = "CREATE UNIQUE INDEX IF NOT EXISTS idx_name ON test(name,age);";
let ident_vec = vec![Ident::new("name"), Ident::new("age")];
match verified_stmt(sql) {
Statement::CreateIndex {
name,
table_name,
columns,
unique,
if_not_exists,
} => {
assert_eq!("idx_name", name.to_string());
assert_eq!("test", table_name.to_string());
assert_eq!(ident_vec, columns);
assert_eq!(true, unique);
assert_eq!(true, if_not_exists)
}
_ => unreachable!(),
}
}
#[test]
fn parse_drop_index() {
let sql = "DROP INDEX idx_a";
match verified_stmt(sql) {
Statement::Drop {
names, object_type, ..
} => {
assert_eq!(
vec!["idx_a"],
names.iter().map(ToString::to_string).collect::<Vec<_>>()
);
assert_eq!(ObjectType::Index, object_type);
}
_ => unreachable!(),
}
}
fn parse_sql_statements(sql: &str) -> Result<Vec<Statement>, ParserError> { fn parse_sql_statements(sql: &str) -> Result<Vec<Statement>, ParserError> {
all_dialects().parse_sql_statements(sql) all_dialects().parse_sql_statements(sql)
} }