]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
- This releases' "autogenerate index detection" bug, when a MySQL table
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 2 May 2014 20:04:43 +0000 (16:04 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 2 May 2014 20:04:43 +0000 (16:04 -0400)
includes an Index with the same name as a column, autogenerate reported
it as an "add" even though its not; this is because we ignore reflected
indexes of this nature due to MySQL creating them implicitly.  Indexes
that are named the same as a column are now ignored on
MySQL if we see that the backend is reporting that it already exists;
this indicates that we can still detect additions of these indexes
but not drops, as we cannot distinguish a backend index same-named
as the column as one that is user generated or mysql-generated.
fixes #202

alembic/ddl/mysql.py
docs/build/changelog.rst
tests/test_autogen_indexes.py
tests/test_autogenerate.py

index 088ba59b47b4d1d024778fb42add21a3ce53c119..96f42f382d97e602f22fcb1113185859ced6fda1 100644 (file)
@@ -71,15 +71,24 @@ class MySQLImpl(DefaultImpl):
                 )
             )
 
-    def correct_for_autogen_constraints(self, conn_unique_constraints, conn_indexes,
+    def correct_for_autogen_constraints(self, conn_unique_constraints,
+                                        conn_indexes,
                                         metadata_unique_constraints,
                                         metadata_indexes):
+        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)
+
+        # then remove indexes from the "metadata_indexes"
+        # that we've removed from reflected, otherwise they come out
+        # as adds (see #202)
+        for idx in list(metadata_indexes):
+            if idx.name in removed:
+                metadata_indexes.remove(idx)
 
 class MySQLAlterDefault(AlterColumn):
     def __init__(self, name, column_name, default, schema=None):
index e312603edbfdee7fd07bcb148db2cc208a542e81..356c506f11236dce3d105822fa6899b17104904b 100644 (file)
@@ -5,6 +5,20 @@ Changelog
 .. changelog::
     :version: 0.6.5
 
+    .. change::
+      :tags: bug, autogenerate, mysql
+      :tickets: 202
+
+      This releases' "autogenerate index detection" bug, when a MySQL table
+      includes an Index with the same name as a column, autogenerate reported
+      it as an "add" even though its not; this is because we ignore reflected
+      indexes of this nature due to MySQL creating them implicitly.  Indexes
+      that are named the same as a column are now ignored on
+      MySQL if we see that the backend is reporting that it already exists;
+      this indicates that we can still detect additions of these indexes
+      but not drops, as we cannot distinguish a backend index same-named
+      as the column as one that is user generated or mysql-generated.
+
     .. change::
       :tags: feature, environment
       :tickets: 201
index 514367094e237714b92888f42cccd938dc66a54a..e9d932112d73d59a6e0541a38034806b5d3d9d90 100644 (file)
@@ -7,8 +7,7 @@ from sqlalchemy import MetaData, Column, Table, Integer, String, Text, \
     UniqueConstraint, Boolean, \
     PrimaryKeyConstraint, Index, func, ForeignKeyConstraint
 
-from . import staging_env, sqlite_db, clear_staging_env, eq_, \
-        eq_ignore_whitespace, db_for_dialect
+from . import sqlite_db, eq_, db_for_dialect
 
 py3k = sys.version_info >= (3, )
 
@@ -216,6 +215,68 @@ class AutogenerateUniqueIndexTest(AutogenFixtureTest, TestCase):
         diffs = self._fixture(m1, m2)
         eq_(diffs, [])
 
+    def test_nothing_changed_index_named_as_column(self):
+        m1 = MetaData()
+        m2 = MetaData()
+
+        Table('nothing_changed', m1,
+            Column('id1', Integer, primary_key=True),
+            Column('id2', Integer, primary_key=True),
+            Column('x', String(20)),
+            Index('x', 'x')
+            )
+
+        Table('nothing_changed', m2,
+            Column('id1', Integer, primary_key=True),
+            Column('id2', Integer, primary_key=True),
+            Column('x', String(20)),
+            Index('x', 'x')
+            )
+
+        diffs = self._fixture(m1, m2)
+        eq_(diffs, [])
+
+    def test_new_idx_index_named_as_column(self):
+        m1 = MetaData()
+        m2 = MetaData()
+
+        Table('new_idx', m1,
+            Column('id1', Integer, primary_key=True),
+            Column('id2', Integer, primary_key=True),
+            Column('x', String(20)),
+            )
+
+        idx = Index('x', 'x')
+        Table('new_idx', m2,
+            Column('id1', Integer, primary_key=True),
+            Column('id2', Integer, primary_key=True),
+            Column('x', String(20)),
+            idx
+            )
+
+        diffs = self._fixture(m1, m2)
+        eq_(diffs, [('add_index', idx)])
+
+    def test_removed_idx_index_named_as_column(self):
+        m1 = MetaData()
+        m2 = MetaData()
+
+        idx = Index('x', 'x')
+        Table('new_idx', m1,
+            Column('id1', Integer, primary_key=True),
+            Column('id2', Integer, primary_key=True),
+            Column('x', String(20)),
+            idx
+            )
+
+        Table('new_idx', m2,
+            Column('id1', Integer, primary_key=True),
+            Column('id2', Integer, primary_key=True),
+            Column('x', String(20))
+            )
+
+        diffs = self._fixture(m1, m2)
+        eq_(diffs[0][0], 'remove_index')
 
     def test_unnamed_cols_changed(self):
         m1 = MetaData()
@@ -410,6 +471,10 @@ class PGUniqueIndexTest(AutogenerateUniqueIndexTest):
 class MySQLUniqueIndexTest(AutogenerateUniqueIndexTest):
     reports_unnamed_constraints = True
 
+    def test_removed_idx_index_named_as_column(self):
+        # TODO: this should be an "assert fails"
+        pass
+
     @classmethod
     def _get_bind(cls):
         return db_for_dialect('mysql')
index a0f9216a8d77eea9824134adc2f9b047825e993d..932a656265456548f5ee015c4869c3968e893195 100644 (file)
@@ -114,7 +114,8 @@ class AutogenFixtureTest(object):
         self.bind = self._get_bind()
 
     def tearDown(self):
-        self.metadata.drop_all(self.bind)
+        if hasattr(self, 'metadata'):
+            self.metadata.drop_all(self.bind)
         clear_staging_env()
 
     @classmethod