From: Mike Bayer Date: Fri, 15 Jun 2018 02:56:21 +0000 (-0400) Subject: Lookup index columns in parent table by key for copy X-Git-Tag: rel_1_3_0b1~166 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8f7766cc61479f3c9220c640230eeecd3d49ccc8;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Lookup index columns in parent table by key for copy Fixed regression in 1.2 due to :ticket:`4147` where a :class:`.Table` that has had some of its indexed columns redefined with new ones, as would occur when overriding columns during reflection or when using :paramref:`.Table.extend_existing`, such that the :meth:`.Table.tometadata` method would fail when attempting to copy those indexes as they still referred to the replaced column. The copy logic now accommodates for this condition. Change-Id: I521aa2c9f3baa0e84598bbdd6ffe4bf07b6e3ba8 Fixes: #4279 --- diff --git a/doc/build/changelog/unreleased_12/4279.rst b/doc/build/changelog/unreleased_12/4279.rst new file mode 100644 index 0000000000..f7cedbf394 --- /dev/null +++ b/doc/build/changelog/unreleased_12/4279.rst @@ -0,0 +1,12 @@ +.. change:: + :tags: bug, sql + :tickets: 4279 + + Fixed regression in 1.2 due to :ticket:`4147` where a :class:`.Table` that + has had some of its indexed columns redefined with new ones, as would occur + when overriding columns during reflection or when using + :paramref:`.Table.extend_existing`, such that the :meth:`.Table.tometadata` + method would fail when attempting to copy those indexes as they still + referred to the replaced column. The copy logic now accommodates for this + condition. + diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 1d6bc4c61f..88050b87e3 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -69,7 +69,8 @@ def _get_table_key(name, schema): # break an import cycle def _copy_expression(expression, source_table, target_table): def replace(col): - if source_table.c.contains_column(col): + if isinstance(col, Column) and \ + col.table is source_table and col.key in source_table.c: return target_table.c[col.key] else: return None diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index 7d17e25f34..da133b21ab 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -1066,6 +1066,38 @@ class ToMetaDataTest(fixtures.TestBase, ComparesTables): sorted([_get_key(i) for i in table_c.indexes]) ) + def test_indexes_with_col_redefine(self): + meta = MetaData() + + table = Table('mytable', meta, + Column('id', Integer, primary_key=True), + Column('data1', Integer), + Column('data2', Integer), + Index('text', text('data1 + 1')), + ) + Index('multi', table.c.data1, table.c.data2) + Index('func', func.abs(table.c.data1)) + Index('multi-func', table.c.data1, func.abs(table.c.data2)) + + table = Table('mytable', meta, + Column('data1', Integer), + Column('data2', Integer), + extend_existing=True + ) + + meta2 = MetaData() + table_c = table.tometadata(meta2) + + def _get_key(i): + return [i.name, i.unique] + \ + sorted(i.kwargs.items()) + \ + [str(col) for col in i.expressions] + + eq_( + sorted([_get_key(i) for i in table.indexes]), + sorted([_get_key(i) for i in table_c.indexes]) + ) + @emits_warning("Table '.+' already exists within the given MetaData") def test_already_exists(self):