]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Changed the approach by which the "single inheritance criterion"
authorMike Bayer <mike_mp@zzzcomputing.com>
Fri, 29 Aug 2014 16:05:00 +0000 (12:05 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Fri, 29 Aug 2014 16:05:00 +0000 (12:05 -0400)
is applied, when using :meth:`.Query.from_self`, or its common
user :meth:`.Query.count`.  The criteria to limit rows to those
with a certain type is now indicated on the inside subquery,
not the outside one, so that even if the "type" column is not
available in the columns clause, we can filter on it on the "inner"
query.
fixes #3177

doc/build/changelog/changelog_10.rst
doc/build/changelog/migration_10.rst
lib/sqlalchemy/orm/query.py
test/orm/inheritance/test_single.py

index 87f32aff6acab5510ceddd5ee1eab1563b25ea01..13af7f953c534579599c24d9ca4ba3ba426f1108 100644 (file)
     on compatibility concerns, see :doc:`/changelog/migration_10`.
 
 
+    .. change::
+        :tags: bug, orm
+        :tickets: 3177
+
+        Changed the approach by which the "single inheritance criterion"
+        is applied, when using :meth:`.Query.from_self`, or its common
+        user :meth:`.Query.count`.  The criteria to limit rows to those
+        with a certain type is now indicated on the inside subquery,
+        not the outside one, so that even if the "type" column is not
+        available in the columns clause, we can filter on it on the "inner"
+        query.
+
+        .. seealso::
+
+            :ref:`migration_3177`
+
     .. change::
         :tags: change, orm
 
index 3dc2871b04e8f63306c831a26fa7016e1e88fd02..16a7902346c07bea7c4ffae7a60c869585b24f75 100644 (file)
@@ -417,6 +417,63 @@ as remaining ORM constructs such as :func:`.orm.synonym`.
 
 :ticket:`2963`
 
+.. _migration_3177:
+
+Change to single-table-inheritance criteria when using from_self(), count()
+---------------------------------------------------------------------------
+
+Given a single-table inheritance mapping, such as::
+
+       class Widget(Base):
+               __table__ = 'widget_table'
+
+       class FooWidget(Widget):
+               pass
+
+Using :meth:`.Query.from_self` or :meth:`.Query.count` against a subclass
+would produce a subquery, but then add the "WHERE" criteria for subtypes
+to the outside::
+
+       sess.query(FooWidget).from_self().all()
+
+rendering::
+
+       SELECT
+               anon_1.widgets_id AS anon_1_widgets_id,
+               anon_1.widgets_type AS anon_1_widgets_type
+       FROM (SELECT widgets.id AS widgets_id, widgets.type AS widgets_type,
+       FROM widgets) AS anon_1
+       WHERE anon_1.widgets_type IN (?)
+
+The issue with this is that if the inner query does not specify all
+columns, then we can't add the WHERE clause on the outside (it actually tries,
+and produces a bad query).  This decision
+apparently goes way back to 0.6.5 with the note "may need to make more
+adjustments to this".   Well, those adjustments have arrived!  So now the
+above query will render::
+
+       SELECT
+               anon_1.widgets_id AS anon_1_widgets_id,
+               anon_1.widgets_type AS anon_1_widgets_type
+       FROM (SELECT widgets.id AS widgets_id, widgets.type AS widgets_type,
+       FROM widgets
+       WHERE widgets.type IN (?)) AS anon_1
+
+So that queries that don't include "type" will still work!::
+
+       sess.query(FooWidget.id).count()
+
+Renders::
+
+       SELECT count(*) AS count_1
+       FROM (SELECT widgets.id AS widgets_id
+       FROM widgets
+       WHERE widgets.type IN (?)) AS anon_1
+
+
+:ticket:`3177`
+
+
 Dialect Changes
 ===============
 
index b0564671947bc1aa7f9299bbe859a07734a91b93..61fbd1be8794d956736a706a9c4a042a3b129a67 100644 (file)
@@ -945,9 +945,9 @@ class Query(object):
 
         """
         fromclause = self.with_labels().enable_eagerloads(False).\
-            _set_enable_single_crit(False).\
             statement.correlate(None)
         q = self._from_selectable(fromclause)
+        q._enable_single_crit = False
         if entities:
             q._set_entities(entities)
         return q
index 434642ca14cef15c3ba5f6e23a43219914c01742..23b1c4fd2a694839929716c809969dbcce393cb9 100644 (file)
@@ -149,11 +149,24 @@ class SingleInheritanceTest(testing.AssertsCompiledSQL, fixtures.MappedTest):
                             'employees_manager_data, '
                             'employees.engineer_info AS '
                             'employees_engineer_info, employees.type '
-                            'AS employees_type FROM employees) AS '
-                            'anon_1 WHERE anon_1.employees_type IN '
-                            '(:type_1, :type_2)',
+                            'AS employees_type FROM employees WHERE '
+                            'employees.type IN (:type_1, :type_2)) AS '
+                            'anon_1',
                             use_default_dialect=True)
 
+    def test_from_self_count(self):
+        Engineer = self.classes.Engineer
+
+        sess = create_session()
+        col = func.count(literal_column('*'))
+        self.assert_compile(
+            sess.query(Engineer.employee_id).from_self(col),
+            "SELECT count(*) AS count_1 "
+            "FROM (SELECT employees.employee_id AS employees_employee_id "
+            "FROM employees "
+            "WHERE employees.type IN (?, ?)) AS anon_1"
+        )
+
     def test_select_from(self):
         Manager, JuniorEngineer, employees, Engineer = (self.classes.Manager,
                                 self.classes.JuniorEngineer,