summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2016-09-15 00:50:17 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2016-09-15 00:54:15 -0400
commit25804aeae262fa01256dbd2f045ad4a380644f66 (patch)
tree9016ee540e1b1ca9d4b4c6e20f9d6517e37047df
parent6e1f34ed6230d7fce338ee4fb022678a7e511627 (diff)
downloadsqlalchemy-25804aeae262fa01256dbd2f045ad4a380644f66.tar.gz
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
-rw-r--r--doc/build/changelog/changelog_10.rst10
-rw-r--r--lib/sqlalchemy/sql/selectable.py2
-rw-r--r--test/ext/declarative/test_inheritance.py52
-rw-r--r--test/sql/test_selectable.py38
4 files changed, 100 insertions, 2 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst
index fbf5ed163..9ca98ff37 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 11ef99f09..43aff7caa 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 274a6aa28..a5a86b7c6 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 94e4ac024..95a0336b7 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):