From: Mike Bayer Date: Thu, 27 Jun 2019 17:25:12 +0000 (-0400) Subject: Unwrap TIMESTAMP when doing an isinstance() X-Git-Tag: rel_1_3_6~29 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=22131f06294698781dca4b279bfeaed818bf1e43;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Unwrap TIMESTAMP when doing an isinstance() Fixed bug where the special logic to render "NULL" for the :class:`.TIMESTAMP` datatype when ``nullable=True`` would not work if the column's datatype were a :class:`.TypeDecorator` or a :class:`.Variant`. The logic now ensures that it unwraps down to the original :class:`.TIMESTAMP` so that this special case NULL keyword is correctly rendered when requested. Fixes: #4743 Change-Id: I02b22dfa3db06daea37b044e2206a8569e2e5d22 (cherry picked from commit 401a2691fbeebd5a26341e732644584cb096bc58) --- diff --git a/doc/build/changelog/unreleased_13/4743.rst b/doc/build/changelog/unreleased_13/4743.rst new file mode 100644 index 0000000000..0bac5dc688 --- /dev/null +++ b/doc/build/changelog/unreleased_13/4743.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, mysql + :tickets: 4743 + + Fixed bug where the special logic to render "NULL" for the + :class:`.TIMESTAMP` datatype when ``nullable=True`` would not work if the + column's datatype were a :class:`.TypeDecorator` or a :class:`.Variant`. + The logic now ensures that it unwraps down to the original + :class:`.TIMESTAMP` so that this special case NULL keyword is correctly + rendered when requested. diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index bfd1693d97..e79327b2b8 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -1499,7 +1499,10 @@ class MySQLDDLCompiler(compiler.DDLCompiler): ), ] - is_timestamp = isinstance(column.type, sqltypes.TIMESTAMP) + is_timestamp = isinstance( + column.type._unwrapped_dialect_impl(self.dialect), + sqltypes.TIMESTAMP, + ) if not column.nullable: colspec.append("NOT NULL") diff --git a/test/dialect/mysql/test_types.py b/test/dialect/mysql/test_types.py index 2801c800b1..86e4b13a08 100644 --- a/test/dialect/mysql/test_types.py +++ b/test/dialect/mysql/test_types.py @@ -1,5 +1,4 @@ # coding: utf-8 - from collections import OrderedDict import datetime import decimal @@ -19,6 +18,7 @@ from sqlalchemy import String from sqlalchemy import Table from sqlalchemy import testing from sqlalchemy import TIMESTAMP +from sqlalchemy import TypeDecorator from sqlalchemy import types as sqltypes from sqlalchemy import UnicodeText from sqlalchemy import util @@ -667,14 +667,27 @@ class TypesTest( Table("t", MetaData(), c) self.assert_compile(schema.CreateColumn(c), "t %s" % expected) + def test_timestamp_nullable_plain(self): + self._test_timestamp_nullable(TIMESTAMP) + + def test_timestamp_nullable_typedecorator(self): + class MyTime(TypeDecorator): + impl = TIMESTAMP + + self._test_timestamp_nullable(MyTime()) + + def test_timestamp_nullable_variant(self): + t = String().with_variant(TIMESTAMP, "mysql") + self._test_timestamp_nullable(t) + @testing.requires.mysql_zero_date @testing.provide_metadata - def test_timestamp_nullable(self): + def _test_timestamp_nullable(self, type_): ts_table = Table( "mysql_timestamp", self.metadata, - Column("t1", TIMESTAMP), - Column("t2", TIMESTAMP, nullable=False), + Column("t1", type_), + Column("t2", type_, nullable=False), mysql_engine="InnoDB", ) self.metadata.create_all()