]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Parse NOT NULL for MySQL generated columns
authorGeorg Wicke-Arndt <wicke-arndt@gapzero.de>
Tue, 9 Jan 2024 13:04:33 +0000 (14:04 +0100)
committerGeorg Wicke-Arndt <georg.wicke@rwth-aachen.de>
Sat, 13 Jan 2024 23:14:17 +0000 (00:14 +0100)
As per the MySQL CREATE TABLE specification (see https://dev.mysql.com/doc/refman/8.0/en/create-table.html),
the location of the NULL/NOT NULL syntax is slightly different for generated vs. regular columns: in generated
columns, the NULL/NOT NULL goes after the VIRTUAL/STORED instead of directly after the data type.

Fixes #10850

lib/sqlalchemy/dialects/mysql/reflection.py
test/dialect/mysql/test_reflection.py

index 74c60f07b58c274e20a5e96ae784f6bcc5927715..c764e8ccc7fd36e98810d2cd571bc319596e521f 100644 (file)
@@ -290,6 +290,9 @@ class MySQLTableDefinitionParser:
         # this can be "NULL" in the case of TIMESTAMP
         if spec.get("notnull", False) == "NOT NULL":
             col_kw["nullable"] = False
+        # For generated columns, the nullability is marked in a different place
+        if spec.get("notnull_generated", False) == "NOT NULL":
+            col_kw["nullable"] = False
 
         # AUTO_INCREMENT
         if spec.get("autoincr", False):
@@ -452,7 +455,9 @@ class MySQLTableDefinitionParser:
             r"(?: +ON UPDATE [\-\w\.\(\)]+)?)"
             r"))?"
             r"(?: +(?:GENERATED ALWAYS)? ?AS +(?P<generated>\("
-            r".*\))? ?(?P<persistence>VIRTUAL|STORED)?)?"
+            r".*\))? ?(?P<persistence>VIRTUAL|STORED)?"
+            r"(?: +(?P<notnull_generated>(?:NOT )?NULL))?"
+            r")?"
             r"(?: +(?P<autoincr>AUTO_INCREMENT))?"
             r"(?: +COMMENT +'(?P<comment>(?:''|[^'])*)')?"
             r"(?: +COLUMN_FORMAT +(?P<colfmt>\w+))?"
index f3d1f34599b00c3a5ed68afaf41af824787f04f7..573fed45d8647d8b43180e1f6e80ffb3822dde3f 100644 (file)
@@ -792,6 +792,7 @@ class ReflectionTest(fixtures.TestBase, AssertsCompiledSQL):
                 ["s TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP"],
                 ["t TIMESTAMP"],
                 ["u TIMESTAMP DEFAULT CURRENT_TIMESTAMP"],
+                ["v INTEGER GENERATED ALWAYS AS (4711) VIRTUAL NOT NULL"],
             ]
         ):
             Table("nn_t%d" % idx, meta)  # to allow DROP
@@ -859,6 +860,7 @@ class ReflectionTest(fixtures.TestBase, AssertsCompiledSQL):
                     else False,
                     "default": current_timestamp,
                 },
+                {"name": "v", "nullable": False, "default": None},
             ],
         )