mirror of
https://github.com/apache/datafusion-sqlparser-rs.git
synced 2025-10-09 13:40:22 +00:00
Implement ALTER TABLE ADD COLUMN and RENAME (#203)
Based on sqlite grammar https://www.sqlite.org/lang_altertable.html
This commit is contained in:
parent
fab6e28271
commit
faeb7d440a
5 changed files with 117 additions and 27 deletions
|
@ -16,6 +16,7 @@ Check https://github.com/andygrove/sqlparser-rs/commits/master for undocumented
|
|||
- Use Token::EOF instead of Option<Token> (#195)
|
||||
- Make the units keyword following `INTERVAL '...'` optional (#184) - thanks @maxcountryman!
|
||||
- Generalize `DATE`/`TIME`/`TIMESTAMP` literals representation in the AST (`TypedString { data_type, value }`) and allow `DATE` and other keywords to be used as identifiers when not followed by a string (#187) - thanks @maxcountryman!
|
||||
- Output DataType capitalized (`fmt::Display`) (#202) - thanks @Dandandan!
|
||||
|
||||
### Added
|
||||
- Support MSSQL `TOP (<N>) [ PERCENT ] [ WITH TIES ]` (#150) - thanks @alexkyllo!
|
||||
|
@ -29,9 +30,11 @@ Check https://github.com/andygrove/sqlparser-rs/commits/master for undocumented
|
|||
- Support the string concatentation operator `||` (#178) - thanks @Dandandan!
|
||||
- Support bitwise AND (`&`), OR (`|`), XOR (`^`) (#181) - thanks @Dandandan!
|
||||
- Add serde support to AST structs and enums (#196) - thanks @panarch!
|
||||
- Support `ALTER TABLE ADD COLUMN`, `RENAME COLUMN`, and `RENAME TO` (#203) - thanks @mashuai!
|
||||
|
||||
### Fixed
|
||||
- Report an error for unterminated string literals (#165)
|
||||
- Make file format (`STORED AS`) case insensitive (#200) and don't allow quoting it (#201) - thanks @Dandandan!
|
||||
|
||||
## [0.5.0] - 2019-10-10
|
||||
|
||||
|
|
|
@ -23,15 +23,38 @@ use std::fmt;
|
|||
pub enum AlterTableOperation {
|
||||
/// `ADD <table_constraint>`
|
||||
AddConstraint(TableConstraint),
|
||||
/// `ADD [ COLUMN ] <column_def>`
|
||||
AddColumn { column_def: ColumnDef },
|
||||
/// TODO: implement `DROP CONSTRAINT <name>`
|
||||
DropConstraint { name: Ident },
|
||||
/// `RENAME [ COLUMN ] <old_column_name> TO <new_column_name>`
|
||||
RenameColumn {
|
||||
old_column_name: Ident,
|
||||
new_column_name: Ident,
|
||||
},
|
||||
/// `RENAME TO <table_name>`
|
||||
RenameTable { table_name: Ident },
|
||||
}
|
||||
|
||||
impl fmt::Display for AlterTableOperation {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {}", c),
|
||||
AlterTableOperation::AddColumn { column_def } => {
|
||||
write!(f, "ADD COLUMN {}", column_def.to_string())
|
||||
}
|
||||
AlterTableOperation::DropConstraint { name } => write!(f, "DROP CONSTRAINT {}", name),
|
||||
AlterTableOperation::RenameColumn {
|
||||
old_column_name,
|
||||
new_column_name,
|
||||
} => write!(
|
||||
f,
|
||||
"RENAME COLUMN {} TO {}",
|
||||
old_column_name, new_column_name
|
||||
),
|
||||
AlterTableOperation::RenameTable { table_name } => {
|
||||
write!(f, "RENAME TO {}", table_name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -340,6 +340,7 @@ define_keywords!(
|
|||
REGR_SXY,
|
||||
REGR_SYY,
|
||||
RELEASE,
|
||||
RENAME,
|
||||
REPEATABLE,
|
||||
RESTRICT,
|
||||
RESULT,
|
||||
|
|
|
@ -1122,6 +1122,29 @@ impl Parser {
|
|||
})
|
||||
}
|
||||
|
||||
fn parse_column_def(&mut self) -> Result<ColumnDef, ParserError> {
|
||||
let name = self.parse_identifier()?;
|
||||
let data_type = self.parse_data_type()?;
|
||||
let collation = if self.parse_keyword(Keyword::COLLATE) {
|
||||
Some(self.parse_object_name()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut options = vec![];
|
||||
loop {
|
||||
match self.peek_token() {
|
||||
Token::EOF | Token::Comma | Token::RParen => break,
|
||||
_ => options.push(self.parse_column_option_def()?),
|
||||
}
|
||||
}
|
||||
Ok(ColumnDef {
|
||||
name,
|
||||
data_type,
|
||||
collation,
|
||||
options,
|
||||
})
|
||||
}
|
||||
|
||||
fn parse_columns(&mut self) -> Result<(Vec<ColumnDef>, Vec<TableConstraint>), ParserError> {
|
||||
let mut columns = vec![];
|
||||
let mut constraints = vec![];
|
||||
|
@ -1132,28 +1155,9 @@ impl Parser {
|
|||
loop {
|
||||
if let Some(constraint) = self.parse_optional_table_constraint()? {
|
||||
constraints.push(constraint);
|
||||
} else if let Token::Word(column_name) = self.peek_token() {
|
||||
self.next_token();
|
||||
let data_type = self.parse_data_type()?;
|
||||
let collation = if self.parse_keyword(Keyword::COLLATE) {
|
||||
Some(self.parse_object_name()?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mut options = vec![];
|
||||
loop {
|
||||
match self.peek_token() {
|
||||
Token::EOF | Token::Comma | Token::RParen => break,
|
||||
_ => options.push(self.parse_column_option_def()?),
|
||||
}
|
||||
}
|
||||
|
||||
columns.push(ColumnDef {
|
||||
name: column_name.to_ident(),
|
||||
data_type,
|
||||
collation,
|
||||
options,
|
||||
});
|
||||
} else if let Token::Word(_) = self.peek_token() {
|
||||
let column_def = self.parse_column_def()?;
|
||||
columns.push(column_def);
|
||||
} else {
|
||||
return self.expected("column name or constraint definition", self.peek_token());
|
||||
}
|
||||
|
@ -1318,10 +1322,26 @@ impl Parser {
|
|||
if let Some(constraint) = self.parse_optional_table_constraint()? {
|
||||
AlterTableOperation::AddConstraint(constraint)
|
||||
} else {
|
||||
return self.expected("a constraint in ALTER TABLE .. ADD", self.peek_token());
|
||||
let _ = self.parse_keyword(Keyword::COLUMN);
|
||||
let column_def = self.parse_column_def()?;
|
||||
AlterTableOperation::AddColumn { column_def }
|
||||
}
|
||||
} else if self.parse_keyword(Keyword::RENAME) {
|
||||
if self.parse_keyword(Keyword::TO) {
|
||||
let table_name = self.parse_identifier()?;
|
||||
AlterTableOperation::RenameTable { table_name }
|
||||
} else {
|
||||
let _ = self.parse_keyword(Keyword::COLUMN);
|
||||
let old_column_name = self.parse_identifier()?;
|
||||
self.expect_keyword(Keyword::TO)?;
|
||||
let new_column_name = self.parse_identifier()?;
|
||||
AlterTableOperation::RenameColumn {
|
||||
old_column_name,
|
||||
new_column_name,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return self.expected("ADD after ALTER TABLE", self.peek_token());
|
||||
return self.expected("ADD or RENAME after ALTER TABLE", self.peek_token());
|
||||
};
|
||||
Ok(Statement::AlterTable {
|
||||
name: table_name,
|
||||
|
|
|
@ -1313,6 +1313,51 @@ fn parse_create_table_empty() {
|
|||
let _ = verified_stmt("CREATE TABLE t ()");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_alter_table() {
|
||||
let add_column = "ALTER TABLE tab ADD COLUMN foo TEXT";
|
||||
match verified_stmt(add_column) {
|
||||
Statement::AlterTable {
|
||||
name,
|
||||
operation: AlterTableOperation::AddColumn { column_def },
|
||||
} => {
|
||||
assert_eq!("tab", name.to_string());
|
||||
assert_eq!("foo", column_def.name.to_string());
|
||||
assert_eq!("TEXT", column_def.data_type.to_string());
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let rename_table = "ALTER TABLE tab RENAME TO new_tab";
|
||||
match verified_stmt(rename_table) {
|
||||
Statement::AlterTable {
|
||||
name,
|
||||
operation: AlterTableOperation::RenameTable { table_name },
|
||||
} => {
|
||||
assert_eq!("tab", name.to_string());
|
||||
assert_eq!("new_tab", table_name.to_string())
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
let rename_column = "ALTER TABLE tab RENAME COLUMN foo TO new_foo";
|
||||
match verified_stmt(rename_column) {
|
||||
Statement::AlterTable {
|
||||
name,
|
||||
operation:
|
||||
AlterTableOperation::RenameColumn {
|
||||
old_column_name,
|
||||
new_column_name,
|
||||
},
|
||||
} => {
|
||||
assert_eq!("tab", name.to_string());
|
||||
assert_eq!(old_column_name.to_string(), "foo");
|
||||
assert_eq!(new_column_name.to_string(), "new_foo");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_alter_table_constraints() {
|
||||
check_one("CONSTRAINT address_pkey PRIMARY KEY (address_id)");
|
||||
|
@ -1347,9 +1392,7 @@ fn parse_alter_table_constraints() {
|
|||
fn parse_bad_constraint() {
|
||||
let res = parse_sql_statements("ALTER TABLE tab ADD");
|
||||
assert_eq!(
|
||||
ParserError::ParserError(
|
||||
"Expected a constraint in ALTER TABLE .. ADD, found: EOF".to_string()
|
||||
),
|
||||
ParserError::ParserError("Expected identifier, found: EOF".to_string()),
|
||||
res.unwrap_err()
|
||||
);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue