]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Append table name to batch temp name
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 11 Oct 2017 14:08:19 +0000 (10:08 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 11 Oct 2017 14:08:19 +0000 (10:08 -0400)
The name of the temporary table in batch mode is now generated
off of the original table name itself, to avoid conflicts for the
unusual case of multiple batch operations running against the same
database schema at the same time.

Change-Id: Idbeabf9558887d3f5525e7045d5de33bab6805a5
Fixes: #457
alembic/operations/batch.py
docs/build/unreleased/457.rst [new file with mode: 0644]
tests/test_batch.py

index fa7899e026c6d24436fa7e1956662f09aef1342b..84d29d9539e394f9ad2bc33f2e585501ffbfb45a 100644 (file)
@@ -117,6 +117,7 @@ class ApplyBatchImpl(object):
         self.table = table  # this is a Table object
         self.table_args = table_args
         self.table_kwargs = table_kwargs
+        self.temp_table_name = self._calc_temp_name(table.name)
         self.new_table = None
         self.column_transfers = OrderedDict(
             (c.name, {'expr': c}) for c in self.table.c
@@ -124,6 +125,10 @@ class ApplyBatchImpl(object):
         self.reflected = reflected
         self._grab_table_elements()
 
+    @classmethod
+    def _calc_temp_name(cls, tablename):
+        return ("_alembic_tmp_%s" % tablename)[0:50]
+
     def _grab_table_elements(self):
         schema = self.table.schema
         self.columns = OrderedDict()
@@ -164,7 +169,7 @@ class ApplyBatchImpl(object):
         schema = self.table.schema
 
         self.new_table = new_table = Table(
-            '_alembic_batch_temp', m,
+            self.temp_table_name, m,
             *(list(self.columns.values()) + list(self.table_args)),
             schema=schema,
             **self.table_kwargs)
@@ -221,7 +226,7 @@ class ApplyBatchImpl(object):
         else:
             referent_schema = None
 
-        if tname != '_alembic_batch_temp':
+        if tname != self.temp_table_name:
             key = sql_schema._get_table_key(tname, referent_schema)
             if key in metadata.tables:
                 t = metadata.tables[key]
@@ -263,7 +268,7 @@ class ApplyBatchImpl(object):
             raise
         else:
             op_impl.rename_table(
-                "_alembic_batch_temp",
+                self.temp_table_name,
                 self.table.name,
                 schema=self.table.schema
             )
@@ -272,7 +277,7 @@ class ApplyBatchImpl(object):
                 for idx in self._gather_indexes_from_both_tables():
                     op_impl.create_index(idx)
             finally:
-                self.new_table.name = "_alembic_batch_temp"
+                self.new_table.name = self.temp_table_name
 
     def alter_column(self, table_name, column_name,
                      nullable=None,
diff --git a/docs/build/unreleased/457.rst b/docs/build/unreleased/457.rst
new file mode 100644 (file)
index 0000000..92f88af
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, batch
+    :tickets: 457
+
+    The name of the temporary table in batch mode is now generated
+    off of the original table name itself, to avoid conflicts for the
+    unusual case of multiple batch operations running against the same
+    database schema at the same time.
\ No newline at end of file
index afffa356aff23a0f9bba5cf71b35f8b475fc585f..03be9f98a4f48110567121388c8b17c674bfd087 100644 (file)
@@ -205,7 +205,8 @@ class BatchApplyTest(TestBase):
         for idx in impl.new_indexes.values():
             impl.new_table.name = impl.table.name
             idx_stmt += str(CreateIndex(idx).compile(dialect=context.dialect))
-            impl.new_table.name = '_alembic_batch_temp'
+            impl.new_table.name = ApplyBatchImpl._calc_temp_name(
+                impl.table.name)
         idx_stmt = re.sub(r'[\n\t]', '', idx_stmt)
 
         if ddl_contains:
@@ -222,6 +223,8 @@ class BatchApplyTest(TestBase):
         else:
             args = {"schema": ""}
 
+        args["temp_name"] = impl.new_table.name
+
         args['colnames'] = ", ".join([
             impl.new_table.c[name].name
             for name in colnames
@@ -242,10 +245,10 @@ class BatchApplyTest(TestBase):
         )
 
         expected.extend([
-            'INSERT INTO %(schema)s_alembic_batch_temp (%(colnames)s) '
+            'INSERT INTO %(schema)s%(temp_name)s (%(colnames)s) '
             'SELECT %(tname_colnames)s FROM %(schema)stname' % args,
             'DROP TABLE %(schema)stname' % args,
-            'ALTER TABLE %(schema)s_alembic_batch_temp '
+            'ALTER TABLE %(schema)s%(temp_name)s '
             'RENAME TO %(schema)stname' % args
         ])
         if idx_stmt:
@@ -772,12 +775,12 @@ class CopyFromTest(TestBase):
                 "foo", copy_from=self.table) as batch_op:
             batch_op.alter_column('data', type_=Integer)
         context.assert_(
-            'CREATE TABLE _alembic_batch_temp (id INTEGER NOT NULL, '
+            'CREATE TABLE _alembic_tmp_foo (id INTEGER NOT NULL, '
             'data INTEGER, x INTEGER, PRIMARY KEY (id))',
-            'INSERT INTO _alembic_batch_temp (id, data, x) SELECT foo.id, '
+            'INSERT INTO _alembic_tmp_foo (id, data, x) SELECT foo.id, '
             'CAST(foo.data AS INTEGER) AS anon_1, foo.x FROM foo',
             'DROP TABLE foo',
-            'ALTER TABLE _alembic_batch_temp RENAME TO foo'
+            'ALTER TABLE _alembic_tmp_foo RENAME TO foo'
         )
 
     def test_change_type_from_schematype(self):
@@ -793,12 +796,12 @@ class CopyFromTest(TestBase):
                 existing_type=Boolean(
                     create_constraint=True, name="ck1"))
         context.assert_(
-            'CREATE TABLE _alembic_batch_temp (id INTEGER NOT NULL, '
+            'CREATE TABLE _alembic_tmp_foo (id INTEGER NOT NULL, '
             'data VARCHAR(50), x INTEGER, y INTEGER, PRIMARY KEY (id))',
-            'INSERT INTO _alembic_batch_temp (id, data, x, y) SELECT foo.id, '
+            'INSERT INTO _alembic_tmp_foo (id, data, x, y) SELECT foo.id, '
             'foo.data, foo.x, CAST(foo.y AS INTEGER) AS anon_1 FROM foo',
             'DROP TABLE foo',
-            'ALTER TABLE _alembic_batch_temp RENAME TO foo'
+            'ALTER TABLE _alembic_tmp_foo RENAME TO foo'
         )
 
     def test_change_type_to_schematype(self):
@@ -813,13 +816,13 @@ class CopyFromTest(TestBase):
                 type_=Boolean(
                     create_constraint=True, name="ck1"))
         context.assert_(
-            'CREATE TABLE _alembic_batch_temp (id INTEGER NOT NULL, '
+            'CREATE TABLE _alembic_tmp_foo (id INTEGER NOT NULL, '
             'data VARCHAR(50), x INTEGER, y BOOLEAN, PRIMARY KEY (id), '
             'CONSTRAINT ck1 CHECK (y IN (0, 1)))',
-            'INSERT INTO _alembic_batch_temp (id, data, x, y) SELECT foo.id, '
+            'INSERT INTO _alembic_tmp_foo (id, data, x, y) SELECT foo.id, '
             'foo.data, foo.x, CAST(foo.y AS BOOLEAN) AS anon_1 FROM foo',
             'DROP TABLE foo',
-            'ALTER TABLE _alembic_batch_temp RENAME TO foo'
+            'ALTER TABLE _alembic_tmp_foo RENAME TO foo'
         )
 
     def test_create_drop_index_w_always(self):
@@ -830,13 +833,13 @@ class CopyFromTest(TestBase):
                 'ix_data', ['data'], unique=True)
 
         context.assert_(
-            'CREATE TABLE _alembic_batch_temp (id INTEGER NOT NULL, '
+            'CREATE TABLE _alembic_tmp_foo (id INTEGER NOT NULL, '
             'data VARCHAR(50), '
             'x INTEGER, PRIMARY KEY (id))',
-            'INSERT INTO _alembic_batch_temp (id, data, x) '
+            'INSERT INTO _alembic_tmp_foo (id, data, x) '
             'SELECT foo.id, foo.data, foo.x FROM foo',
             'DROP TABLE foo',
-            'ALTER TABLE _alembic_batch_temp RENAME TO foo',
+            'ALTER TABLE _alembic_tmp_foo RENAME TO foo',
             'CREATE UNIQUE INDEX ix_data ON foo (data)',
         )
 
