From: Mike Bayer Date: Thu, 15 Sep 2016 04:50:17 +0000 (-0400) Subject: Repair foreign_keys population for Join._refresh_for_new_column X-Git-Tag: rel_1_1_0~31 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=25804aeae262fa01256dbd2f045ad4a380644f66;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Repair foreign_keys population for Join._refresh_for_new_column 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 --- diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index fbf5ed1639..9ca98ff375 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -18,6 +18,16 @@ .. 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 diff --git a/lib/sqlalchemy/sql/selectable.py b/lib/sqlalchemy/sql/selectable.py index 11ef99f09f..43aff7caa2 100644 --- a/lib/sqlalchemy/sql/selectable.py +++ b/lib/sqlalchemy/sql/selectable.py @@ -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 diff --git a/test/ext/declarative/test_inheritance.py b/test/ext/declarative/test_inheritance.py index 274a6aa285..a5a86b7c6f 100644 --- a/test/ext/declarative/test_inheritance.py +++ b/test/ext/declarative/test_inheritance.py @@ -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]""" diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py index 94e4ac024c..95a0336b7b 100644 --- a/test/sql/test_selectable.py +++ b/test/sql/test_selectable.py @@ -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):