Skip to content

Commit d1fff06

Browse files
author
mashuai
committed
implement alter table for sqlite grammer: https://www.sqlite.org/lang_altertable.html
1 parent fab6e28 commit d1fff06

File tree

4 files changed

+90
-18
lines changed

4 files changed

+90
-18
lines changed

src/ast/ddl.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,25 @@ use std::fmt;
2323
pub enum AlterTableOperation {
2424
/// `ADD <table_constraint>`
2525
AddConstraint(TableConstraint),
26+
AddColumn{has_column_identifier: bool, column_def: ColumnDef},
2627
/// TODO: implement `DROP CONSTRAINT <name>`
2728
DropConstraint { name: Ident },
29+
RenameColumn{has_column_identifier: bool, old_column_name: Ident, new_column_name: Ident},
30+
RenameTable{name: Ident}
2831
}
2932

3033
impl fmt::Display for AlterTableOperation {
3134
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3235
match self {
3336
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {}", c),
37+
AlterTableOperation::AddColumn { has_column_identifier, column_def } => {
38+
write!(f, "ADD {}{}", if *has_column_identifier { "COLUMN "} else {""},column_def.to_string())
39+
},
3440
AlterTableOperation::DropConstraint { name } => write!(f, "DROP CONSTRAINT {}", name),
41+
AlterTableOperation::RenameColumn {has_column_identifier, old_column_name, new_column_name} => {
42+
write!(f,"RENAME {}{} TO {}", if *has_column_identifier {"COLUMN "} else {""} ,old_column_name, new_column_name)
43+
},
44+
AlterTableOperation::RenameTable { name } => write!(f, "RENAME TO {}", name),
3545
}
3646
}
3747
}

src/dialect/keywords.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,7 @@ define_keywords!(
340340
REGR_SXY,
341341
REGR_SYY,
342342
RELEASE,
343+
RENAME,
343344
REPEATABLE,
344345
RESTRICT,
345346
RESULT,

src/parser.rs

Lines changed: 39 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,29 @@ impl Parser {
11221122
})
11231123
}
11241124

