This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-sqlparser-rs.git


The following commit(s) were added to refs/heads/main by this push:
     new cb21477f MySQL: Allow optional constraint name after CONSTRAINT 
keyword (#2183)
cb21477f is described below

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]

Reply via email to