]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
pass to_metadata argument to Enum.copy()
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 29 Aug 2024 14:04:47 +0000 (10:04 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 29 Aug 2024 15:49:50 +0000 (11:49 -0400)
Fixed bug where the ``metadata`` element of an ``Enum`` datatype would not
be transferred to the new :class:`.MetaData` object when the type had been
copied via a :meth:`.Table.to_metadata` operation, leading to inconsistent
behaviors within create/drop sequences.

Fixes: #11802
Change-Id: Ibbc93aa31bdfde0d67a9530f41a08e826c17d58e

doc/build/changelog/unreleased_20/11802.rst [new file with mode: 0644]
lib/sqlalchemy/sql/schema.py
lib/sqlalchemy/sql/sqltypes.py
test/sql/test_metadata.py

diff --git a/doc/build/changelog/unreleased_20/11802.rst b/doc/build/changelog/unreleased_20/11802.rst
new file mode 100644 (file)
index 0000000..f6e7847
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, schema
+    :tickets: 11802
+
+    Fixed bug where the ``metadata`` element of an ``Enum`` datatype would not
+    be transferred to the new :class:`.MetaData` object when the type had been
+    copied via a :meth:`.Table.to_metadata` operation, leading to inconsistent
+    behaviors within create/drop sequences.
index 1ecb680e446766fbd328b22c27fafb6ec202eb8f..21c44d8170adeaf97657c96b88e6fb3d3560ccd9 100644 (file)
@@ -1435,7 +1435,7 @@ class Table(
 
         args = []
         for col in self.columns:
-            args.append(col._copy(schema=actual_schema))
+            args.append(col._copy(schema=actual_schema, _to_metadata=metadata))
         table = Table(
             name,
             metadata,
@@ -2477,6 +2477,8 @@ class Column(DialectKWArgs, SchemaItem, ColumnClause[_T]):
         server_onupdate = self.server_onupdate
         if isinstance(server_default, (Computed, Identity)):
             # TODO: likely should be copied in all cases
+            # TODO: if a Sequence, we would need to transfer the Sequence
+            # .metadata as well
             args.append(server_default._copy(**kw))
             server_default = server_onupdate = None
 
index 0a411ce349d7c5068e094d6c1cba7336847d733c..145fce2fb40f6f46ec7db7365b9ed7048aa5d006 100644 (file)
@@ -1086,6 +1086,11 @@ class SchemaType(SchemaEventTarget, TypeEngineMixin):
         return self.adapt(
             cast("Type[TypeEngine[Any]]", self.__class__),
             _create_events=True,
+            metadata=(
+                kw.get("_to_metadata", self.metadata)
+                if self.metadata is not None
+                else None
+            ),
         )
 
     @overload
@@ -1909,6 +1914,13 @@ class Boolean(SchemaType, Emulated, TypeEngine[bool]):
         if _adapted_from:
             self.dispatch = self.dispatch._join(_adapted_from.dispatch)
 
+    def copy(self, **kw):
+        # override SchemaType.copy() to not include to_metadata logic
+        return self.adapt(
+            cast("Type[TypeEngine[Any]]", self.__class__),
+            _create_events=True,
+        )
+
     def _should_create_constraint(self, compiler, **kw):
         if not self._is_impl_for_variant(compiler.dialect, kw):
             return False
index 97c2f08645824f79be3bc82e36320a84b35285da..1b068c02f7f44b4cc04bc9ed12d83ca5167f77f9 100644 (file)
@@ -2395,17 +2395,27 @@ class SchemaTypeTest(fixtures.TestBase):
         t1 = Table("x", m, Column("y", type_), schema="z")
         eq_(t1.c.y.type.schema, "z")
 
-    def test_to_metadata_copy_type(self):
+    @testing.variation("assign_metadata", [True, False])
+    def test_to_metadata_copy_type(self, assign_metadata):
         m1 = MetaData()
 
-        type_ = self.MyType()
+        if assign_metadata:
+            type_ = self.MyType(metadata=m1)
+        else:
+            type_ = self.MyType()
+
         t1 = Table("x", m1, Column("y", type_))
 
         m2 = MetaData()
         t2 = t1.to_metadata(m2)
 
-        # metadata isn't set
-        is_(t2.c.y.type.metadata, None)
+        if assign_metadata:
+            # metadata was transferred
+            # issue #11802
+            is_(t2.c.y.type.metadata, m2)
+        else:
+            # metadata isn't set
+            is_(t2.c.y.type.metadata, None)
 
         # our test type sets table, though
         is_(t2.c.y.type.table, t2)
@@ -2435,11 +2445,34 @@ class SchemaTypeTest(fixtures.TestBase):
 
         eq_(t2.c.y.type.schema, None)
 
-    def test_to_metadata_inherit_schema(self):
+    @testing.combinations(
+        ("name", "foobar", "name"),
+        ("schema", "someschema", "schema"),
+        ("inherit_schema", True, "inherit_schema"),
+        ("metadata", MetaData(), "metadata"),
+    )
+    def test_copy_args(self, argname, value, attrname):
+        kw = {argname: value}
+        e1 = self.MyType(**kw)
+
+        e1_copy = e1.copy()
+
+        eq_(getattr(e1_copy, attrname), value)
+
+    @testing.variation("already_has_a_schema", [True, False])
+    def test_to_metadata_inherit_schema(self, already_has_a_schema):
         m1 = MetaData()
 
-        type_ = self.MyType(inherit_schema=True)
+        if already_has_a_schema:
+            type_ = self.MyType(schema="foo", inherit_schema=True)
+            eq_(type_.schema, "foo")
+        else:
+            type_ = self.MyType(inherit_schema=True)
+
         t1 = Table("x", m1, Column("y", type_))
+        # note that inherit_schema means the schema mutates to be that
+        # of the table
+        is_(type_.schema, None)
 
         m2 = MetaData()
         t2 = t1.to_metadata(m2, schema="bar")