This is an automated email from the ASF dual-hosted git repository. github-bot pushed a commit to branch gh-readonly-queue/main/pr-2243-6f0e803aa77414e83aefd326e23231c51b60ae32 in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit 83baf5e89179dd00321330312fe460100d755c25 Author: Michael Victor Zink <[email protected]> AuthorDate: Fri Feb 27 02:59:05 2026 -0800 Support MySQL KEY keyword in column definitions (#2243) Co-authored-by: Yoav Cohen <[email protected]> --- src/ast/ddl.rs | 2 +- src/dialect/generic.rs | 4 ++++ src/dialect/mod.rs | 12 ++++++++++++ src/dialect/mysql.rs | 5 +++++ src/parser/mod.rs | 23 ++++++++++++++++++++++- tests/sqlparser_mysql.rs | 9 +++++++++ 6 files changed, 53 insertions(+), 2 deletions(-) diff --git a/src/ast/ddl.rs b/src/ast/ddl.rs index 0c4f93e6..3a951f66 100644 --- a/src/ast/ddl.rs +++ b/src/ast/ddl.rs @@ -2040,7 +2040,7 @@ impl fmt::Display for ColumnOption { Ok(()) } Unique(constraint) => { - write!(f, "UNIQUE")?; + write!(f, "UNIQUE{:>}", constraint.index_type_display)?; if let Some(characteristics) = &constraint.characteristics { write!(f, " {characteristics}")?; } diff --git a/src/dialect/generic.rs b/src/dialect/generic.rs index 1cf195e6..a7a3c271 100644 --- a/src/dialect/generic.rs +++ b/src/dialect/generic.rs @@ -280,4 +280,8 @@ impl Dialect for GenericDialect { fn supports_constraint_keyword_without_name(&self) -> bool { true } + + fn supports_key_column_option(&self) -> bool { + true + } } diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index 698c12ec..796b25f0 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -1195,6 +1195,18 @@ pub trait Dialect: Debug + Any { false } + /// Returns true if the dialect supports the `KEY` keyword as part of + /// column-level constraints in a `CREATE TABLE` statement. + /// + /// When enabled, the parser accepts these MySQL-specific column options: + /// - `UNIQUE [KEY]` — optional `KEY` after `UNIQUE` + /// - `[PRIMARY] KEY` — standalone `KEY` as shorthand for `PRIMARY KEY` + /// + /// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html> + fn supports_key_column_option(&self) -> bool { + false + } + /// Returns true if the specified keyword is reserved and cannot be /// used as an identifier without special handling like quoting. fn is_reserved_for_identifier(&self, kw: Keyword) -> bool { diff --git a/src/dialect/mysql.rs b/src/dialect/mysql.rs index bdced482..6b057539 100644 --- a/src/dialect/mysql.rs +++ b/src/dialect/mysql.rs @@ -206,6 +206,11 @@ impl Dialect for MySqlDialect { fn supports_constraint_keyword_without_name(&self) -> bool { true } + + /// See: <https://dev.mysql.com/doc/refman/8.4/en/create-table.html> + fn supports_key_column_option(&self) -> bool { + true + } } /// `LOCK TABLES` diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 75db4d24..a00eab34 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9048,12 +9048,18 @@ impl<'a> Parser<'a> { .into(), )) } else if self.parse_keyword(Keyword::UNIQUE) { + let index_type_display = + if self.dialect.supports_key_column_option() && self.parse_keyword(Keyword::KEY) { + KeyOrIndexDisplay::Key + } else { + KeyOrIndexDisplay::None + }; let characteristics = self.parse_constraint_characteristics()?; Ok(Some( UniqueConstraint { name: None, index_name: None, - index_type_display: KeyOrIndexDisplay::None, + index_type_display, index_type: None, columns: vec![], index_options: vec![], @@ -9062,6 +9068,21 @@ impl<'a> Parser<'a> { } .into(), )) + } else if self.dialect.supports_key_column_option() && self.parse_keyword(Keyword::KEY) { + // In MySQL, `KEY` in a column definition is shorthand for `PRIMARY KEY`. + // See: https://dev.mysql.com/doc/refman/8.4/en/create-table.html + let characteristics = self.parse_constraint_characteristics()?; + Ok(Some( + PrimaryKeyConstraint { + name: None, + index_name: None, + index_type: None, + columns: vec![], + index_options: vec![], + characteristics, + } + .into(), + )) } else if self.parse_keyword(Keyword::REFERENCES) { let foreign_table = self.parse_object_name(false)?; // PostgreSQL allows omitting the column list and diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 30405623..b4ae764c 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -944,6 +944,15 @@ fn parse_create_table_primary_and_unique_key_characteristic_test() { } } +#[test] +fn parse_create_table_column_key_options() { + mysql_and_generic().verified_stmt("CREATE TABLE foo (x INT UNIQUE KEY)"); + mysql_and_generic().one_statement_parses_to( + "CREATE TABLE foo (x INT KEY)", + "CREATE TABLE foo (x INT PRIMARY KEY)", + ); +} + #[test] fn parse_create_table_comment() { let without_equal = "CREATE TABLE foo (bar INT) COMMENT 'baz'"; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
