Skip to content

Commit 56567f8

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

File tree

4 files changed

+139
-22
lines changed

4 files changed

+139
-22
lines changed

src/ast/ddl.rs

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,15 +23,58 @@ use std::fmt;
2323
pub enum AlterTableOperation {
2424
/// `ADD <table_constraint>`
2525
AddConstraint(TableConstraint),
26+
AddColumn {
27+
has_column_identifier: bool,
28+
column_def: ColumnDef,
29+
},
2630
/// TODO: implement `DROP CONSTRAINT <name>`
27-
DropConstraint { name: Ident },
31+
DropConstraint {
32+
name: Ident,
33+
},
34+
RenameColumn {
35+
has_column_identifier: bool,
36+
old_column_name: Ident,
37+
new_column_name: Ident,
38+
},
39+
RenameTable {
40+
name: Ident,
41+
},
2842
}
2943

3044
impl fmt::Display for AlterTableOperation {
3145
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
3246
match self {
3347
AlterTableOperation::AddConstraint(c) => write!(f, "ADD {}", c),
48+
AlterTableOperation::AddColumn {
49+
has_column_identifier,
50+
column_def,
51+
} => write!(
52+
f,
53+
"ADD {}{}",
54+
if *has_column_identifier {
55+
"COLUMN "
56+
} else {
57+
""
58+
},
59+
column_def.to_string()
60+
),
3461
AlterTableOperation::DropConstraint { name } => write!(f, "DROP CONSTRAINT {}", name),
62+
AlterTableOperation::RenameColumn {
63+
has_column_identifier,
64+
old_column_name,
65+
new_column_name,
66+
} => write!(
67+
f,
68+
"RENAME {}{} TO {}",
69+
if *has_column_identifier {
70+
"COLUMN "
71+
} else {
72+
""
73+
},
74+
old_column_name,
75+
new_column_name
76+
),
77+
AlterTableOperation::RenameTable { name } => write!(f, "RENAME TO {}", name),
3578
}
3679
}
3780
}

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: 48 additions & 2 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,33 @@ 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 {
1347+
has_column_identifier,
1348+
column_def,
1349+
}
1350+
}
1351+
} else if self.parse_keyword(Keyword::RENAME) {
1352+
if self.parse_keyword(Keyword::TO) {
1353+
let name = self.parse_identifier()?;
1354+
AlterTableOperation::RenameTable { name }
1355+
} else {
1356+
let has_column_identifier = self.parse_keyword(Keyword::COLUMN);
1357+
let old_column_name = self.parse_identifier()?;
1358+
self.expect_keyword(Keyword::TO)?;
1359+
let new_column_name = self.parse_identifier()?;
1360+
AlterTableOperation::RenameColumn {
1361+
has_column_identifier,
1362+
old_column_name,
1363+
new_column_name,
1364+
}
13221365
}
13231366
} else {
1324-
return self.expected("ADD after ALTER TABLE", self.peek_token());
1367+
return self.expected(
1368+
"ADD,RENAME TO or RENAME after ALTER TABLE",
1369+
self.peek_token(),
1370+
);
13251371
};
13261372
Ok(Statement::AlterTable {
13271373
name: table_name,

tests/sqlparser_common.rs

Lines changed: 46 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,41 +1315,68 @@ 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-
Statement::AlterTable {
1334-
name,
1335-
operation: AlterTableOperation::AddConstraint(constraint),
1336-
} => {
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)) {
1339+
Statement::AlterTable { name, operation } => {
13371340
assert_eq!("tab", name.to_string());
1338-
assert_eq!(constraint_text, constraint.to_string());
1341+
match operation {
1342+
AlterTableOperation::AddConstraint(constraint) => {
1343+
assert_eq!(stmt, "ADD ".to_string() + &constraint.to_string());
1344+
}
1345+
AlterTableOperation::AddColumn {
1346+
has_column_identifier: _,
1347+
column_def,
1348+
} => {
1349+
assert_eq!("foo", column_def.name.to_string());
1350+
}
1351+
AlterTableOperation::RenameColumn {
1352+
has_column_identifier: _,
1353+
old_column_name,
1354+
new_column_name,
1355+
} => {
1356+
assert_eq!("old_col", old_column_name.to_string());
1357+
assert_eq!("new_col", new_column_name.to_string());
1358+
}
1359+
AlterTableOperation::RenameTable { name } => {
1360+
assert_eq!("tab_rename", name.to_string())
1361+
}
1362+
_ => unreachable!(),
1363+
}
13391364
}
13401365
_ => unreachable!(),
13411366
}
1342-
verified_stmt(&format!("CREATE TABLE foo (id INT, {})", constraint_text));
1367+
if stmt.starts_with("ADD") {
1368+
let stmt = stmt.replacen("ADD ", "", 1);
1369+
let stmt = stmt.replacen("COLUMN ", "", 1);
1370+
verified_stmt(&format!("CREATE TABLE foo (id INT, {})", stmt));
1371+
}
13431372
}
13441373
}
13451374

13461375
#[test]
13471376
fn parse_bad_constraint() {
13481377
let res = parse_sql_statements("ALTER TABLE tab ADD");
13491378
assert_eq!(
1350-
ParserError::ParserError(
1351-
"Expected a constraint in ALTER TABLE .. ADD, found: EOF".to_string()
1352-
),
1379+
ParserError::ParserError("Expected identifier, found: EOF".to_string()),
13531380
res.unwrap_err()
13541381
);
13551382

0 commit comments

Comments
 (0)