]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Repair foreign_keys population for Join._refresh_for_new_column
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 15 Sep 2016 04:50:17 +0000 (00:50 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 15 Sep 2016 04:54:15 +0000 (00:54 -0400)
Fixed bug where setting up a single-table inh subclass of a joined-table
subclass which included an extra column would corrupt the foreign keys
collection of the mapped table, thereby interfering with the
initialization of relationships.

Change-Id: I04a0cf98fd456d12d5a5b9e77a46a01246969a63
Fixes: #3797
doc/build/changelog/changelog_10.rst
lib/sqlalchemy/sql/selectable.py
test/ext/declarative/test_inheritance.py
test/sql/test_selectable.py

index fbf5ed163919ff918da9a72b8d069e73d4f81adb..9ca98ff375bc0fb92b99670b63d1690de4a9b733 100644 (file)
 .. changelog::
     :version: 1.0.16
 
+    .. change::
+        :tags: bug, orm.declarative
+        :tickets: 3797
+        :versions: 1.1.0
+
+        Fixed bug where setting up a single-table inh subclass of a joined-table
+        subclass which included an extra column would corrupt the foreign keys
+        collection of the mapped table, thereby interfering with the
+        initialization of relationships.
+
 .. changelog::
     :version: 1.0.15
     :released: September 1, 2016
index 11ef99f09f426d5c140a048abe98b39a67f0a217..43aff7caa23b67696ce78d9bed9fb64313e17e35 100644 (file)
@@ -905,7 +905,7 @@ class Join(FromClause):
         if col is not None:
             if self._cols_populated:
                 self._columns[col._label] = col
-                self.foreign_keys.add(col)
+                self.foreign_keys.update(col.foreign_keys)
                 if col.primary_key:
                     self.primary_key.add(col)
                 return col
index 274a6aa285ec643625945b53724ef669824f8ada..a5a86b7c6f6165d31ecec3cc46d1225f4fcfe895 100644 (file)
@@ -1,6 +1,6 @@
 
 from sqlalchemy.testing import eq_, assert_raises, \
-    assert_raises_message, is_
+    assert_raises_message, is_, is_true
 from sqlalchemy.ext import declarative as decl
 import sqlalchemy as sa
 from sqlalchemy import testing
@@ -485,6 +485,56 @@ class DeclarativeInheritanceTest(DeclarativeTestBase):
                                            ).one(),
             Engineer(name='vlad', primary_language='cobol'))
 
+    def test_single_cols_on_sub_to_joined(self):
+        """test [ticket:3797]"""
+
+        class BaseUser(Base):
+            __tablename__ = 'root'
+
+            id = Column(Integer, primary_key=True)
+            row_type = Column(String)
+
+            __mapper_args__ = {
+                'polymorphic_on': row_type,
+                'polymorphic_identity': 'baseuser'
+            }
+
+        class User(BaseUser):
+            __tablename__ = 'user'
+
+            __mapper_args__ = {
+                'polymorphic_identity': 'user'
+            }
+
+            baseuser_id = Column(
+                Integer, ForeignKey('root.id'), primary_key=True)
+
+        class Bat(Base):
+            __tablename__ = 'bat'
+            id = Column(Integer, primary_key=True)
+
+        class Thing(Base):
+            __tablename__ = 'thing'
+
+            id = Column(Integer, primary_key=True)
+
+            owner_id = Column(Integer, ForeignKey('user.baseuser_id'))
+            owner = relationship('User')
+
+        class SubUser(User):
+            __mapper_args__ = {
+                'polymorphic_identity': 'subuser'
+            }
+
+            sub_user_custom_thing = Column(Integer, ForeignKey('bat.id'))
+
+        eq_(
+            User.__table__.foreign_keys,
+            User.baseuser_id.foreign_keys.union(
+                SubUser.sub_user_custom_thing.foreign_keys))
+        is_true(Thing.owner.property.primaryjoin.compare(
+            Thing.owner_id == User.baseuser_id))
+
     def test_single_constraint_on_sub(self):
         """test the somewhat unusual case of [ticket:3341]"""
 
index 94e4ac024c83fae75d538f7d63d3e0ba5b4a9b93..95a0336b7bfc7c81ee51b70d5bc24939e166f4fe 100644 (file)
@@ -916,6 +916,44 @@ class RefreshForNewColTest(fixtures.TestBase):
         j._refresh_for_new_column(q)
         assert j.c.b_q is q
 
+    def test_fk_table(self):
+        m = MetaData()
+        fk = ForeignKey('x.id')
+        Table('x', m, Column('id', Integer))
+        a = Table('a', m, Column('x', Integer, fk))
+        a.c
+
+        q = Column('q', Integer)
+        a.append_column(q)
+        a._refresh_for_new_column(q)
+        eq_(a.foreign_keys, set([fk]))
+
+        fk2 = ForeignKey('g.id')
+        p = Column('p', Integer, fk2)
+        a.append_column(p)
+        a._refresh_for_new_column(p)
+        eq_(a.foreign_keys, set([fk, fk2]))
+
+    def test_fk_join(self):
+        m = MetaData()
+        fk = ForeignKey('x.id')
+        Table('x', m, Column('id', Integer))
+        a = Table('a', m, Column('x', Integer, fk))
+        b = Table('b', m, Column('y', Integer))
+        j = a.join(b, a.c.x == b.c.y)
+        j.c
+
+        q = Column('q', Integer)
+        b.append_column(q)
+        j._refresh_for_new_column(q)
+        eq_(j.foreign_keys, set([fk]))
+
+        fk2 = ForeignKey('g.id')
+        p = Column('p', Integer, fk2)
+        b.append_column(p)
+        j._refresh_for_new_column(p)
+        eq_(j.foreign_keys, set([fk, fk2]))
+
 
 class AnonLabelTest(fixtures.TestBase):