Skip to content

Commit 1b6df46

Browse files
beneschjamii
andcommitted
Support DROP [TABLE|VIEW]
Co-authored-by: Jamie Brandon <jamie@scattered-thoughts.net>
1 parent 4f944dd commit 1b6df46

File tree

4 files changed

+139
-0
lines changed

4 files changed

+139
-0
lines changed

src/dialect/keywords.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ define_keywords!(
7171
CALL,
7272
CALLED,
7373
CARDINALITY,
74+
CASCADE,
7475
CASCADED,
7576
CASE,
7677
CAST,
@@ -178,6 +179,7 @@ define_keywords!(
178179
HOLD,
179180
HOUR,
180181
IDENTITY,
182+
IF,
181183
IN,
182184
INDICATOR,
183185
INNER,
@@ -290,6 +292,7 @@ define_keywords!(
290292
REGR_SXY,
291293
REGR_SYY,
292294
RELEASE,
295+
RESTRICT,
293296
RESULT,
294297
RETURN,
295298
RETURNS,

src/sqlast/mod.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,10 @@ pub enum SQLStatement {
394394
name: SQLObjectName,
395395
operation: AlterOperation,
396396
},
397+
/// DROP TABLE
398+
SQLDropTable(SQLDrop),
399+
/// DROP VIEW
400+
SQLDropView(SQLDrop),
397401
}
398402

399403
impl ToString for SQLStatement {
@@ -499,6 +503,8 @@ impl ToString for SQLStatement {
499503
name.to_string(),
500504
comma_separated_string(columns)
501505
),
506+
SQLStatement::SQLDropTable(drop) => drop.to_string_internal("TABLE"),
507+
SQLStatement::SQLDropView(drop) => drop.to_string_internal("VIEW"),
502508
SQLStatement::SQLAlterTable { name, operation } => {
503509
format!("ALTER TABLE {} {}", name.to_string(), operation.to_string())
504510
}
@@ -608,3 +614,22 @@ impl FromStr for FileFormat {
608614
}
609615
}
610616
}
617+
618+
#[derive(Debug, Clone, PartialEq)]
619+
pub struct SQLDrop {
620+
pub if_exists: bool,
621+
pub names: Vec<SQLObjectName>,
622+
pub cascade: bool,
623+
}
624+
625+
impl SQLDrop {
626+
fn to_string_internal(&self, object_type: &str) -> String {
627+
format!(
628+
"DROP {}{} {}{}",
629+
object_type,
630+
if self.if_exists { " IF EXISTS" } else { "" },
631+
comma_separated_string(&self.names),
632+
if self.cascade { " CASCADE" } else { "" },
633+
)
634+
}
635+
}

src/sqlparser.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ impl Parser {
9797
Ok(SQLStatement::SQLQuery(Box::new(self.parse_query()?)))
9898
}
9999
"CREATE" => Ok(self.parse_create()?),
100+
"DROP" => Ok(self.parse_drop()?),
100101
"DELETE" => Ok(self.parse_delete()?),
101102
"INSERT" => Ok(self.parse_insert()?),
102103
"ALTER" => Ok(self.parse_alter()?),
@@ -738,6 +739,53 @@ impl Parser {
738739
})
739740
}
740741

