]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Apply DDLCompiler name rules to Index for autogenerate
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 15 Mar 2017 21:10:28 +0000 (17:10 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 15 Mar 2017 21:36:01 +0000 (17:36 -0400)
The autogenerate compare scheme now takes into account the name truncation
rules applied by SQLAlchemy's DDL compiler to the names of the
:class:`.Index` object, when these names are dynamically truncated
due to a too-long identifier name.   As the identifier truncation is
deterministic, applying the same rule to the metadata name allows
correct comparison to the database-derived name.

Change-Id: I270fbde4430a41f4bcc7857f1932347d86f07675
Fixes: #421
alembic/autogenerate/compare.py
alembic/util/sqla_compat.py
docs/build/changelog.rst
tests/test_autogen_indexes.py

index 0d4f4d27a7e96a9e51a50b5ac793bf6db2ab3397..f393c40b964f441eda5a1808a4b13c39ec173f8d 100644 (file)
@@ -277,6 +277,9 @@ def _compare_columns(schema, tname, conn_table, metadata_table,
 
 class _constraint_sig(object):
 
+    def md_name_to_sql_name(self, context):
+        return self.name
+
     def __eq__(self, other):
         return self.const == other.const
 
@@ -310,6 +313,9 @@ class _ix_constraint_sig(_constraint_sig):
         self.sig = tuple(sorted([col.name for col in const.columns]))
         self.is_unique = bool(const.unique)
 
+    def md_name_to_sql_name(self, context):
+        return sqla_compat._get_index_final_name(context.dialect, self.const)
+
     @property
     def column_names(self):
         return sqla_compat._get_index_column_names(self.const)
@@ -433,7 +439,7 @@ def _compare_indexes_and_uniques(
 
     # 5. index things by name, for those objects that have names
     metadata_names = dict(
-        (c.name, c) for c in
+        (c.md_name_to_sql_name(autogen_context), c) for c in
         metadata_unique_constraints.union(metadata_indexes)
         if c.name is not None)
 
index 2d56d3ea2529dfa9378627898349ed373ca79386..28a6548c4680d20233e8a89beb4e37ee6a68fbcf 100644 (file)
@@ -171,3 +171,10 @@ def _get_index_expressions(idx):
 
 def _get_index_column_names(idx):
     return [getattr(exp, "name", None) for exp in _get_index_expressions(idx)]
+
+
+def _get_index_final_name(dialect, idx):
+    if sqla_08:
+        return dialect.ddl_compiler(dialect, None)._prepared_index_name(idx)
+    else:
+        return idx.name
index 32a9a2c5d43e3eb35ae1b3e45a71ecec33a98722..78358837daa1c4d06134f0868936468a74a87e78 100644 (file)
@@ -7,6 +7,17 @@ Changelog
     :version: 0.9.2
     :released:
 
+    .. change:: 421
+      :tags: bug, autogenerate
+      :tickets: 421
+
+      The autogenerate compare scheme now takes into account the name truncation
+      rules applied by SQLAlchemy's DDL compiler to the names of the
+      :class:`.Index` object, when these names are dynamically truncated
+      due to a too-long identifier name.   As the identifier truncation is
+      deterministic, applying the same rule to the metadata name allows
+      correct comparison to the database-derived name.
+
     .. change:: 419
       :tags: bug environment
       :tickets: 419
index bec90a7d4cd2846bd35b750e9b2db1c696afc507..85e0731ba26060b19e5c12cd23954549f2192685 100644 (file)
@@ -979,3 +979,27 @@ class IncludeHooksTest(AutogenFixtureTest, TestBase):
         eq_(diffs[1][0], 'add_constraint')
         eq_(diffs[1][1].name, 'uq2')
         eq_(len(diffs), 2)
+
+
+class TruncatedIdxTest(AutogenFixtureTest, TestBase):
+    __requires__ = ('sqlalchemy_09', )
+
+    def setUp(self):
+        self.bind = engines.testing_engine()
+        self.bind.dialect.max_identifier_length = 30
+
+    def test_idx_matches_long(self):
+        from alembic.operations.base import conv
+
+        m1 = MetaData()
+        Table(
+            'q', m1,
+            Column('id', Integer, primary_key=True),
+            Column('data', Integer),
+            Index(
+                conv("idx_q_table_this_is_more_than_thirty_characters"),
+                "data")
+        )
+
+        diffs = self._fixture(m1, m1)
+        eq_(diffs, [])