]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Consult _select_from_entity in _adjust_for_single_inheritance
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 16 Jan 2017 18:06:44 +0000 (13:06 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 14 Mar 2017 23:41:21 +0000 (19:41 -0400)
Fixed bug in single-table inheritance where the select_from()
argument would not be taken into account when limiting rows
to a subclass.  Previously, only expressions in the
columns requested would be taken into account.

Change-Id: Id353c45eade52b264d8f6685a58ba53975669eea
Fixes: #3891
doc/build/changelog/changelog_12.rst
doc/build/changelog/migration_12.rst
lib/sqlalchemy/orm/query.py
test/orm/inheritance/test_single.py

index 7e6c406da9e1ed407506963ac82568118f098ebf..a158ec1a3befed9a8a436f228dd0905dde4ffdc0 100644 (file)
         of SQL expressions) could not be reliably serialized.  Also bumped
         the default pickle level for the serializer to "HIGHEST_PROTOCOL".
 
+    .. change:: 3891
+        :tags: bug, orm
+        :tickets: 3891
+
+        Fixed bug in single-table inheritance where the select_from()
+        argument would not be taken into account when limiting rows
+        to a subclass.  Previously, only expressions in the
+        columns requested would be taken into account.
+
+        .. seealso::
+
+            :ref:`change_3891`
+
     .. change:: 3932
         :tags: bug, oracle
         :tickets: 3932
index 4ef08bca6c18896ef72bb71b2248cf2ef1e0d2e3..d64200d120661e367bd3f8c527af05a6bc86b1df 100644 (file)
@@ -34,6 +34,7 @@ SQLAlchemy is currnetly tested on versions 3.5 and 3.6.
 New Features and Improvements - ORM
 ===================================
 
+
 New Features and Improvements - Core
 ====================================
 
@@ -103,6 +104,41 @@ able to load within the scope of the event.
 
 :ticket:`3934`
 
+.. _change_3891:
+
+Fixed issue involving single-table inheritance with ``select_from()``
+---------------------------------------------------------------------
+
+The :meth:`.Query.select_from` method now honors the single-table inheritance
+column discriminator when generating SQL; previously, only the expressions
+in the query column list would be taken into account.
+
+Supposing ``Manager`` is a subclass of ``Employee``.  A query like the following::
+
+    sess.query(Manager.id)
+
+Would generate SQL as::
+
+    SELECT employee.id FROM employee WHERE employee.type IN ('manager')
+
+However, if ``Manager`` were only specified by :meth:`.Query.select_from`
+and not in the columns list, the discriminator would not be added::
+
+    sess.query(func.count(1)).select_from(Manager)
+
+would generate::
+
+    SELECT count(1) FROM employee
+
+With the fix, :meth:`.Query.select_from` now works correctly and we get::
+
+    SELECT count(1) FROM employee WHERE employee.type IN ('manager')
+
+Applications that may have been working around this by supplying the
+WHERE clause manually may need to be adjusted.
+
+:ticket:`3891`
+
 Key Behavioral Changes - Core
 =============================
 
index 2fae36272b614132d416be66f2ea4980a2eb91c9..f6459de2c0d00218bed861cdb1802f5a596ea046 100644 (file)
@@ -3475,12 +3475,22 @@ class Query(object):
         """Apply single-table-inheritance filtering.
 
         For all distinct single-table-inheritance mappers represented in
-        the columns clause of this query, add criterion to the WHERE
+        the columns clause of this query, as well as the "select from entity",
+        add criterion to the WHERE
         clause of the given QueryContext such that only the appropriate
         subtypes are selected from the total results.
 
         """
-        for (ext_info, adapter) in set(self._mapper_adapter_map.values()):
+
+        search = set(self._mapper_adapter_map.values())
+        if self._select_from_entity:
+            # based on the behavior in _set_select_from,
+            # when we have self._select_from_entity, we don't
+            # have  _from_obj_alias.
+            # assert self._from_obj_alias is None
+            search = search.union([(self._select_from_entity, None)])
+
+        for (ext_info, adapter) in search:
             if ext_info in self._join_entities:
                 continue
             single_crit = ext_info.mapper._single_table_criterion
index 26cf9fa01a0ebbbb66508179c47a497ed3356cb4..0c7fc6f8d373fe64abfdf28020ec6d80005a6024 100644 (file)
@@ -310,11 +310,26 @@ class SingleInheritanceTest(testing.AssertsCompiledSQL, fixtures.MappedTest):
             use_default_dialect=True
         )
 
-    def test_select_from(self):
-        Manager = self.classes.Manager
-        JuniorEngineer = self.classes.JuniorEngineer
-        employees = self.tables.employees
-        Engineer = self.classes.Engineer
+    def test_select_from_count(self):
+        Manager, Engineer = (self.classes.Manager, self.classes.Engineer)
+
+        sess = create_session()
+        m1 = Manager(name='Tom', manager_data='data1')
+        e1 = Engineer(name='Kurt', engineer_info='knows how to hack')
+        sess.add_all([m1, e1])
+        sess.flush()
+
+        eq_(
+            sess.query(func.count(1)).select_from(Manager).all(),
+            [(1, )]
+        )
+
+    def test_select_from_subquery(self):
+        Manager, JuniorEngineer, employees, Engineer = (
+            self.classes.Manager,
+            self.classes.JuniorEngineer,
+            self.tables.employees,
+            self.classes.Engineer)
 
         sess = create_session()
         m1 = Manager(name='Tom', manager_data='data1')