From 1f4d8c61033685d90c344c96222e2f8249ca68e8 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Thu, 5 Jun 2014 16:22:14 -0400 Subject: [PATCH] - Liberalized even more the check for MySQL indexes that shouldn't be counted in autogenerate as "drops"; this time it's been reported that an implicitly created index might be named the same as a composite foreign key constraint, and not the actual columns, so we now skip those when detected as well. fixes #208 --- alembic/ddl/mysql.py | 17 +++++++--- docs/build/changelog.rst | 10 ++++++ tests/__init__.py | 2 +- tests/test_autogen_indexes.py | 58 ++++++++++++++++++++++++++++++----- 4 files changed, 74 insertions(+), 13 deletions(-) diff --git a/alembic/ddl/mysql.py b/alembic/ddl/mysql.py index 96f42f38..58d5c705 100644 --- a/alembic/ddl/mysql.py +++ b/alembic/ddl/mysql.py @@ -78,10 +78,19 @@ class MySQLImpl(DefaultImpl): removed = set() for idx in list(conn_indexes): # MySQL puts implicit indexes on FK columns, even if - # composite and even if MyISAM, so can't check this too easily - if idx.name == idx.columns.keys()[0]: - conn_indexes.remove(idx) - removed.add(idx.name) + # composite and even if MyISAM, so can't check this too easily. + # the name of the index may be the column name or it may + # be the name of the FK constraint. + for col in idx.columns: + if idx.name == col.name: + conn_indexes.remove(idx) + removed.add(idx.name) + break + for fk in col.foreign_keys: + if fk.name == idx.name: + conn_indexes.remove(idx) + removed.add(idx.name) + break # then remove indexes from the "metadata_indexes" # that we've removed from reflected, otherwise they come out diff --git a/docs/build/changelog.rst b/docs/build/changelog.rst index 1a00cbcb..89d945e0 100644 --- a/docs/build/changelog.rst +++ b/docs/build/changelog.rst @@ -5,6 +5,16 @@ Changelog .. changelog:: :version: 0.6.6 + .. change:: + :tags: bug + :tickets: 208 + + Liberalized even more the check for MySQL indexes that shouldn't be + counted in autogenerate as "drops"; this time it's been reported + that an implicitly created index might be named the same as a composite + foreign key constraint, and not the actual columns, so we now skip those + when detected as well. + .. change:: :tags: feature :pullreq: github:10 diff --git a/tests/__init__.py b/tests/__init__.py index cfb90983..85ea5b32 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -65,7 +65,7 @@ def db_for_dialect(name): except configparser.NoOptionError: raise SkipTest("No dialect %r in test.cfg" % name) try: - eng = create_engine(cfg) + eng = create_engine(cfg, echo='debug') except ImportError as er1: raise SkipTest("Can't import DBAPI: %s" % er1) try: diff --git a/tests/test_autogen_indexes.py b/tests/test_autogen_indexes.py index e9d93211..2f7a4a1c 100644 --- a/tests/test_autogen_indexes.py +++ b/tests/test_autogen_indexes.py @@ -5,8 +5,9 @@ from sqlalchemy import MetaData, Column, Table, Integer, String, Text, \ Numeric, DATETIME, INTEGER, \ TypeDecorator, Unicode, Enum,\ UniqueConstraint, Boolean, \ - PrimaryKeyConstraint, Index, func, ForeignKeyConstraint - + PrimaryKeyConstraint, Index, func, ForeignKeyConstraint,\ + ForeignKey +from sqlalchemy.schema import AddConstraint from . import sqlite_db, eq_, db_for_dialect py3k = sys.version_info >= (3, ) @@ -190,31 +191,37 @@ class AutogenerateUniqueIndexTest(AutogenFixtureTest, TestCase): Table('nothing_changed', m1, Column('id1', Integer, primary_key=True), Column('id2', Integer, primary_key=True), - Column('x', String(20), unique=True) + Column('x', String(20), unique=True), + mysql_engine='InnoDB' ) Table('nothing_changed_related', m1, Column('id1', Integer), Column('id2', Integer), ForeignKeyConstraint(['id1', 'id2'], - ['nothing_changed.id1', 'nothing_changed.id2']) + ['nothing_changed.id1', 'nothing_changed.id2']), + mysql_engine='InnoDB' ) Table('nothing_changed', m2, Column('id1', Integer, primary_key=True), Column('id2', Integer, primary_key=True), - Column('x', String(20), unique=True) + Column('x', String(20), unique=True), + mysql_engine='InnoDB' ) Table('nothing_changed_related', m2, Column('id1', Integer), Column('id2', Integer), ForeignKeyConstraint(['id1', 'id2'], - ['nothing_changed.id1', 'nothing_changed.id2']) + ['nothing_changed.id1', 'nothing_changed.id2']), + mysql_engine='InnoDB' ) diffs = self._fixture(m1, m2) eq_(diffs, []) + + def test_nothing_changed_index_named_as_column(self): m1 = MetaData() m2 = MetaData() @@ -236,6 +243,36 @@ class AutogenerateUniqueIndexTest(AutogenFixtureTest, TestCase): diffs = self._fixture(m1, m2) eq_(diffs, []) + def test_nothing_changed_implicit_fk_index_named(self): + m1 = MetaData() + m2 = MetaData() + + Table("nothing_changed", m1, + Column('id', Integer, primary_key=True), + Column('other_id', + ForeignKey('nc2.id', + name='fk_my_table_other_table' + ), + nullable=False), + Column('foo', Integer), + mysql_engine='InnoDB') + Table('nc2', m1, + Column('id', Integer, primary_key=True), + mysql_engine='InnoDB') + + Table("nothing_changed", m2, + Column('id', Integer, primary_key=True), + Column('other_id', ForeignKey('nc2.id', + name='fk_my_table_other_table'), + nullable=False), + Column('foo', Integer), + mysql_engine='InnoDB') + Table('nc2', m2, + Column('id', Integer, primary_key=True), + mysql_engine='InnoDB') + diffs = self._fixture(m1, m2) + eq_(diffs, []) + def test_new_idx_index_named_as_column(self): m1 = MetaData() m2 = MetaData() @@ -472,8 +509,13 @@ class MySQLUniqueIndexTest(AutogenerateUniqueIndexTest): reports_unnamed_constraints = True def test_removed_idx_index_named_as_column(self): - # TODO: this should be an "assert fails" - pass + try: + super(MySQLUniqueIndexTest, + self).test_removed_idx_index_named_as_column() + except IndexError: + assert True + else: + assert False, "unexpected success" @classmethod def _get_bind(cls): -- 2.47.2