@@ -848,12 +851,12 @@ class CopyFromTest(TestBase):
             batch_op.drop_index('ix_data')
 
         context.assert_(
-            'CREATE TABLE _alembic_batch_temp (id INTEGER NOT NULL, '
+            'CREATE TABLE _alembic_tmp_foo (id INTEGER NOT NULL, '
             'data VARCHAR(50), x INTEGER, PRIMARY KEY (id))',
-            'INSERT INTO _alembic_batch_temp (id, data, x) '
+            'INSERT INTO _alembic_tmp_foo (id, data, x) '
             'SELECT foo.id, foo.data, foo.x FROM foo',
             'DROP TABLE foo',
-            'ALTER TABLE _alembic_batch_temp RENAME TO foo'
+            'ALTER TABLE _alembic_tmp_foo RENAME TO foo'
         )
 
     def test_create_drop_index_wo_always(self):
@@ -887,12 +890,12 @@ class CopyFromTest(TestBase):
                 'ix_data', ['data'], unique=True)
 
         context.assert_(
-            'CREATE TABLE _alembic_batch_temp (id INTEGER NOT NULL, '
+            'CREATE TABLE _alembic_tmp_foo (id INTEGER NOT NULL, '
             'data INTEGER, x INTEGER, PRIMARY KEY (id))',
-            'INSERT INTO _alembic_batch_temp (id, data, x) SELECT foo.id, '
+            'INSERT INTO _alembic_tmp_foo (id, data, x) SELECT foo.id, '
             'CAST(foo.data AS INTEGER) AS anon_1, foo.x FROM foo',
             'DROP TABLE foo',
-            'ALTER TABLE _alembic_batch_temp RENAME TO foo',
+            'ALTER TABLE _alembic_tmp_foo RENAME TO foo',
             'CREATE UNIQUE INDEX ix_data ON foo (data)',
         )
 