1125+
fn parse_column(&mut self) -> Result<ColumnDef, ParserError> {
1126+
let name = self.parse_identifier()?;
1127+
let data_type = self.parse_data_type()?;
1128+
let collation = if self.parse_keyword(Keyword::COLLATE) {
1129+
Some(self.parse_object_name()?)
1130+
} else {
1131+
None
1132+
};
1133+
let mut options = vec![];
1134+
loop {
1135+
match self.peek_token() {
1136+
Token::EOF => break,
1137+
_ => options.push(self.parse_column_option_def()?),
1138+
}
1139+
}
1140+
Ok(ColumnDef{
1141+
name,
1142+
data_type,
1143+
collation,
1144+
options
1145+
})
1146+
}
1147+
11251148
fn parse_columns(&mut self) -> Result<(Vec<ColumnDef>, Vec<TableConstraint>), ParserError> {
11261149
let mut columns = vec![];
11271150
let mut constraints = vec![];
@@ -1318,10 +1341,23 @@ impl Parser {
13181341
if let Some(constraint) = self.parse_optional_table_constraint()? {
13191342
AlterTableOperation::AddConstraint(constraint)
13201343
} else {
1321-
return self.expected("a constraint in ALTER TABLE .. ADD", self.peek_token());
1344+
let has_column_identifier = self.parse_keyword(Keyword::COLUMN);
1345+
let column_def = self.parse_column()?;
1346+
AlterTableOperation::AddColumn {has_column_identifier, column_def}
13221347
}
1323-
} else {
1324-
return self.expected("ADD after ALTER TABLE", self.peek_token());
1348+
} else if self.parse_keyword(Keyword::RENAME){
1349+
if self.parse_keyword(Keyword::TO) {
1350+
let name = self.parse_identifier()?;
1351+
AlterTableOperation::RenameTable {name}
1352+
} else {
1353+
let has_column_identifier = self.parse_keyword(Keyword::COLUMN);
1354+
let old_column_name = self.parse_identifier()?;
1355+
self.expect_keyword(Keyword::TO)?;
1356+
let new_column_name = self.parse_identifier()?;
1357+
AlterTableOperation::RenameColumn {has_column_identifier, old_column_name, new_column_name}
1358+
}
1359+
}else {
1360+
return self.expected("ADD,RENAME TO or RENAME after ALTER TABLE", self.peek_token());
13251361
};
13261362
Ok(Statement::AlterTable {
13271363
name: table_name,

tests/sqlparser_common.rs

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,31 +1315,56 @@ fn parse_create_table_empty() {
13151315

13161316
#[test]
13171317
fn parse_alter_table_constraints() {
1318-
check_one("CONSTRAINT address_pkey PRIMARY KEY (address_id)");
1319-
check_one("CONSTRAINT uk_task UNIQUE (report_date, task_id)");
1318+
check_one("ADD CONSTRAINT address_pkey PRIMARY KEY (address_id)");
1319+
check_one("ADD CONSTRAINT uk_task UNIQUE (report_date, task_id)");
13201320
check_one(
1321-
"CONSTRAINT customer_address_id_fkey FOREIGN KEY (address_id) \
1321+
"ADD CONSTRAINT customer_address_id_fkey FOREIGN KEY (address_id) \
13221322
REFERENCES public.address(address_id)",
13231323
);
1324-
check_one("CONSTRAINT ck CHECK (rtrim(ltrim(REF_CODE)) <> '')");
1324+
check_one("ADD CONSTRAINT ck CHECK (rtrim(ltrim(REF_CODE)) <> '')");
13251325

1326-
check_one("PRIMARY KEY (foo, bar)");
1327-
check_one("UNIQUE (id)");
1328-
check_one("FOREIGN KEY (foo, bar) REFERENCES AnotherTable(foo, bar)");
1329-
check_one("CHECK (end_date > start_date OR end_date IS NULL)");
1326+
check_one("ADD PRIMARY KEY (foo, bar)");
1327+
check_one("ADD UNIQUE (id)");
1328+
check_one("ADD FOREIGN KEY (foo, bar) REFERENCES AnotherTable(foo, bar)");
1329+
check_one("ADD CHECK (end_date > start_date OR end_date IS NULL)");
1330+
check_one("ADD foo TEXT");
1331+
check_one("ADD COLUMN foo TEXT");
13301332

1331-
fn check_one(constraint_text: &str) {
1332-
match verified_stmt(&format!("ALTER TABLE tab ADD {}", constraint_text)) {
1333+
check_one("RENAME TO tab_rename");
1334+
check_one("RENAME old_col TO new_col");
1335+
check_one("RENAME COLUMN old_col TO new_col");
1336+
1337+
fn check_one(stmt: &str) {
1338+
match verified_stmt(&format!("ALTER TABLE tab {}", stmt)) {
13331339
Statement::AlterTable {
13341340
name,
1335-
operation: AlterTableOperation::AddConstraint(constraint),
1341+
operation,
13361342
} => {
13371343
assert_eq!("tab", name.to_string());
1338-
assert_eq!(constraint_text, constraint.to_string());
1339-
}
1344+
match operation {
1345+
AlterTableOperation::AddConstraint(constraint) => {
1346+
assert_eq!(stmt, "ADD ".to_string() + &constraint.to_string());
1347+
},
1348+
AlterTableOperation::AddColumn { has_column_identifier, column_def } => {
1349+
assert_eq!("foo", column_def.name.to_string());
1350+
}
1351+
AlterTableOperation::DropConstraint {.. } => {},
1352+
AlterTableOperation::RenameColumn { has_column_identifier, old_column_name, new_column_name } => {
1353+
assert_eq!("old_col", old_column_name.to_string());
1354+
assert_eq!("new_col", new_column_name.to_string());
1355+
},
1356+
AlterTableOperation::RenameTable { name } => {
1357+
assert_eq!("tab_rename", name.to_string())
1358+
},
1359+
}
1360+
},
13401361
_ => unreachable!(),
13411362
}
1342-
verified_stmt(&format!("CREATE TABLE foo (id INT, {})", constraint_text));
1363+
if stmt.starts_with("ADD") {
1364+
let stmt = stmt.replacen("ADD ", "", 1);
1365+
let stmt = stmt.replacen("COLUMN ", "", 1);
1366+
verified_stmt(&format!("CREATE TABLE foo (id INT, {})", stmt));
1367+
}
13431368
}
13441369
}
13451370

@@ -1348,7 +1373,7 @@ fn parse_bad_constraint() {
13481373
let res = parse_sql_statements("ALTER TABLE tab ADD");
13491374
assert_eq!(
13501375
ParserError::ParserError(
1351-
"Expected a constraint in ALTER TABLE .. ADD, found: EOF".to_string()
1376+
"Expected identifier, found: EOF".to_string()
13521377
),
13531378
res.unwrap_err()
13541379
);

0 commit comments

Comments
 (0)