]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
allow control of constraint isolation w/ add/drop constraint
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 27 Feb 2025 17:04:12 +0000 (12:04 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 27 Feb 2025 19:48:03 +0000 (14:48 -0500)
Added new parameters :paramref:`.AddConstraint.isolate_from_table` and
:paramref:`.DropConstraint.isolate_from_table`, defaulting to True, which
both document and allow to be controllable the long-standing behavior of
these two constructs blocking the given constraint from being included
inline within the "CREATE TABLE" sequence, under the assumption that
separate add/drop directives were to be used.

Fixes: #12382
Change-Id: I53c4170ccb5803f69945ba7aa3d3a143131508eb

doc/build/changelog/unreleased_20/12382.rst [new file with mode: 0644]
lib/sqlalchemy/sql/ddl.py
test/sql/test_constraints.py

diff --git a/doc/build/changelog/unreleased_20/12382.rst b/doc/build/changelog/unreleased_20/12382.rst
new file mode 100644 (file)
index 0000000..80f4630
--- /dev/null
@@ -0,0 +1,10 @@
+.. change::
+    :tags: bug, sql
+    :tickets: 12382
+
+    Added new parameters :paramref:`.AddConstraint.isolate_from_table` and
+    :paramref:`.DropConstraint.isolate_from_table`, defaulting to True, which
+    both document and allow to be controllable the long-standing behavior of
+    these two constructs blocking the given constraint from being included
+    inline within the "CREATE TABLE" sequence, under the assumption that
+    separate add/drop directives were to be used.
index 7210d930a188dd545673afda6212f1029d2b1a47..4e1973ea02455a5a9b8ffb6245f0570c1ceb9ae6 100644 (file)
@@ -751,11 +751,33 @@ class AddConstraint(_CreateBase):
 
     __visit_name__ = "add_constraint"
 
-    def __init__(self, element):
+    def __init__(
+        self,
+        element: Constraint,
+        *,
+        isolate_from_table: bool = True,
+    ):
+        """Construct a new :class:`.AddConstraint` construct.
+
+        :param element: a :class:`.Constraint` object
+
+        :param isolate_from_table: optional boolean, defaults to True.  Has
+         the effect of the incoming constraint being isolated from being
+         included in a CREATE TABLE sequence when associated with a
+         :class:`.Table`.
+
+         .. versionadded:: 2.0.39 - added
+            :paramref:`.AddConstraint.isolate_from_table`, defaulting
+            to True.  Previously, the behavior of this parameter was implicitly
+            turned on in all cases.
+
+        """
         super().__init__(element)
-        element._create_rule = util.portable_instancemethod(
-            self._create_rule_disable
-        )
+
+        if isolate_from_table:
+            element._create_rule = util.portable_instancemethod(
+                self._create_rule_disable
+            )
 
 
 class DropConstraint(_DropBase):
@@ -763,12 +785,40 @@ class DropConstraint(_DropBase):
 
     __visit_name__ = "drop_constraint"
 
-    def __init__(self, element, cascade=False, if_exists=False, **kw):
+    def __init__(
+        self,
+        element: Constraint,
+        *,
+        cascade: bool = False,
+        if_exists: bool = False,
+        isolate_from_table: bool = True,
+        **kw: Any,
+    ):
+        """Construct a new :class:`.DropConstraint` construct.
+
+        :param element: a :class:`.Constraint` object
+        :param cascade: optional boolean, indicates backend-specific
+         "CASCADE CONSTRAINT" directive should be rendered if available
+        :param if_exists: optional boolean, indicates backend-specific
+         "IF EXISTS" directive should be rendered if available
+        :param isolate_from_table: optional boolean, defaults to True.  Has
+         the effect of the incoming constraint being isolated from being
+         included in a CREATE TABLE sequence when associated with a
+         :class:`.Table`.
+
+         .. versionadded:: 2.0.39 - added
+            :paramref:`.DropConstraint.isolate_from_table`, defaulting
+            to True.  Previously, the behavior of this parameter was implicitly
+            turned on in all cases.
+
+        """
         self.cascade = cascade
         super().__init__(element, if_exists=if_exists, **kw)
-        element._create_rule = util.portable_instancemethod(
-            self._create_rule_disable
-        )
+
+        if isolate_from_table:
+            element._create_rule = util.portable_instancemethod(
+                self._create_rule_disable
+            )
 
 
 class SetTableComment(_CreateDropBase):
index 93c385ba4d75d92415fb70b5cc9e7fe5dfdef19d..ebd44cdcb576daadd2580f8a12c20365c0c644ad 100644 (file)
@@ -1219,7 +1219,11 @@ class ConstraintCompilationTest(fixtures.TestBase, AssertsCompiledSQL):
             "CHECK (a < b) DEFERRABLE INITIALLY DEFERRED",
         )
 
-    def test_external_ck_constraint_cancels_internal(self):
+    @testing.variation("isolate", [True, False])
+    @testing.variation("type_", ["add", "drop"])
+    def test_external_ck_constraint_cancels_internal(
+        self, isolate: testing.Variation, type_: testing.Variation
+    ):
         t, t2 = self._constraint_create_fixture()
 
         constraint = CheckConstraint(
@@ -1230,15 +1234,27 @@ class ConstraintCompilationTest(fixtures.TestBase, AssertsCompiledSQL):
             table=t,
         )
 
-        schema.AddConstraint(constraint)
-
-        # once we make an AddConstraint,
-        # inline compilation of the CONSTRAINT
-        # is disabled
-        self.assert_compile(
-            schema.CreateTable(t),
-            "CREATE TABLE tbl (a INTEGER, b INTEGER)",
-        )
+        if type_.add:
+            cls = schema.AddConstraint
+        elif type_.drop:
+            cls = schema.DropConstraint
+        else:
+            type_.fail()
+
+        if not isolate:
+            cls(constraint, isolate_from_table=False)
+            self.assert_compile(
+                schema.CreateTable(t),
+                "CREATE TABLE tbl (a INTEGER, b INTEGER, "
+                "CONSTRAINT my_test_constraint CHECK (a < b) "
+                "DEFERRABLE INITIALLY DEFERRED)",
+            )
+        else:
+            cls(constraint)
+            self.assert_compile(
+                schema.CreateTable(t),
+                "CREATE TABLE tbl (a INTEGER, b INTEGER)",
+            )
 
     def test_render_drop_constraint(self):
         t, t2 = self._constraint_create_fixture()