From: Mike Bayer Date: Fri, 12 Apr 2013 00:04:57 +0000 (-0400) Subject: Fixed bug whereby ORM would run the wrong kind of X-Git-Tag: rel_0_8_1~15^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=ce5cff151ad5f4d807c2655f7e44c3245552c0b6;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Fixed bug whereby ORM would run the wrong kind of query when refreshing an inheritance-mapped class where the superclass was mapped to a non-Table object, like a custom join() or a select(), running a query that assumed a hierarchy that's mapped to individual Table-per-class. [ticket:2697] --- diff --git a/doc/build/changelog/changelog_08.rst b/doc/build/changelog/changelog_08.rst index 13c044351c..60d61cb8da 100644 --- a/doc/build/changelog/changelog_08.rst +++ b/doc/build/changelog/changelog_08.rst @@ -6,6 +6,17 @@ .. changelog:: :version: 0.8.1 + .. change:: + :tags: bug, orm + :tickets: 2697 + + Fixed bug whereby ORM would run the wrong kind of + query when refreshing an inheritance-mapped class + where the superclass was mapped to a non-Table + object, like a custom join() or a select(), + running a query that assumed a hierarchy that's + mapped to individual Table-per-class. + .. change:: :tags: bug, orm diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index d258a20b60..914c29b7fa 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -1933,6 +1933,8 @@ class Mapper(_InspectionAttr): for mapper in reversed(list(self.iterate_to_root())): if mapper.local_table in tables: start = True + elif not isinstance(mapper.local_table, expression.TableClause): + return None if start and not mapper.single: allconds.append(visitors.cloned_traverse( mapper.inherit_condition, diff --git a/test/orm/inheritance/test_basic.py b/test/orm/inheritance/test_basic.py index 3cd3db9280..f883a07a7b 100644 --- a/test/orm/inheritance/test_basic.py +++ b/test/orm/inheritance/test_basic.py @@ -1637,6 +1637,53 @@ class OptimizedLoadTest(fixtures.MappedTest): Column('b', String(10)) ) + def test_no_optimize_on_map_to_join(self): + base, sub = self.tables.base, self.tables.sub + + class Base(fixtures.ComparableEntity): + pass + + class JoinBase(fixtures.ComparableEntity): + pass + class SubJoinBase(JoinBase): + pass + + mapper(Base, base) + mapper(JoinBase, base.outerjoin(sub), properties={ + 'id': [base.c.id, sub.c.id], + 'counter': [base.c.counter, sub.c.counter] + }) + mapper(SubJoinBase, inherits=JoinBase) + + sess = Session() + sess.add(Base(data='data')) + sess.commit() + + sjb = sess.query(SubJoinBase).one() + sjb_id = sjb.id + sess.expire(sjb) + + # this should not use the optimized load, + # which assumes discrete tables + def go(): + eq_(sjb.data, 'data') + + self.assert_sql_execution( + testing.db, + go, + CompiledSQL( + "SELECT base.counter AS base_counter, " + "sub.counter AS sub_counter, base.id AS base_id, " + "sub.id AS sub_id, base.data AS base_data, " + "base.type AS base_type, sub.sub AS sub_sub, " + "sub.counter2 AS sub_counter2 FROM base " + "LEFT OUTER JOIN sub ON base.id = sub.id " + "WHERE base.id = :param_1", + {'param_1': sjb_id} + ), + ) + + def test_optimized_passes(self): """"test that the 'optimized load' routine doesn't crash when a column in the join condition is not available.""" @@ -1678,7 +1725,7 @@ class OptimizedLoadTest(fixtures.MappedTest): pass mapper(Base, base, polymorphic_on=base.c.type, polymorphic_identity='base') mapper(Sub, sub, inherits=Base, polymorphic_identity='sub', properties={ - 'concat':column_property(sub.c.sub + "|" + sub.c.sub) + 'concat': column_property(sub.c.sub + "|" + sub.c.sub) }) sess = sessionmaker()() s1 = Sub(data='s1data', sub='s1sub') @@ -1697,7 +1744,7 @@ class OptimizedLoadTest(fixtures.MappedTest): pass mapper(Base, base, polymorphic_on=base.c.type, polymorphic_identity='base') mapper(Sub, sub, inherits=Base, polymorphic_identity='sub', properties={ - 'concat':column_property(base.c.data + "|" + sub.c.sub) + 'concat': column_property(base.c.data + "|" + sub.c.sub) }) sess = sessionmaker()() s1 = Sub(data='s1data', sub='s1sub')