From: Mike Bayer Date: Wed, 15 Mar 2017 21:10:28 +0000 (-0400) Subject: Apply DDLCompiler name rules to Index for autogenerate X-Git-Tag: rel_0_9_2~3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4cdb25bf5d70e6e8a789c75c59a2a908433674ce;p=thirdparty%2Fsqlalchemy%2Falembic.git Apply DDLCompiler name rules to Index for autogenerate 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 --- diff --git a/alembic/autogenerate/compare.py b/alembic/autogenerate/compare.py index 0d4f4d27..f393c40b 100644 --- a/alembic/autogenerate/compare.py +++ b/alembic/autogenerate/compare.py @@ -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) diff --git a/alembic/util/sqla_compat.py b/alembic/util/sqla_compat.py index 2d56d3ea..28a6548c 100644 --- a/alembic/util/sqla_compat.py +++ b/alembic/util/sqla_compat.py @@ -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 diff --git a/docs/build/changelog.rst b/docs/build/changelog.rst index 32a9a2c5..78358837 100644 --- a/docs/build/changelog.rst +++ b/docs/build/changelog.rst @@ -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 diff --git a/tests/test_autogen_indexes.py b/tests/test_autogen_indexes.py index bec90a7d..85e0731b 100644 --- a/tests/test_autogen_indexes.py +++ b/tests/test_autogen_indexes.py @@ -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, [])