diff --git a/src/.sqlparser.rs.swo b/src/.sqlparser.rs.swo new file mode 100644 index 00000000..1829715f Binary files /dev/null and b/src/.sqlparser.rs.swo differ diff --git a/src/sqlast.rs b/src/sqlast.rs index 5dcf5693..3859aa34 100644 --- a/src/sqlast.rs +++ b/src/sqlast.rs @@ -56,6 +56,12 @@ pub enum ASTNode { having: Option>, limit: Option>, }, + SQLDelete { + relation: Option>, // FROM statement + selection: Option>, // WHERE statement + order_by: Option>, + limit: Option>, + }, SQLCreateTable { /// Table name name: String, diff --git a/src/sqlparser.rs b/src/sqlparser.rs index e59fee35..d698dafb 100644 --- a/src/sqlparser.rs +++ b/src/sqlparser.rs @@ -87,6 +87,7 @@ impl Parser { Token::Keyword(k) => match k.to_uppercase().as_ref() { "SELECT" => Ok(self.parse_select()?), "CREATE" => Ok(self.parse_create()?), + "DELETE" => Ok(self.parse_delete()?), _ => return parser_err!(format!("No prefix parser for keyword {}", k)), }, Token::Mult => Ok(ASTNode::SQLWildcard), @@ -440,6 +441,49 @@ impl Parser { } } + pub fn parse_delete(&mut self) -> Result { + + let relation: Option> = if self.parse_keyword("FROM") { + Some(Box::new(self.parse_expr(0)?)) + } else { + None + }; + + let order_by = if self.parse_keywords(vec!["ORDER", "BY"]) { + Some(self.parse_order_by_expr_list()?) + } else { + None + }; + + let limit = if self.parse_keyword("LIMIT") { + self.parse_limit()? + } else { + None + }; + + let selection = if self.parse_keyword("WHERE") { + Some(Box::new(self.parse_expr(0)?)) + } else { + None + }; + + // parse next token + if let Some(next_token) = self.peek_token() { + parser_err!(format!( + "Unexpected token at end of DELETE: {:?}", + next_token + )) + } else { + Ok(ASTNode::SQLDelete { + relation, + selection, + order_by, + limit, + }) + } + + } + /// Parse a SELECT statement pub fn parse_select(&mut self) -> Result { let projection = self.parse_expr_list()?; @@ -581,6 +625,56 @@ mod tests { use super::*; + #[test] + fn parse_delete_statement() { + + let sql: &str = "DELETE FROM 'table'"; + + match parse_sql(&sql) { + + ASTNode::SQLDelete { + relation, + .. + } => { + assert_eq!(Some(Box::new(ASTNode::SQLLiteralString("table".to_string()))), relation); + }, + + _ => assert!(false), + } + } + + #[test] + fn parse_where_delete_statement() { + + let sql: &str = "DELETE FROM 'table' WHERE name = 5"; + + use self::ASTNode::*; + use self::SQLOperator::*; + + match parse_sql(&sql) { + + ASTNode::SQLDelete { + relation, + selection, + .. + } => { + assert_eq!(Some(Box::new(ASTNode::SQLLiteralString("table".to_string()))), relation); + + assert_eq!( + SQLBinaryExpr { + left: Box::new(SQLIdentifier("name".to_string())), + op: Eq, + right: Box::new(SQLLiteralLong(5)), + }, + *selection.unwrap(), + ); + + }, + + _ => assert!(false), + } + } + #[test] fn parse_simple_select() { let sql = String::from("SELECT id, fname, lname FROM customer WHERE id = 1 LIMIT 5"); @@ -851,6 +945,7 @@ mod tests { } + #[test] fn parse_select_version() { let sql = "SELECT @@version";