From f3600ab89957600883f89ce9bface3c27c930e56 Mon Sep 17 00:00:00 2001 From: Stepan Koltsov Date: Wed, 8 Jan 2025 20:41:15 +0000 Subject: [PATCH] ALTER TABLE DROP {COLUMN|CONSTRAINT} xxx RESTRICT https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#_11_23_drop_column_definition https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#_11_26_drop_table_constraint_definition --- src/ast/ddl.rs | 20 ++++++++++---- src/ast/spans.rs | 4 +-- src/parser/mod.rs | 8 +++--- tests/sqlparser_common.rs | 58 +++++++++++++++++++-------------------- 4 files changed, 48 insertions(+), 42 deletions(-) diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index f31fbf293..1b5ccda26 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -115,13 +115,13 @@ pub enum AlterTableOperation { DropConstraint { if_exists: bool, name: Ident, - cascade: bool, + drop_behavior: Option, }, /// `DROP [ COLUMN ] [ IF EXISTS ] [ CASCADE ]` DropColumn { column_name: Ident, if_exists: bool, - cascade: bool, + drop_behavior: Option, }, /// `ATTACH PART|PARTITION ` /// Note: this is a ClickHouse-specific operation, please refer to @@ -451,27 +451,35 @@ impl fmt::Display for AlterTableOperation { AlterTableOperation::DropConstraint { if_exists, name, - cascade, + drop_behavior, } => { write!( f, "DROP CONSTRAINT {}{}{}", if *if_exists { "IF EXISTS " } else { "" }, name, - if *cascade { " CASCADE" } else { "" }, + match drop_behavior { + None => "", + Some(DropBehavior::Restrict) => " RESTRICT", + Some(DropBehavior::Cascade) => " CASCADE", + } ) } AlterTableOperation::DropPrimaryKey => write!(f, "DROP PRIMARY KEY"), AlterTableOperation::DropColumn { column_name, if_exists, - cascade, + drop_behavior, } => write!( f, "DROP COLUMN {}{}{}", if *if_exists { "IF EXISTS " } else { "" }, column_name, - if *cascade { " CASCADE" } else { "" } + match drop_behavior { + None => "", + Some(DropBehavior::Restrict) => " RESTRICT", + Some(DropBehavior::Cascade) => " CASCADE", + } ), AlterTableOperation::AttachPartition { partition } => { write!(f, "ATTACH {partition}") diff --git a/src/ast/spans.rs b/src/ast/spans.rs index 2ca659147..82d40b3b6 100644 --- a/src/ast/spans.rs +++ b/src/ast/spans.rs @@ -960,12 +960,12 @@ impl Spanned for AlterTableOperation { AlterTableOperation::DropConstraint { if_exists: _, name, - cascade: _, + drop_behavior: _, } => name.span, AlterTableOperation::DropColumn { column_name, if_exists: _, - cascade: _, + drop_behavior: _, } => column_name.span, AlterTableOperation::AttachPartition { partition } => partition.span(), AlterTableOperation::DetachPartition { partition } => partition.span(), diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 3ffd78d02..4274ccc47 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -7615,11 +7615,11 @@ impl<'a> Parser<'a> { } 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); + let drop_behavior = self.parse_optional_drop_behavior(); AlterTableOperation::DropConstraint { if_exists, name, - cascade, + drop_behavior, } } else if self.parse_keywords(&[Keyword::PRIMARY, Keyword::KEY]) && dialect_of!(self is MySqlDialect | GenericDialect) @@ -7637,11 +7637,11 @@ impl<'a> Parser<'a> { let _ = self.parse_keyword(Keyword::COLUMN); // [ COLUMN ] let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]); let column_name = self.parse_identifier()?; - let cascade = self.parse_keyword(Keyword::CASCADE); + let drop_behavior = self.parse_optional_drop_behavior(); AlterTableOperation::DropColumn { column_name, if_exists, - cascade, + drop_behavior, } } } else if self.parse_keyword(Keyword::PARTITION) { diff --git a/tests/sqlparser_common.rs b/tests/sqlparser_common.rs index 899194eb1..220b6fcb4 100644 --- a/tests/sqlparser_common.rs +++ b/tests/sqlparser_common.rs @@ -4388,7 +4388,9 @@ fn parse_alter_table_constraints() { #[test] fn parse_alter_table_drop_column() { + check_one("DROP COLUMN IF EXISTS is_active"); check_one("DROP COLUMN IF EXISTS is_active CASCADE"); + check_one("DROP COLUMN IF EXISTS is_active RESTRICT"); one_statement_parses_to( "ALTER TABLE tab DROP IF EXISTS is_active CASCADE", "ALTER TABLE tab DROP COLUMN IF EXISTS is_active CASCADE", @@ -4403,11 +4405,15 @@ fn parse_alter_table_drop_column() { AlterTableOperation::DropColumn { column_name, if_exists, - cascade, + drop_behavior, } => { assert_eq!("is_active", column_name.to_string()); assert!(if_exists); - assert!(cascade); + match drop_behavior { + None => assert!(constraint_text.ends_with(" is_active")), + Some(DropBehavior::Restrict) => assert!(constraint_text.ends_with(" RESTRICT")), + Some(DropBehavior::Cascade) => assert!(constraint_text.ends_with(" CASCADE")), + } } _ => unreachable!(), } @@ -4497,37 +4503,29 @@ fn parse_alter_table_alter_column_type() { #[test] fn parse_alter_table_drop_constraint() { - let alter_stmt = "ALTER TABLE tab"; - match alter_table_op(verified_stmt( - "ALTER TABLE tab DROP CONSTRAINT constraint_name CASCADE", - )) { - AlterTableOperation::DropConstraint { - name: constr_name, - if_exists, - cascade, - } => { - assert_eq!("constraint_name", constr_name.to_string()); - assert!(!if_exists); - assert!(cascade); - } - _ => unreachable!(), - } - match alter_table_op(verified_stmt( - "ALTER TABLE tab DROP CONSTRAINT IF EXISTS constraint_name", - )) { - AlterTableOperation::DropConstraint { - name: constr_name, - if_exists, - cascade, - } => { - assert_eq!("constraint_name", constr_name.to_string()); - assert!(if_exists); - assert!(!cascade); + check_one("DROP CONSTRAINT IF EXISTS constraint_name"); + check_one("DROP CONSTRAINT IF EXISTS constraint_name RESTRICT"); + check_one("DROP CONSTRAINT IF EXISTS constraint_name CASCADE"); + fn check_one(constraint_text: &str) { + match alter_table_op(verified_stmt(&format!("ALTER TABLE tab {constraint_text}"))) { + AlterTableOperation::DropConstraint { + name: constr_name, + if_exists, + drop_behavior, + } => { + assert_eq!("constraint_name", constr_name.to_string()); + assert!(if_exists); + match drop_behavior { + None => assert!(constraint_text.ends_with(" constraint_name")), + Some(DropBehavior::Restrict) => assert!(constraint_text.ends_with(" RESTRICT")), + Some(DropBehavior::Cascade) => assert!(constraint_text.ends_with(" CASCADE")), + } + } + _ => unreachable!(), } - _ => unreachable!(), } - let res = parse_sql_statements(&format!("{alter_stmt} DROP CONSTRAINT is_active TEXT")); + let res = parse_sql_statements("ALTER TABLE tab DROP CONSTRAINT is_active TEXT"); assert_eq!( ParserError::ParserError("Expected: end of statement, found: TEXT".to_string()), res.unwrap_err()