]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
merge compound select grouping patch from trunk (ticket #623)
authorAnts Aasma <ants.aasma@gmail.com>
Tue, 26 Jun 2007 18:31:57 +0000 (18:31 +0000)
committerAnts Aasma <ants.aasma@gmail.com>
Tue, 26 Jun 2007 18:31:57 +0000 (18:31 +0000)
CHANGES
lib/sqlalchemy/sql.py
test/sql/query.py
test/sql/select.py

diff --git a/CHANGES b/CHANGES
index c7c8be6a858ac773cdac9ff32f39659cb422640e..b49dec627baae8e6fd5a23b0be7c5d6ffadccd29 100644 (file)
--- a/CHANGES
+++ b/CHANGES
       to polymorphic mappers that are using a straight "outerjoin"
       clause
 - sql
+    - fixed grouping of compound selects to give correct results. will break
+      on sqlite in some cases, but those cases were producing incorrect
+      results anyway, sqlite doesn't support grouped compound selects
+      [ticket:623]
     - fixed precedence of operators so that parenthesis are correctly applied
       [ticket:620]
     - calling <column>.in_() (i.e. with no arguments) will return 
index 15d46889ad7d981a1349d788f6e0e5b49cea04e3..aaac096d068519b85e022ac0b01f1c99875dd0bc 100644 (file)
@@ -2314,7 +2314,10 @@ class _Grouping(ColumnElement):
         
     def _get_from_objects(self, **modifiers):
         return self.elem._get_from_objects(**modifiers)
-        
+
+    def __getattr__(self, attr):
+        return getattr(self.elem, attr)
+
 class _Label(ColumnElement):
     """represent a label, as typically applied to any column-level element
     using the ``AS`` sql keyword.
@@ -2633,10 +2636,14 @@ class CompoundSelect(_SelectBaseMixin, FromClause):
         self.selects = []
 
         # some DBs do not like ORDER BY in the inner queries of a UNION, etc.
-        for s in selects:
+        for n, s in enumerate(selects):
             if len(s._order_by_clause):
                 s = s.order_by(None)
-            self.selects.append(s)
+            # unions group from left to right, so don't group first select
+            if n:
+                self.selects.append(s.self_group(self))
+            else:
+                self.selects.append(s)
 
         self._col_map = {}
 
@@ -2956,6 +2963,8 @@ class Select(_SelectBaseMixin, FromClause):
             return column._make_proxy(self)
 
     def self_group(self, against=None):
+        if isinstance(against, CompoundSelect):
+            return self
         return _Grouping(self)
 
     def _locate_oid_column(self):
index f27c7624c20e3ce5f28d9842819137e6148343c7..8648555c782f5cc7002dc964848081d1d4b88ddd 100644 (file)
@@ -585,6 +585,29 @@ class CompoundTest(PersistTest):
         assert e.execute().fetchall() == [('aaa', 'aaa'), ('aaa', 'ccc'), ('bbb', 'aaa'), ('bbb', 'bbb'), ('ccc', 'bbb'), ('ccc', 'ccc')]
         assert e.alias('bar').select().execute().fetchall() == [('aaa', 'aaa'), ('aaa', 'ccc'), ('bbb', 'aaa'), ('bbb', 'bbb'), ('ccc', 'bbb'), ('ccc', 'ccc')]
 
+    @testbase.unsupported('sqlite', 'mysql', 'oracle')
+    def test_except_style3(self):
+        # aaa, bbb, ccc - (aaa, bbb, ccc - (ccc)) = ccc
+        e = except_(
+            select([t1.c.col3]), # aaa, bbb, ccc
+            except_(
+                select([t2.c.col3]), # aaa, bbb, ccc
+                select([t3.c.col3], t3.c.col3 == 'ccc'), #ccc
+            )
+        )
+        self.assertEquals(e.execute().fetchall(), [('ccc',)])
+
+    @testbase.unsupported('sqlite', 'mysql', 'oracle')
+    def test_union_union_all(self):
+        e = union_all(
+            select([t1.c.col3]),
+            union(
+                select([t1.c.col3]),
+                select([t1.c.col3]),
+            )
+        )
+        self.assertEquals(e.execute().fetchall(), [('aaa',),('bbb',),('ccc',),('aaa',),('bbb',),('ccc',)])
+
     @testbase.unsupported('mysql')
     def test_composite(self):
         u = intersect(
index 80b86fec5109faa054b6a089724756fcb648b6f7..7d9a2a8ca3469a68299945be897f06a8cabc3794 100644 (file)
@@ -674,6 +674,33 @@ FROM myothertable ORDER BY myid \
 WHERE mytable.name = :mytable_name GROUP BY mytable.myid, mytable.name UNION SELECT mytable.myid, mytable.name, mytable.description \
 FROM mytable WHERE mytable.name = :mytable_name_1"
             )
+
+    def test_compound_select_grouping(self):
+            self.runtest(
+                union_all(
+                    select([table1.c.myid]),
+                    union(
+                        select([table2.c.otherid]),
+                        select([table3.c.userid]),
+                    )
+                )
+                ,
+                "SELECT mytable.myid FROM mytable UNION ALL (SELECT myothertable.otherid FROM myothertable UNION \
+SELECT thirdtable.userid FROM thirdtable)"
+            )
+            # This doesn't need grouping, so don't group to not give sqlite unnecessarily hard time
+            self.runtest(
+                union(
+                    except_(
+                        select([table2.c.otherid]),
+                        select([table3.c.userid]),
+                    ),
+                    select([table1.c.myid])
+                )
+                ,
+                "SELECT myothertable.otherid FROM myothertable EXCEPT SELECT thirdtable.userid FROM thirdtable \
+UNION SELECT mytable.myid FROM mytable"
+            )
             
     def testouterjoin(self):
         # test an outer join.  the oracle module should take the ON clause of the join and