diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 78ec2e0c7..7ff17c616 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -31,8 +31,12 @@ pub enum AlterTableOperation { AddConstraint(TableConstraint), /// `ADD [ COLUMN ] ` AddColumn { column_def: ColumnDef }, - /// TODO: implement `DROP CONSTRAINT ` - DropConstraint { name: Ident }, + /// `DROP CONSTRAINT [ IF EXISTS ] ` + DropConstraint { + if_exists: bool, + name: Ident, + cascade: bool, + }, /// `DROP [ COLUMN ] [ IF EXISTS ] [ CASCADE ]` DropColumn { column_name: Ident, @@ -106,7 +110,19 @@ impl fmt::Display for AlterTableOperation { display_comma_separated(partitions), ie = if *if_exists { " IF EXISTS" } else { "" } ), - AlterTableOperation::DropConstraint { name } => write!(f, "DROP CONSTRAINT {}", name), + AlterTableOperation::DropConstraint { + if_exists, + name, + cascade, + } => { + write!( + f, + "DROP CONSTRAINT {}{}{}", + if *if_exists { "IF EXISTS " } else { "" }, + name, + if *cascade { " CASCADE" } else { "" }, + ) + } AlterTableOperation::DropColumn { column_name, if_exists, diff --git a/src/parser.rs b/src/parser.rs index 6d917f027..3fd2cf537 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1982,6 +1982,15 @@ impl<'a> Parser<'a> { partitions, if_exists: false, } + } else if self.parse_keyword(Keyword::CONSTRAINT) { + let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); + let name = self.parse_identifier()?; + let cascade = self.parse_keyword(Keyword::CASCADE); + AlterTableOperation::DropConstraint { + if_exists, + name, + cascade, + } } else { let _ = self.parse_keyword(Keyword::COLUMN); let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 07a0db524..82c59bd1c 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -2052,6 +2052,54 @@ fn parse_alter_table_alter_column_type() { ); } +#[test] +fn parse_alter_table_drop_constraint() { + let alter_stmt = "ALTER TABLE tab"; + match verified_stmt("ALTER TABLE tab DROP CONSTRAINT constraint_name CASCADE") { + Statement::AlterTable { + name, + operation: + AlterTableOperation::DropConstraint { + name: constr_name, + if_exists, + cascade, + }, + } => { + assert_eq!("tab", name.to_string()); + assert_eq!("constraint_name", constr_name.to_string()); + assert!(!if_exists); + assert!(cascade); + } + _ => unreachable!(), + } + match verified_stmt("ALTER TABLE tab DROP CONSTRAINT IF EXISTS constraint_name") { + Statement::AlterTable { + name, + operation: + AlterTableOperation::DropConstraint { + name: constr_name, + if_exists, + cascade, + }, + } => { + assert_eq!("tab", name.to_string()); + assert_eq!("constraint_name", constr_name.to_string()); + assert!(if_exists); + assert!(!cascade); + } + _ => unreachable!(), + } + + let res = Parser::parse_sql( + &GenericDialect {}, + &format!("{} DROP CONSTRAINT is_active TEXT", alter_stmt), + ); + assert_eq!( + ParserError::ParserError("Expected end of statement, found: TEXT".to_string()), + res.unwrap_err() + ); +} + #[test] fn parse_bad_constraint() { let res = parse_sql_statements("ALTER TABLE tab ADD");