]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
hardcode now(), current_timstamp() into the MySQL regex
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 5 Jun 2025 12:58:49 +0000 (08:58 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 5 Jun 2025 16:41:19 +0000 (12:41 -0400)
Fixed yet another regression caused by by the DEFAULT rendering changes in
2.0.40 :ticket:`12425`, similar to :ticket:`12488`, this time where using a
CURRENT_TIMESTAMP function with a fractional seconds portion inside a
textual default value would also fail to be recognized as a
non-parenthesized server default.

There's no way to do this other than start hardcoding a list
of MySQL functions that demand that parenthesis are not added around
them, I can think of no other heuristic that will work here.
Suggestions welcome

Fixes: #12648
Change-Id: I75d274b56306089929b369ecfb23604e9d6fa9dd

doc/build/changelog/unreleased_20/12648.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mysql/base.py
test/dialect/mysql/test_compiler.py
test/dialect/mysql/test_query.py

diff --git a/doc/build/changelog/unreleased_20/12648.rst b/doc/build/changelog/unreleased_20/12648.rst
new file mode 100644 (file)
index 0000000..4abe0e3
--- /dev/null
@@ -0,0 +1,11 @@
+.. change::
+    :tags: bug, mysql
+    :tickets: 12648
+
+    Fixed yet another regression caused by by the DEFAULT rendering changes in
+    2.0.40 :ticket:`12425`, similar to :ticket:`12488`, this time where using a
+    CURRENT_TIMESTAMP function with a fractional seconds portion inside a
+    textual default value would also fail to be recognized as a
+    non-parenthesized server default.
+
+
index e45538723ecbc50782f65912996fc15981c23972..889ab858b2cf6f179745ef244a2c5920c9a8ddea 100644 (file)
@@ -2083,6 +2083,11 @@ class MySQLDDLCompiler(compiler.DDLCompiler):
                     self.dialect._support_default_function
                     and not re.match(r"^\s*[\'\"\(]", default)
                     and not re.search(r"ON +UPDATE", default, re.I)
+                    and not re.match(
+                        r"\bnow\(\d+\)|\bcurrent_timestamp\(\d+\)",
+                        default,
+                        re.I,
+                    )
                     and re.match(r".*\W.*", default)
                 ):
                     colspec.append(f"DEFAULT ({default})")
index 92e9bdd2b9f36f3dd4203a9e49b4d393bc27b2d3..d458449f09421f05bea20b51abac6fecde2c3bd6 100644 (file)
@@ -457,6 +457,26 @@ class CompileTest(ReservedWordFixture, fixtures.TestBase, AssertsCompiledSQL):
                 DateTime,
                 server_default=text("now() ON UPDATE now()"),
             ),
+            Column(
+                "updated4",
+                DateTime,
+                server_default=text("now(3)"),
+            ),
+            Column(
+                "updated5",
+                DateTime,
+                server_default=text("nOW(3)"),
+            ),
+            Column(
+                "updated6",
+                DateTime,
+                server_default=text("notnow(1)"),
+            ),
+            Column(
+                "updated7",
+                DateTime,
+                server_default=text("CURRENT_TIMESTAMP(3)"),
+            ),
         )
 
         eq_(dialect._support_default_function, has_brackets)
@@ -471,7 +491,11 @@ class CompileTest(ReservedWordFixture, fixtures.TestBase, AssertsCompiledSQL):
                 "data JSON DEFAULT (json_object()), "
                 "updated1 DATETIME DEFAULT now() on update now(), "
                 "updated2 DATETIME DEFAULT now() On  UpDate now(), "
-                "updated3 DATETIME DEFAULT now() ON UPDATE now())",
+                "updated3 DATETIME DEFAULT now() ON UPDATE now(), "
+                "updated4 DATETIME DEFAULT now(3), "
+                "updated5 DATETIME DEFAULT nOW(3), "
+                "updated6 DATETIME DEFAULT (notnow(1)), "
+                "updated7 DATETIME DEFAULT CURRENT_TIMESTAMP(3))",
                 dialect=dialect,
             )
         else:
@@ -484,7 +508,11 @@ class CompileTest(ReservedWordFixture, fixtures.TestBase, AssertsCompiledSQL):
                 "data JSON DEFAULT json_object(), "
                 "updated1 DATETIME DEFAULT now() on update now(), "
                 "updated2 DATETIME DEFAULT now() On  UpDate now(), "
-                "updated3 DATETIME DEFAULT now() ON UPDATE now())",
+                "updated3 DATETIME DEFAULT now() ON UPDATE now(), "
+                "updated4 DATETIME DEFAULT now(3), "
+                "updated5 DATETIME DEFAULT nOW(3), "
+                "updated6 DATETIME DEFAULT notnow(1), "
+                "updated7 DATETIME DEFAULT CURRENT_TIMESTAMP(3))",
                 dialect=dialect,
             )
 
index b15ee517aa022a5c76caf8794db2fe5d025286d5..a27993d38972f3af1230d2db9a92f0f94dc6573e 100644 (file)
@@ -24,6 +24,7 @@ from sqlalchemy import text
 from sqlalchemy import true
 from sqlalchemy import update
 from sqlalchemy.dialects.mysql import limit
+from sqlalchemy.dialects.mysql import TIMESTAMP
 from sqlalchemy.testing import assert_raises
 from sqlalchemy.testing import combinations
 from sqlalchemy.testing import eq_
@@ -90,6 +91,16 @@ class ServerDefaultCreateTest(fixtures.TestBase):
             DateTime,
             text("now() ON   UPDATE now()"),
         ),
+        (
+            TIMESTAMP(fsp=3),
+            text("now(3)"),
+            testing.requires.mysql_fsp,
+        ),
+        (
+            TIMESTAMP(fsp=3),
+            text("CURRENT_TIMESTAMP(3)"),
+            testing.requires.mysql_fsp,
+        ),
         argnames="datatype, default",
     )
     def test_create_server_defaults(