]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
support BLANK_SCHEMA, RETAIN_SCHEMA FK schema on copy
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 26 Mar 2022 14:09:10 +0000 (10:09 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 26 Mar 2022 14:11:31 +0000 (10:11 -0400)
Added support so that the :paramref:`.Table.tometadata.referred_schema_fn`
callable passed to :meth:`.Table.to_metadata` may return the value
:data:`.BLANK_SCHEMA` to indicate that the referenced foreign key should be
reset to None. The :data.`RETAIN_SCHEMA` symbol may also be returned from
this function to indicate "no change", which will behave the same as
``None`` currently does which also indicates no change.

Fixes: #7860
Change-Id: I82a45988d534295d8356453f68001b21d4ff706d

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

diff --git a/doc/build/changelog/unreleased_14/7860.rst b/doc/build/changelog/unreleased_14/7860.rst
new file mode 100644 (file)
index 0000000..cb6bcc5
--- /dev/null
@@ -0,0 +1,11 @@
+.. change::
+    :tags: usecase, schema
+    :tickets: 7860
+
+    Added support so that the :paramref:`.Table.tometadata.referred_schema_fn`
+    callable passed to :meth:`.Table.to_metadata` may return the value
+    :data:`.BLANK_SCHEMA` to indicate that the referenced foreign key should be
+    reset to None. The :data.`RETAIN_SCHEMA` symbol may also be returned from
+    this function to indicate "no change", which will behave the same as
+    ``None`` currently does which also indicates no change.
+
index dfe82432d77e6f6c240ca39add985e841b18210c..9924e632bf8a49d4ee1616517b3d089a4d0b1b58 100644 (file)
@@ -91,7 +91,8 @@ RETAIN_SCHEMA = util.symbol("retain_schema")
 
 BLANK_SCHEMA = util.symbol(
     "blank_schema",
-    """Symbol indicating that a :class:`_schema.Table` or :class:`.Sequence`
+    """Symbol indicating that a :class:`_schema.Table`, :class:`.Sequence`
+    or in some cases a :class:`_schema.ForeignKey` object
     should have 'None' for its schema, even if the parent
     :class:`_schema.MetaData` has specified a schema.
 
@@ -1111,7 +1112,14 @@ class Table(DialectKWArgs, HasSchemaAttr, TableClause):
          target schema that we are changing to, the
          :class:`_schema.ForeignKeyConstraint` object, and the existing
          "target schema" of that constraint.  The function should return the
-         string schema name that should be applied.
+         string schema name that should be applied.    To reset the schema
+         to "none", return the symbol :data:`.BLANK_SCHEMA`.  To effect no
+         change, return ``None`` or :data:`.RETAIN_SCHEMA`.
+
+         .. versionchanged:: 1.4.33  The ``referred_schema_fn`` function
+            may return the :data:`.BLANK_SCHEMA` or :data:`.RETAIN_SCHEMA`
+            symbols.
+
          E.g.::
 
                 def referred_schema_fn(table, to_schema,
@@ -2467,11 +2475,14 @@ class ForeignKey(DialectKWArgs, SchemaItem):
         argument first passed to the object's constructor.
 
         """
-        if schema:
+        if schema not in (None, RETAIN_SCHEMA):
             _schema, tname, colname = self._column_tokens
             if table_name is not None:
                 tname = table_name
-            return "%s.%s.%s" % (schema, tname, colname)
+            if schema is BLANK_SCHEMA:
+                return "%s.%s" % (tname, colname)
+            else:
+                return "%s.%s.%s" % (schema, tname, colname)
         elif table_name:
             schema, tname, colname = self._column_tokens
             if schema:
index 21fc0a6272820785a3086f24683cf1df7309528a..f7480d11a96a5cf7bbe5e21378b0980c4fdc0fc6 100644 (file)
@@ -41,6 +41,7 @@ from sqlalchemy.sql import naming
 from sqlalchemy.sql import operators
 from sqlalchemy.sql.elements import _NONE_NAME
 from sqlalchemy.sql.elements import literal_column
+from sqlalchemy.sql.schema import RETAIN_SCHEMA
 from sqlalchemy.testing import assert_raises
 from sqlalchemy.testing import assert_raises_message
 from sqlalchemy.testing import AssertsCompiledSQL
@@ -1315,6 +1316,27 @@ class ToMetaDataTest(fixtures.TestBase, AssertsCompiledSQL, ComparesTables):
 
         self._assert_fk(t2, "z", "h.t1.x", referred_schema_fn=ref_fn)
 
+    def test_fk_reset_to_none(self):
+        m = MetaData()
+
+        t2 = Table("t2", m, Column("y", Integer, ForeignKey("p.t1.x")))
+
+        def ref_fn(table, to_schema, constraint, referred_schema):
+            return BLANK_SCHEMA
+
+        self._assert_fk(t2, None, "t1.x", referred_schema_fn=ref_fn)
+
+    @testing.combinations(None, RETAIN_SCHEMA)
+    def test_fk_test_non_return_for_referred_schema(self, sym):
+        m = MetaData()
+
+        t2 = Table("t2", m, Column("y", Integer, ForeignKey("p.t1.x")))
+
+        def ref_fn(table, to_schema, constraint, referred_schema):
+            return sym
+
+        self._assert_fk(t2, None, "p.t1.x", referred_schema_fn=ref_fn)
+
     def test_copy_info(self):
         m = MetaData()
         fk = ForeignKey("t2.id")