This is an automated email from the ASF dual-hosted git repository. github-bot pushed a commit to branch gh-readonly-queue/main/pr-2183-d7f56e8942f5e5ad2949b1a9be5f5b1c9bf1c3cd in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git
commit cb21477fdc4527d6a09accf3da201c086782293e Author: Michael Victor Zink <[email protected]> AuthorDate: Fri Feb 6 03:19:53 2026 -0800 MySQL: Allow optional constraint name after CONSTRAINT keyword (#2183) --- src/dialect/generic.rs | 4 ++++ src/dialect/mod.rs | 17 +++++++++++++++++ src/dialect/mysql.rs | 5 +++++ src/parser/mod.rs | 15 ++++++++++++++- tests/sqlparser_mysql.rs | 21 +++++++++++++++++++++ 5 files changed, 61 insertions(+), 1 deletion(-) diff --git a/src/dialect/generic.rs b/src/dialect/generic.rs index 345d63fe..6d25fa2b 100644 --- a/src/dialect/generic.rs +++ b/src/dialect/generic.rs @@ -275,4 +275,8 @@ impl Dialect for GenericDialect { fn supports_comment_optimizer_hint(&self) -> bool { true } + + fn supports_constraint_keyword_without_name(&self) -> bool { + true + } } diff --git a/src/dialect/mod.rs b/src/dialect/mod.rs index f23eb387..15a9c2d1 100644 --- a/src/dialect/mod.rs +++ b/src/dialect/mod.rs @@ -1169,6 +1169,23 @@ pub trait Dialect: Debug + Any { false } + /// Returns true if the dialect supports the `CONSTRAINT` keyword without a name + /// in table constraint definitions. + /// + /// Example: + /// ```sql + /// CREATE TABLE t (a INT, CONSTRAINT CHECK (a > 0)) + /// ``` + /// + /// This is a MySQL extension; the SQL standard requires a name after `CONSTRAINT`. + /// When the name is omitted, the output normalizes to just the constraint type + /// without the `CONSTRAINT` keyword (e.g., `CHECK (a > 0)`). + /// + /// <https://dev.mysql.com/doc/refman/8.4/en/create-table.html> + fn supports_constraint_keyword_without_name(&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 e1a68417..3adb4bc2 100644 --- a/src/dialect/mysql.rs +++ b/src/dialect/mysql.rs @@ -190,6 +190,11 @@ impl Dialect for MySqlDialect { fn supports_comment_optimizer_hint(&self) -> bool { true } + + /// See: <https://dev.mysql.com/doc/refman/8.4/en/create-table.html> + fn supports_constraint_keyword_without_name(&self) -> bool { + true + } } /// `LOCK TABLES` diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 5b1f5990..fb150b76 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -9293,7 +9293,20 @@ impl<'a> Parser<'a> { &mut self, ) -> Result<Option<TableConstraint>, ParserError> { let name = if self.parse_keyword(Keyword::CONSTRAINT) { - Some(self.parse_identifier()?) + if self.dialect.supports_constraint_keyword_without_name() + && self + .peek_one_of_keywords(&[ + Keyword::CHECK, + Keyword::PRIMARY, + Keyword::UNIQUE, + Keyword::FOREIGN, + ]) + .is_some() + { + None + } else { + Some(self.parse_identifier()?) + } } else { None }; diff --git a/tests/sqlparser_mysql.rs b/tests/sqlparser_mysql.rs index 601b6c4f..1b9d12f8 100644 --- a/tests/sqlparser_mysql.rs +++ b/tests/sqlparser_mysql.rs @@ -3469,6 +3469,27 @@ fn parse_create_table_unallow_constraint_then_index() { assert!(mysql_and_generic().parse_sql_statements(sql).is_ok()); } +#[test] +fn parse_create_table_constraint_check_without_name() { + let dialects = all_dialects_where(|d| d.supports_constraint_keyword_without_name()); + dialects.one_statement_parses_to( + "CREATE TABLE t (x INT, CONSTRAINT PRIMARY KEY (x))", + "CREATE TABLE t (x INT, PRIMARY KEY (x))", + ); + dialects.one_statement_parses_to( + "CREATE TABLE t (x INT, CONSTRAINT UNIQUE (x))", + "CREATE TABLE t (x INT, UNIQUE (x))", + ); + dialects.one_statement_parses_to( + "CREATE TABLE t (x INT, CONSTRAINT FOREIGN KEY (x) REFERENCES t2(id))", + "CREATE TABLE t (x INT, FOREIGN KEY (x) REFERENCES t2(id))", + ); + dialects.one_statement_parses_to( + "CREATE TABLE t (x INT, CONSTRAINT CHECK (x > 1))", + "CREATE TABLE t (x INT, CHECK (x > 1))", + ); +} + #[test] fn parse_create_table_with_fulltext_definition() { mysql_and_generic().verified_stmt("CREATE TABLE tb (id INT, FULLTEXT (id))"); --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