742+
pub fn parse_drop(&mut self) -> Result<SQLStatement, ParserError> {
743+
if self.parse_keyword("TABLE") {
744+
self.parse_drop_table()
745+
} else if self.parse_keyword("VIEW") {
746+
self.parse_drop_view()
747+
} else {
748+
parser_err!(format!(
749+
"Unexpected token after DROP: {:?}",
750+
self.peek_token()
751+
))
752+
}
753+
}
754+
755+
pub fn parse_drop_table(&mut self) -> Result<SQLStatement, ParserError> {
756+
Ok(SQLStatement::SQLDropTable(self.parse_drop_inner()?))
757+
}
758+
759+
pub fn parse_drop_view(&mut self) -> Result<SQLStatement, ParserError> {
760+
Ok(SQLStatement::SQLDropView(self.parse_drop_inner()?))
761+
}
762+
763+
pub fn parse_drop_inner(&mut self) -> Result<SQLDrop, ParserError> {
764+
let if_exists = self.parse_keywords(vec!["IF", "EXISTS"]);
765+
let mut names = vec![self.parse_object_name()?];
766+
loop {
767+
let token = &self.next_token();
768+
if let Some(Token::Comma) = token {
769+
names.push(self.parse_object_name()?)
770+
} else {
771+
if token.is_some() {
772+
self.prev_token();
773+
}
774+
break;
775+
}
776+
}
777+
let cascade = self.parse_keyword("CASCADE");
778+
let restrict = self.parse_keyword("RESTRICT");
779+
if cascade && restrict {
780+
return parser_err!("Cannot specify both CASCADE and RESTRICT in DROP");
781+
}
782+
Ok(SQLDrop {
783+
if_exists,
784+
names,
785+
cascade,
786+
})
787+
}
788+
741789
pub fn parse_create_table(&mut self) -> Result<SQLStatement, ParserError> {
742790
let table_name = self.parse_object_name()?;
743791
// parse optional column list (schema)

tests/sqlparser_common.rs

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,69 @@ fn parse_create_materialized_view() {
12001200
}
12011201
}
12021202

1203+
#[test]
1204+
fn parse_drop_table() {
1205+
let sql = "DROP TABLE foo";
1206+
match verified_stmt(sql) {
1207+
SQLStatement::SQLDropTable(SQLDrop {
1208+
if_exists,
1209+
names,
1210+
cascade,
1211+
}) => {
1212+
assert_eq!(false, if_exists);
1213+
assert_eq!(
1214+
vec!["foo"],
1215+
names.iter().map(|n| n.to_string()).collect::<Vec<_>>()
1216+
);
1217+
assert_eq!(false, cascade);
1218+
}
1219+
_ => assert!(false),
1220+
}
1221+
1222+
let sql = "DROP TABLE IF EXISTS foo, bar CASCADE";
1223+
match verified_stmt(sql) {
1224+
SQLStatement::SQLDropTable(SQLDrop {
1225+
if_exists,
1226+
names,
1227+
cascade,
1228+
}) => {
1229+
assert_eq!(true, if_exists);
1230+
assert_eq!(
1231+
vec!["foo", "bar"],
1232+
names.iter().map(|n| n.to_string()).collect::<Vec<_>>()
1233+
);
1234+
assert_eq!(true, cascade);
1235+
}
1236+
_ => assert!(false),
1237+
}
1238+
1239+
let sql = "DROP TABLE";
1240+
assert_eq!(
1241+
ParserError::ParserError("Expected identifier, found: EOF".to_string()),
1242+
parse_sql_statements(sql).unwrap_err(),
1243+
);
1244+
1245+
let sql = "DROP TABLE IF EXISTS foo, bar CASCADE RESTRICT";
1246+
assert_eq!(
1247+
ParserError::ParserError("Cannot specify both CASCADE and RESTRICT in DROP".to_string()),
1248+
parse_sql_statements(sql).unwrap_err(),
1249+
);
1250+
}
1251+
1252+
#[test]
1253+
fn parse_drop_view() {
1254+
let sql = "DROP VIEW myschema.myview";
1255+
match verified_stmt(sql) {
1256+
SQLStatement::SQLDropView(SQLDrop { names, .. }) => {
1257+
assert_eq!(
1258+
vec!["myschema.myview"],
1259+
names.iter().map(|n| n.to_string()).collect::<Vec<_>>()
1260+
);
1261+
}
1262+
_ => assert!(false),
1263+
}
1264+
}
1265+
12031266
#[test]
12041267
fn parse_invalid_subquery_without_parens() {
12051268
let res = parse_sql_statements("SELECT SELECT 1 FROM bar WHERE 1=1 FROM baz");

0 commit comments

Comments
 (0)