From 3da3322ec4f42b58ec8b07108f2dacd33044c73d Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Sun, 24 Apr 2022 16:19:16 -0400 Subject: [PATCH] forwards port test cases and changelog for #7958 to 2.0 in 6f02d5edd88fe2475629438b0730181a2b00c5fe some cleanup to ForeignKey repaired the use case of ForeignKey objects referring to table name alone, by adding more robust column resolution logic. This change also fixes an issue where the "referred column" naming convention key uses the resolved referred column earlier than usual when a ForeignKey is setting up its constraint. change message for 1.4: Fixed bug where :class:`.ForeignKeyConstraint` naming conventions using the ``referred_column_0`` naming convention key would not work if the foreign key constraint were set up as a :class:`.ForeignKey` object rather than an explicit :class:`.ForeignKeyConstraint` object. As this change makes use of a backport of some fixes from version 2.0, an additional little-known feature that has likely been broken for many years is also fixed which is that a :class:`.ForeignKey` object may refer to a referred table by name of the table alone without using a column name, if the name of the referent column is the same as that of the referred column. The ``referred_column_0`` naming convention key was not previously not tested with the :class:`.ForeignKey` object, only :class:`.ForeignKeyConstraint`, and this bug reveals that the feature has never worked correctly unless :class:`.ForeignKeyConstraint` is used for all FK constraints. This bug traces back to the original introduction of the feature introduced for :ticket:`3989`. Fixes: #7958 Change-Id: I230d43e9deba5dff889b9e7fee6cd4d3aa2496d3 (cherry picked from commit e32937fa6a7dcc3d5087aa1f41049373ab9e4038) --- doc/build/changelog/unreleased_14/7958.rst | 20 +++++++++++++++++++ test/sql/test_metadata.py | 23 ++++++++++++++++++++++ 2 files changed, 43 insertions(+) create mode 100644 doc/build/changelog/unreleased_14/7958.rst diff --git a/doc/build/changelog/unreleased_14/7958.rst b/doc/build/changelog/unreleased_14/7958.rst new file mode 100644 index 0000000000..057647bd87 --- /dev/null +++ b/doc/build/changelog/unreleased_14/7958.rst @@ -0,0 +1,20 @@ +.. change:: + :tags: bug, schema + :tickets: 7958 + + Fixed bug where :class:`.ForeignKeyConstraint` naming conventions using the + ``referred_column_0`` naming convention key would not work if the foreign + key constraint were set up as a :class:`.ForeignKey` object rather than an + explicit :class:`.ForeignKeyConstraint` object. As this change makes use of + a backport of some fixes from version 2.0, an additional little-known + feature that has likely been broken for many years is also fixed which is + that a :class:`.ForeignKey` object may refer to a referred table by name of + the table alone without using a column name, if the name of the referent + column is the same as that of the referred column. + + The ``referred_column_0`` naming convention key was not previously not + tested with the :class:`.ForeignKey` object, only + :class:`.ForeignKeyConstraint`, and this bug reveals that the feature has + never worked correctly unless :class:`.ForeignKeyConstraint` is used for + all FK constraints. This bug traces back to the original introduction of + the feature introduced for :ticket:`3989`. diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index f7480d11a9..b175f96633 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -5345,6 +5345,29 @@ class NamingConventionTest(fixtures.TestBase, AssertsCompiledSQL): a1.append_constraint(fk) eq_(fk.name, "fk_address_user_id_user_id") + @testing.combinations(True, False, argnames="col_has_type") + def test_fk_ref_local_referent_has_no_type(self, col_has_type): + """test #7958""" + + metadata = MetaData( + naming_convention={ + "fk": "fk_%(referred_column_0_name)s", + } + ) + Table("a", metadata, Column("id", Integer, primary_key=True)) + b = Table( + "b", + metadata, + Column("id", Integer, primary_key=True), + Column("aid", ForeignKey("a.id")) + if not col_has_type + else Column("aid", Integer, ForeignKey("a.id")), + ) + fks = list( + c for c in b.constraints if isinstance(c, ForeignKeyConstraint) + ) + eq_(fks[0].name, "fk_id") + def test_custom(self): def key_hash(const, table): return "HASH_%s" % table.name -- 2.47.2