From: Mike Bayer Date: Fri, 11 Sep 2020 13:56:14 +0000 (-0400) Subject: Use regular renderer for MySQL server default X-Git-Tag: rel_1_4_3~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=712adb3325291561281c64498d77bc0c2b5fe7e1;p=thirdparty%2Fsqlalchemy%2Falembic.git Use regular renderer for MySQL server default Fixed issue where the MySQL dialect would not correctly render the server default of a column in an alter operation, if the operation were programmatically generated from an autogenerate pass as it would not accommodate for the full structure of the DefaultClause construct. Change-Id: I2701b396067e80c75bacbb596e24bb1e75454d10 Fixes: #736 --- diff --git a/alembic/ddl/mysql.py b/alembic/ddl/mysql.py index 96383fb2..446eeb14 100644 --- a/alembic/ddl/mysql.py +++ b/alembic/ddl/mysql.py @@ -15,7 +15,6 @@ from .base import format_server_default from .impl import DefaultImpl from .. import util from ..autogenerate import compare -from ..util.compat import string_types from ..util.sqla_compat import _is_mariadb from ..util.sqla_compat import _is_type_bound @@ -342,13 +341,6 @@ def _mysql_change_column(element, compiler, **kw): ) -def _render_value(compiler, expr): - if isinstance(expr, string_types): - return "'%s'" % expr - else: - return compiler.sql_compiler.process(expr) - - def _mysql_colspec( compiler, nullable, server_default, type_, autoincrement, comment ): @@ -359,7 +351,7 @@ def _mysql_colspec( if autoincrement: spec += " AUTO_INCREMENT" if server_default is not False and server_default is not None: - spec += " DEFAULT %s" % _render_value(compiler, server_default) + spec += " DEFAULT %s" % format_server_default(compiler, server_default) if comment: spec += " COMMENT %s" % compiler.sql_compiler.render_literal_value( comment, sqltypes.String() diff --git a/docs/build/unreleased/736.rst b/docs/build/unreleased/736.rst new file mode 100644 index 00000000..ce166c79 --- /dev/null +++ b/docs/build/unreleased/736.rst @@ -0,0 +1,8 @@ +.. change:: + :tags: bug, ops, mysql + :tickets: 736 + + Fixed issue where the MySQL dialect would not correctly render the server + default of a column in an alter operation, if the operation were + programmatically generated from an autogenerate pass as it would not + accommodate for the full structure of the DefaultClause construct. diff --git a/tests/test_mysql.py b/tests/test_mysql.py index 4294a315..4ab43309 100644 --- a/tests/test_mysql.py +++ b/tests/test_mysql.py @@ -1,6 +1,7 @@ from sqlalchemy import Boolean from sqlalchemy import Column from sqlalchemy import DATETIME +from sqlalchemy import Float from sqlalchemy import func from sqlalchemy import inspect from sqlalchemy import Integer @@ -11,7 +12,10 @@ from sqlalchemy import TIMESTAMP from alembic import op from alembic import util +from alembic.autogenerate import api +from alembic.autogenerate import compare from alembic.migration import MigrationContext +from alembic.operations import ops from alembic.testing import assert_raises_message from alembic.testing import config from alembic.testing.env import clear_staging_env @@ -197,6 +201,35 @@ class MySQLOpTest(TestBase): "ALTER TABLE t CHANGE c c DATETIME NULL DEFAULT CURRENT_TIMESTAMP" ) + def test_alter_column_modify_programmatic_default(self): + # test issue #736 + # when autogenerate.compare creates the operation object + # programmatically, the server_default of the op has the full + # DefaultClause present. make sure the usual renderer works. + context = op_fixture("mysql") + + m1 = MetaData() + + autogen_context = api.AutogenContext(context, m1) + + operation = ops.AlterColumnOp("t", "c") + for fn in ( + compare._compare_nullable, + compare._compare_type, + compare._compare_server_default, + ): + fn( + autogen_context, + operation, + None, + "t", + "c", + Column("c", Float(), nullable=False, server_default=text("0")), + Column("c", Float(), nullable=True, default=0), + ) + op.invoke(operation) + context.assert_("ALTER TABLE t MODIFY c FLOAT NULL DEFAULT 0") + def test_col_not_nullable(self): context = op_fixture("mysql") op.alter_column("t1", "c1", nullable=False, existing_type=Integer)