From: Mike Bayer Date: Sat, 26 Mar 2022 14:09:10 +0000 (-0400) Subject: support BLANK_SCHEMA, RETAIN_SCHEMA FK schema on copy X-Git-Tag: rel_1_4_33~12 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1a196d5b7d47ba1d207661e05605bc79badc9a7d;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git support BLANK_SCHEMA, RETAIN_SCHEMA FK schema on copy 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 (cherry picked from commit 74d3f3965b383aef7421f2cf1779573a4ac65987) --- diff --git a/doc/build/changelog/unreleased_14/7860.rst b/doc/build/changelog/unreleased_14/7860.rst new file mode 100644 index 0000000000..cb6bcc59fc --- /dev/null +++ b/doc/build/changelog/unreleased_14/7860.rst @@ -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. + diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 6240357f54..7c9fef644c 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -62,7 +62,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. @@ -1047,7 +1048,14 @@ class Table(DialectKWArgs, SchemaItem, 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, @@ -2292,11 +2300,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: diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index e193c5ec7a..7205c88233 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -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 @@ -1274,6 +1275,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")