Repository: apache/datafusion-sqlparser-rs (Rust)

Issue:
MySQL "ALTER ... DROP PRIMARY KEY" is not parsed correctly
The following alter statement to drop primary key directly is allowed in MySQL:

```SQL
ALTER TABLE table_name DROP PRIMARY KEY;
```

However, it's not parsed correctly in sqlparser, for example:

```Rust
use sqlparser::dialect::MySqlDialect;
use sqlparser::parser::Parser;
use sqlparser::tokenizer::Token;
use sqlparser::tokenizer::Tokenizer;

#[test]
fn test() {
    let dialect = &MySqlDialect {};
    let sql = r"ALTER TABLE my_table DROP PRIMARY KEY;";
    let mut tokenizer = Tokenizer::new(dialect, sql);
    let tokens: Vec<Token> = tokenizer.tokenize().unwrap();
    let mut parser = Parser::new(tokens, dialect);
    parser.next_token();
    let statement = parser.parse_alter();
    println!("{:?}", statement);
}
```

Which prints 

Ok(AlterTable { name: ObjectName([Ident { value: "my_table", quote_style: None }]), operation: DropColumn { column_name: Ident { value: "PRIMARY", quote_style: None }, if_exists: false, cascade: false } })

Looks like the "drop primary key" is interpreted as "drop column 'PRIMARY'".


Discussion:

Patch:
diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs
index cae0f597b..c758b4f55 100644
--- a/src/ast/ddl.rs
+++ b/src/ast/ddl.rs
@@ -44,6 +44,10 @@ pub enum AlterTableOperation {
         if_exists: bool,
         cascade: bool,
     },
+    /// `DROP PRIMARY KEY`
+    ///
+    /// Note: this is a MySQL-specific operation.
+    DropPrimaryKey,
     /// `RENAME TO PARTITION (partition=val)`
     RenamePartitions {
         old_partitions: Vec<Expr>,
@@ -124,6 +128,7 @@ impl fmt::Display for AlterTableOperation {
                     if *cascade { " CASCADE" } else { "" },
                 )
             }
+            AlterTableOperation::DropPrimaryKey => write!(f, "DROP PRIMARY KEY"),
             AlterTableOperation::DropColumn {
                 column_name,
                 if_exists,
diff --git a/src/parser.rs b/src/parser.rs
index 108427889..d1c2911fc 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -3136,6 +3136,10 @@ impl<'a> Parser<'a> {
                     name,
                     cascade,
                 }
+            } else if self.parse_keywords(&[Keyword::PRIMARY, Keyword::KEY])
+                && dialect_of!(self is MySqlDialect | GenericDialect)
+            {
+                AlterTableOperation::DropPrimaryKey
             } else {
                 let _ = self.parse_keyword(Keyword::COLUMN);
                 let if_exists = self.parse_keywords(&[Keyword::IF, Keyword::EXISTS]);


Test patch:
diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs
index 8c42c715b..52c0205d6 100644
--- a/tests/sqlparser_mysql.rs
+++ b/tests/sqlparser_mysql.rs
@@ -875,6 +875,19 @@ fn parse_update_with_joins() {
     }
 }
 
+#[test]
+fn parse_alter_table_drop_primary_key() {
+    match mysql_and_generic().verified_stmt("ALTER TABLE tab DROP PRIMARY KEY") {
+        Statement::AlterTable {
+            name,
+            operation: AlterTableOperation::DropPrimaryKey,
+        } => {
+            assert_eq!("tab", name.to_string());
+        }
+        _ => unreachable!(),
+    }
+}
+
 #[test]
 fn parse_alter_table_change_column() {
     let expected_name = ObjectName(vec![Ident::new("orders")]);