@@ -905,12 +908,12 @@ class CopyFromTest(TestBase):
             batch_op.alter_column('data', type_=String)
 
         context.assert_(
-            'CREATE TABLE _alembic_batch_temp (id INTEGER NOT NULL, '
+            'CREATE TABLE _alembic_tmp_foo (id INTEGER NOT NULL, '
             'data VARCHAR, x INTEGER, PRIMARY KEY (id))',
-            'INSERT INTO _alembic_batch_temp (id, data, x) SELECT foo.id, '
+            'INSERT INTO _alembic_tmp_foo (id, data, x) SELECT foo.id, '
             'foo.data, foo.x FROM foo',
             'DROP TABLE foo',
-            'ALTER TABLE _alembic_batch_temp RENAME TO foo'
+            'ALTER TABLE _alembic_tmp_foo RENAME TO foo'
         )
 
 
@@ -1104,7 +1107,7 @@ class BatchRoundTripTest(TestBase):
 
     # in particular, this tests that the failures
     # on PG and MySQL result in recovery of the batch system,
-    # e.g. that the _alembic_batch_temp table is dropped
+    # e.g. that the _alembic_tmp_temp table is dropped
     @config.requirements.no_referential_integrity
     def test_fk_points_to_me_recreate(self):
         self._test_fk_points_to_me("always")