From: Mike Bayer Date: Thu, 15 Jul 2010 13:59:17 +0000 (-0400) Subject: - Column-entities (i.e. query(Foo.id)) copy their X-Git-Tag: rel_0_6_3 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2bd3c795cfe39249aceb6b04ea4650a17788d9b6;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Column-entities (i.e. query(Foo.id)) copy their state more fully when queries are derived from themselves + a selectable (i.e. from_self(), union(), etc.), so that join() and such have the correct state to work from. [ticket:1853] - Fixed bug where Query.join() would fail if querying a non-ORM column then joining without an on clause when a FROM clause is already present, now raises a checked exception the same way it does when the clause is not present. [ticket:1853] --- diff --git a/CHANGES b/CHANGES index 09f69a0690..12730f9540 100644 --- a/CHANGES +++ b/CHANGES @@ -14,6 +14,19 @@ CHANGES and a delete of the parent has occurred. [ticket:1845] + - Column-entities (i.e. query(Foo.id)) copy their + state more fully when queries are derived from + themselves + a selectable (i.e. from_self(), + union(), etc.), so that join() and such have the + correct state to work from. [ticket:1853] + + - Fixed bug where Query.join() would fail if + querying a non-ORM column then joining without + an on clause when a FROM clause is already + present, now raises a checked exception the + same way it does when the clause is not + present. [ticket:1853] + - Improved the check for an "unmapped class", including the case where the superclass is mapped but the subclass is not. Any attempts to access diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 28ddc1f13b..3f8300a097 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -1301,7 +1301,7 @@ class Query(object): join_to_left = not is_aliased_class and not left_is_aliased - if self._from_obj: + if self._from_obj and left_selectable is not None: replace_clause_index, clause = sql_util.find_join_source( self._from_obj, left_selectable) @@ -2622,7 +2622,9 @@ class _ColumnEntity(_QueryEntity): return self.column.type def adapt_to_selectable(self, query, sel): - _ColumnEntity(query, sel.corresponding_column(self.column)) + c = _ColumnEntity(query, sel.corresponding_column(self.column)) + c.entity_zero = self.entity_zero + c.entities = self.entities def setup_entity(self, entity, mapper, adapter, from_obj, is_aliased_class, with_polymorphic): diff --git a/test/orm/test_query.py b/test/orm/test_query.py index ba8112db0c..ebe72b5655 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -2343,6 +2343,44 @@ class JoinTest(QueryTest, AssertsCompiledSQL): (order3, item3), ] ) + + def test_joins_from_adapted_entities(self): + + # test for #1853 + + session = create_session() + first = session.query(User) + second = session.query(User) + unioned = first.union(second) + subquery = session.query(User.id).subquery() + join = subquery, subquery.c.id == User.id + joined = unioned.outerjoin(join) + self.assert_compile(joined, + 'SELECT anon_1.users_id AS ' + 'anon_1_users_id, anon_1.users_name AS ' + 'anon_1_users_name FROM (SELECT users.id ' + 'AS users_id, users.name AS users_name ' + 'FROM users UNION SELECT users.id AS ' + 'users_id, users.name AS users_name FROM ' + 'users) AS anon_1 LEFT OUTER JOIN (SELECT ' + 'users.id AS id FROM users) AS anon_2 ON ' + 'anon_2.id = anon_1.users_id', + use_default_dialect=True) + + first = session.query(User.id) + second = session.query(User.id) + unioned = first.union(second) + subquery = session.query(User.id).subquery() + join = subquery, subquery.c.id == User.id + joined = unioned.outerjoin(join) + self.assert_compile(joined, + 'SELECT anon_1.users_id AS anon_1_users_id ' + 'FROM (SELECT users.id AS users_id FROM ' + 'users UNION SELECT users.id AS users_id ' + 'FROM users) AS anon_1 LEFT OUTER JOIN ' + '(SELECT users.id AS id FROM users) AS ' + 'anon_2 ON anon_2.id = anon_1.users_id', + use_default_dialect=True) def test_reset_joinpoint(self): for aliased in (True, False): @@ -2422,6 +2460,24 @@ class JoinTest(QueryTest, AssertsCompiledSQL): sess.query(User.name).join((addresses, User.id==addresses.c.user_id)).order_by(User.id).all(), [(u'jack',), (u'ed',), (u'ed',), (u'ed',), (u'fred',)] ) + + def test_no_joinpoint_expr(self): + sess = create_session() + + # these are consistent regardless of + # select_from() being present. + + assert_raises_message( + sa_exc.InvalidRequestError, + "Could not find a FROM", + sess.query(users.c.id).join, User + ) + + assert_raises_message( + sa_exc.InvalidRequestError, + "Could not find a FROM", + sess.query(users.c.id).select_from(users).join, User + ) def test_from_self_resets_joinpaths(self): """test a join from from_self() doesn't confuse joins inside the subquery