From: Mike Bayer Date: Thu, 5 Jun 2025 12:58:49 +0000 (-0400) Subject: hardcode now(), current_timstamp() into the MySQL regex X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8e9f789f1aa0309005e8b7725643b32802e7d214;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git hardcode now(), current_timstamp() into the MySQL regex 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 --- diff --git a/doc/build/changelog/unreleased_20/12648.rst b/doc/build/changelog/unreleased_20/12648.rst new file mode 100644 index 0000000000..4abe0e395d --- /dev/null +++ b/doc/build/changelog/unreleased_20/12648.rst @@ -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. + + diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index e45538723e..889ab858b2 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -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})") diff --git a/test/dialect/mysql/test_compiler.py b/test/dialect/mysql/test_compiler.py index 92e9bdd2b9..d458449f09 100644 --- a/test/dialect/mysql/test_compiler.py +++ b/test/dialect/mysql/test_compiler.py @@ -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, ) diff --git a/test/dialect/mysql/test_query.py b/test/dialect/mysql/test_query.py index b15ee517aa..a27993d389 100644 --- a/test/dialect/mysql/test_query.py +++ b/test/dialect/mysql/test_query.py @@ -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(