]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
Consult ApplyBatchImpl for hints on constraints to drop
authorMike Bayer <mike_mp@zzzcomputing.com>
Sun, 27 Dec 2020 21:40:48 +0000 (16:40 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 29 Dec 2020 01:31:02 +0000 (20:31 -0500)
Made an adjustment to the PostgreSQL dialect to allow it to work more
effectively in batch mode, where a datatype like Boolean or non-native Enum
that may have embedded rules to generate CHECK constraints will be more
correctly handled in that these constraints usually will not have been
generated on the PostgreSQL backend; previously it would inadvertently
assume they existed unconditionally in a special PG-only "drop constraint"
step.

Change-Id: I024b07bee6eec92061d902cbe1b086cb5b3ecd7c
Fixes: #773
alembic/ddl/impl.py
alembic/ddl/postgresql.py
alembic/operations/batch.py
docs/build/unreleased/773.rst [new file with mode: 0644]
tests/test_batch.py

index 08d980b7f00eecc362a218ec1e941dcc7ff0438b..3674c67dea28cb9e360d2d6b0efe04157f5fe99f 100644 (file)
@@ -94,7 +94,7 @@ class DefaultImpl(with_metaclass(ImplMeta)):
         """
         return False
 
-    def prep_table_for_batch(self, table):
+    def prep_table_for_batch(self, batch_impl, table):
         """perform any operations needed on a table before a new
         one is created to replace it in batch mode.
 
index 5fd6c91981d2a70efe6166f35a2201a251e3c93e..beb70fa5fac6b427ddfdf7ffcbfafbf413184992 100644 (file)
@@ -44,9 +44,13 @@ class PostgresqlImpl(DefaultImpl):
     )
     identity_attrs_ignore = ("on_null", "order")
 
-    def prep_table_for_batch(self, table):
+    def prep_table_for_batch(self, batch_impl, table):
+
         for constraint in table.constraints:
-            if constraint.name is not None:
+            if (
+                constraint.name is not None
+                and constraint.name in batch_impl.named_constraints
+            ):
                 self.drop_constraint(constraint)
 
     def compare_server_default(
index a5b31c9a090742a485e13202a6f57e9a97bd0e9a..81e3b99585c18a7e61dadc5606e007495093ca00 100644 (file)
@@ -357,7 +357,7 @@ class ApplyBatchImpl(object):
     def _create(self, op_impl):
         self._transfer_elements_to_new_table()
 
-        op_impl.prep_table_for_batch(self.table)
+        op_impl.prep_table_for_batch(self, self.table)
         op_impl.create_table(self.new_table)
 
         try:
diff --git a/docs/build/unreleased/773.rst b/docs/build/unreleased/773.rst
new file mode 100644 (file)
index 0000000..b0cfd45
--- /dev/null
@@ -0,0 +1,12 @@
+.. change::
+    :tags: bug, batch
+    :tickets: 773
+
+    Made an adjustment to the PostgreSQL dialect to allow it to work more
+    effectively in batch mode, where a datatype like Boolean or non-native Enum
+    that may have embedded rules to generate CHECK constraints will be more
+    correctly handled in that these constraints usually will not have been
+    generated on the PostgreSQL backend; previously it would inadvertently
+    assume they existed unconditionally in a special PG-only "drop constraint"
+    step.
+
index bc32684b2481c435756729dde096d37cab2c930d..c9785f28473f0faa8cc0e3496d5cad5e71bbaa44 100644 (file)
@@ -2030,6 +2030,20 @@ class BatchRoundTripPostgresqlTest(BatchRoundTripTest):
     __only_on__ = "postgresql"
     __backend__ = True
 
+    def _native_boolean_fixture(self):
+        t = Table(
+            "has_native_bool",
+            self.metadata,
+            Column(
+                "x",
+                Boolean(create_constraint=True),
+                server_default="false",
+                nullable=False,
+            ),
+            Column("y", Integer),
+        )
+        t.create(self.conn)
+
     def _datetime_server_default_fixture(self):
         return func.current_timestamp()
 
@@ -2063,3 +2077,42 @@ class BatchRoundTripPostgresqlTest(BatchRoundTripTest):
         super(
             BatchRoundTripPostgresqlTest, self
         ).test_change_type_boolean_to_int()
+
+    def test_add_col_table_has_native_boolean(self):
+        self._native_boolean_fixture()
+
+        # to ensure test coverage on SQLAlchemy 1.4 and above,
+        # force the create_constraint flag to True even though it
+        # defaults to false in 1.4.  this test wants to ensure that the
+        # "should create" rule is consulted
+        def listen_for_reflect(inspector, table, column_info):
+            if isinstance(column_info["type"], Boolean):
+                column_info["type"].create_constraint = True
+
+        with self.op.batch_alter_table(
+            "has_native_bool",
+            recreate="always",
+            reflect_kwargs={
+                "listeners": [("column_reflect", listen_for_reflect)]
+            },
+        ) as batch_op:
+            batch_op.add_column(Column("data", Integer))
+
+        insp = inspect(config.db)
+
+        eq_(
+            [
+                c["type"]._type_affinity
+                for c in insp.get_columns("has_native_bool")
+                if c["name"] == "data"
+            ],
+            [Integer],
+        )
+        eq_(
+            [
+                c["type"]._type_affinity
+                for c in insp.get_columns("has_native_bool")
+                if c["name"] == "x"
+            ],
+            [Boolean],
+        )