Skip to content

Commit 187376e

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

File tree

4 files changed

+145
-0
lines changed

4 files changed

+145
-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: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,13 @@ pub enum SQLStatement {
394394
name: SQLObjectName,
395395
operation: AlterOperation,
396396
},
397+
/// DROP TABLE
398+
SQLDrop {
399+
object_type: SQLObjectType,
400+
if_exists: bool,
401+
names: Vec<SQLObjectName>,
402+
cascade: bool,
403+
},
397404
}
398405

399406
impl ToString for SQLStatement {
@@ -502,6 +509,18 @@ impl ToString for SQLStatement {
502509
SQLStatement::SQLAlterTable { name, operation } => {
503510
format!("ALTER TABLE {} {}", name.to_string(), operation.to_string())
504511
}
512+
SQLStatement::SQLDrop {
513+
object_type,
514+
if_exists,
515+
names,
516+
cascade,
517+
} => format!(
518+
"DROP {}{} {}{}",
519+
object_type.to_string(),
520+
if *if_exists { " IF EXISTS" } else { "" },
521+
comma_separated_string(&names),
522+
if *cascade { " CASCADE" } else { "" },
523+
),
505524
}
506525
}
507526
}
@@ -608,3 +627,18 @@ impl FromStr for FileFormat {
608627
}
609628
}
610629
}
630+
631+
#[derive(Debug, Clone, PartialEq)]
632+
pub enum SQLObjectType {
633+
Table,
634+
View,
635+
}
636+
637+
impl SQLObjectType {
638+
fn to_string(&self) -> String {
639+
match self {
640+
SQLObjectType::Table => "TABLE".into(),
641+
SQLObjectType::View => "VIEW".into(),
642+
}
643+
}
644+
}

src/sqlparser.rs

Lines changed: 38 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,43 @@ impl Parser {
738739
})
739740
}
740741

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

tests/sqlparser_common.rs

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1200,6 +1200,76 @@ 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::SQLDrop {
1208+
object_type,
1209+
if_exists,
1210+
names,
1211+
cascade,
1212+
} => {
1213+
assert_eq!(false, if_exists);
1214+
assert_eq!(SQLObjectType::Table, object_type);
1215+
assert_eq!(
1216+
vec!["foo"],
1217+
names.iter().map(|n| n.to_string()).collect::<Vec<_>>()
1218+
);
1219+
assert_eq!(false, cascade);
1220+
}
1221+
_ => assert!(false),
1222+
}
1223+
1224+
let sql = "DROP TABLE IF EXISTS foo, bar CASCADE";
1225+
match verified_stmt(sql) {
1226+
SQLStatement::SQLDrop {
1227+
object_type,
1228+
if_exists,
1229+
names,
1230+
cascade,
1231+
} => {
1232+
assert_eq!(true, if_exists);
1233+
assert_eq!(SQLObjectType::Table, object_type);
1234+
assert_eq!(
1235+
vec!["foo", "bar"],
1236+
names.iter().map(|n| n.to_string()).collect::<Vec<_>>()
1237+
);
1238+
assert_eq!(true, cascade);
1239+
}
1240+
_ => assert!(false),
1241+
}
1242+
1243+
let sql = "DROP TABLE";
1244+
assert_eq!(
1245+
ParserError::ParserError("Expected identifier, found: EOF".to_string()),
1246+
parse_sql_statements(sql).unwrap_err(),
1247+
);
1248+
1249+
let sql = "DROP TABLE IF EXISTS foo, bar CASCADE RESTRICT";
1250+
assert_eq!(
1251+
ParserError::ParserError("Cannot specify both CASCADE and RESTRICT in DROP".to_string()),
1252+
parse_sql_statements(sql).unwrap_err(),
1253+
);
1254+
}
1255+
1256+
#[test]
1257+
fn parse_drop_view() {
1258+
let sql = "DROP VIEW myschema.myview";
1259+
match verified_stmt(sql) {
1260+
SQLStatement::SQLDrop {
1261+
names, object_type, ..
1262+
} => {
1263+
assert_eq!(
1264+
vec!["myschema.myview"],
1265+
names.iter().map(|n| n.to_string()).collect::<Vec<_>>()
1266+
);
1267+
assert_eq!(SQLObjectType::View, object_type);
1268+
}
1269+
_ => assert!(false),
1270+
}
1271+
}
1272+
12031273
#[test]
12041274
fn parse_invalid_subquery_without_parens() {
12051275
let res = parse_sql_statements("SELECT SELECT 1 FROM bar WHERE 1=1 FROM baz");

0 commit comments

Comments
 (0)