]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
- Fixed bug in batch where if the target table contained multiple
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 13 Dec 2014 19:02:14 +0000 (14:02 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 13 Dec 2014 19:02:14 +0000 (14:02 -0500)
foreign keys to the same target table, the batch mechanics would
fail with a "table already exists" error.  Thanks for the help
on this from Lucas Kahlert. fixes #254

alembic/batch.py
docs/build/changelog.rst
tests/test_batch.py

index f3ac7346ed35ee2e4aa67b32157094200570faef..e97f74e6723996f2c18517877d4469cfd2a3207e 100644 (file)
@@ -1,6 +1,7 @@
 from sqlalchemy import Table, MetaData, Index, select, Column, \
     ForeignKeyConstraint, cast
 from sqlalchemy import types as sqltypes
+from sqlalchemy import schema as sql_schema
 from sqlalchemy.util import OrderedDict
 from . import util
 from .ddl.base import _columns_for_constraint, _is_type_bound
@@ -174,12 +175,22 @@ class ApplyBatchImpl(object):
         else:
             referent_schema = None
         if tname != '_alembic_batch_temp':
-            Table(
-                tname, metadata,
-                *[Column(n, sqltypes.NULLTYPE) for n in
-                    [elem._get_colspec().split(".")[-1]
-                     for elem in constraint.elements]],
-                schema=referent_schema)
+            key = sql_schema._get_table_key(tname, referent_schema)
+            if key in metadata.tables:
+                t = metadata.tables[key]
+                for elem in constraint.elements:
+                    colname = elem._get_colspec().split(".")[-1]
+                    if not t.c.contains_column(colname):
+                        t.append_column(
+                            Column(colname, sqltypes.NULLTYPE)
+                        )
+            else:
+                Table(
+                    tname, metadata,
+                    *[Column(n, sqltypes.NULLTYPE) for n in
+                        [elem._get_colspec().split(".")[-1]
+                         for elem in constraint.elements]],
+                    schema=referent_schema)
 
     def _create(self, op_impl):
         self._transfer_elements_to_new_table()
index 145cab69ae735fa34fddd1c77e3364239429b072..44e2e07089516ebc68d168eb1460fbec5408dbd7 100644 (file)
@@ -6,6 +6,15 @@ Changelog
 .. changelog::
     :version: 0.7.2
 
+    .. change::
+      :tags: bug, batch
+      :tickets: 254
+
+      Fixed bug in batch where if the target table contained multiple
+      foreign keys to the same target table, the batch mechanics would
+      fail with a "table already exists" error.  Thanks for the help
+      on this from Lucas Kahlert.
+
     .. change::
       :tags: bug, mysql
       :tickets: 251
index 70dad5635947193a6bb73b46c7ddcd2b95698f21..279f9453f7d603b5a08ef46295685139e2b02445 100644 (file)
@@ -89,6 +89,22 @@ class BatchApplyTest(TestBase):
         )
         return ApplyBatchImpl(t, table_args, table_kwargs)
 
+    def _multi_fk_fixture(self, table_args=(), table_kwargs={}):
+        m = MetaData()
+        t = Table(
+            'tname', m,
+            Column('id', Integer, primary_key=True),
+            Column('email', String()),
+            Column('user_id_1', Integer, ForeignKey('user.id')),
+            Column('user_id_2', Integer, ForeignKey('user.id')),
+            Column('user_id_3', Integer),
+            Column('user_id_version', Integer),
+            ForeignKeyConstraint(
+                ['user_id_3', 'user_id_version'],
+                ['user.id', 'user.id_version'])
+        )
+        return ApplyBatchImpl(t, table_args, table_kwargs)
+
     def _named_fk_fixture(self, table_args=(), table_kwargs={}):
         m = MetaData()
         t = Table(
@@ -321,6 +337,15 @@ class BatchApplyTest(TestBase):
             "user.id"
         )
 
+    def test_regen_multi_fk(self):
+        impl = self._multi_fk_fixture()
+        self._assert_impl(
+            impl, colnames=[
+                'id', 'email', 'user_id_1', 'user_id_2',
+                'user_id_3', 'user_id_version'],
+            ddl_contains='FOREIGN KEY(user_id_3, user_id_version) '
+            'REFERENCES "user" (id, id_version)')
+
     def test_drop_col(self):
         impl = self._simple_fixture()
         impl.drop_column('tname', column('x'))