From c36f00ea8aa65bc8323f41c7d68ee36e6caad370 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Tue, 30 Apr 2019 10:23:20 -0400 Subject: [PATCH] Emit DROP CHECK for MySQL, DROP CONSTRAINT for MariaDB Added support for MySQL "DROP CHECK", which is added as of MySQL 8.0.16, separate from MariaDB's "DROP CONSTRAINT" for CHECK constraints. The MySQL Alembic implementation now checks for "MariaDB" in server_version_info to decide which one to use. Change-Id: I22d1eb084570769ec11b654bc01af3a0938d9a7c Fixes: #554 --- alembic/ddl/mysql.py | 23 ++++++++++++++++------- alembic/testing/fixtures.py | 7 ++++++- alembic/util/sqla_compat.py | 5 ++++- docs/build/unreleased/554.rst | 10 ++++++++++ tests/test_mysql.py | 18 ++++++++++++++---- 5 files changed, 50 insertions(+), 13 deletions(-) create mode 100644 docs/build/unreleased/554.rst diff --git a/alembic/ddl/mysql.py b/alembic/ddl/mysql.py index f886f104..504eb4c6 100644 --- a/alembic/ddl/mysql.py +++ b/alembic/ddl/mysql.py @@ -16,6 +16,7 @@ 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 from ..util.sqla_compat import sqla_100 @@ -126,9 +127,11 @@ class MySQLImpl(DefaultImpl): ): return False elif inspector_column.type._type_affinity is sqltypes.Integer: - rendered_inspector_default = re.sub( - r"^'|'$", "", rendered_inspector_default - ) if rendered_inspector_default is not None else None + rendered_inspector_default = ( + re.sub(r"^'|'$", "", rendered_inspector_default) + if rendered_inspector_default is not None + else None + ) return rendered_inspector_default != rendered_metadata_default elif rendered_inspector_default and rendered_metadata_default: # adjust for "function()" vs. "FUNCTION" @@ -403,10 +406,16 @@ def _mysql_drop_constraint(element, compiler, **kw): # note that SQLAlchemy as of 1.2 does not yet support # DROP CONSTRAINT for MySQL/MariaDB, so we implement fully # here. - return "ALTER TABLE %s DROP CONSTRAINT %s" % ( - compiler.preparer.format_table(constraint.table), - compiler.preparer.format_constraint(constraint), - ) + if _is_mariadb(compiler.dialect): + return "ALTER TABLE %s DROP CONSTRAINT %s" % ( + compiler.preparer.format_table(constraint.table), + compiler.preparer.format_constraint(constraint), + ) + else: + return "ALTER TABLE %s DROP CHECK %s" % ( + compiler.preparer.format_table(constraint.table), + compiler.preparer.format_constraint(constraint), + ) else: raise NotImplementedError( "No generic 'DROP CONSTRAINT' in MySQL - " diff --git a/alembic/testing/fixtures.py b/alembic/testing/fixtures.py index e0b8fdfb..96bb5839 100644 --- a/alembic/testing/fixtures.py +++ b/alembic/testing/fixtures.py @@ -152,7 +152,12 @@ def op_fixture( opts["as_sql"] = as_sql if literal_binds: opts["literal_binds"] = literal_binds - ctx_dialect = _get_dialect(dialect) + if dialect == "mariadb": + ctx_dialect = _get_dialect("mysql") + ctx_dialect.server_version_info = (10, 0, 0, "MariaDB") + + else: + ctx_dialect = _get_dialect(dialect) if native_boolean is not None: ctx_dialect.supports_native_boolean = native_boolean # this is new as of SQLAlchemy 1.2.7 and is used by SQL Server, diff --git a/alembic/util/sqla_compat.py b/alembic/util/sqla_compat.py index 82250d00..52d4e018 100644 --- a/alembic/util/sqla_compat.py +++ b/alembic/util/sqla_compat.py @@ -233,7 +233,10 @@ def _comment_attribute(obj): def _is_mariadb(mysql_dialect): - return "MariaDB" in mysql_dialect.server_version_info + return ( + mysql_dialect.server_version_info + and "MariaDB" in mysql_dialect.server_version_info + ) def _mariadb_normalized_version_info(mysql_dialect): diff --git a/docs/build/unreleased/554.rst b/docs/build/unreleased/554.rst new file mode 100644 index 00000000..02bbd684 --- /dev/null +++ b/docs/build/unreleased/554.rst @@ -0,0 +1,10 @@ +.. change:: + :tags: bug, mysql + :tickets: 554 + + Added support for MySQL "DROP CHECK", which is added as of MySQL 8.0.16, + separate from MariaDB's "DROP CONSTRAINT" for CHECK constraints. The MySQL + Alembic implementation now checks for "MariaDB" in server_version_info to + decide which one to use. + + diff --git a/tests/test_mysql.py b/tests/test_mysql.py index 6e841e4b..6e0db82e 100644 --- a/tests/test_mysql.py +++ b/tests/test_mysql.py @@ -348,16 +348,26 @@ class MySQLOpTest(TestBase): op.drop_constraint("MyUnique", "MyTable", "unique") context.assert_("ALTER TABLE `MyTable` DROP INDEX `MyUnique`") - def test_drop_check(self): - context = op_fixture("mysql") + def test_drop_check_mariadb(self): + context = op_fixture("mariadb") op.drop_constraint("f1", "t1", "check") context.assert_("ALTER TABLE t1 DROP CONSTRAINT f1") - def test_drop_check_quoted(self): - context = op_fixture("mysql") + def test_drop_check_quoted_mariadb(self): + context = op_fixture("mariadb") op.drop_constraint("MyCheck", "MyTable", "check") context.assert_("ALTER TABLE `MyTable` DROP CONSTRAINT `MyCheck`") + def test_drop_check_mysql(self): + context = op_fixture("mysql") + op.drop_constraint("f1", "t1", "check") + context.assert_("ALTER TABLE t1 DROP CHECK f1") + + def test_drop_check_quoted_mysql(self): + context = op_fixture("mysql") + op.drop_constraint("MyCheck", "MyTable", "check") + context.assert_("ALTER TABLE `MyTable` DROP CHECK `MyCheck`") + def test_drop_unknown(self): op_fixture("mysql") assert_raises_message( -- 2.47.2