From: Ants Aasma Date: Tue, 26 Jun 2007 18:31:57 +0000 (+0000) Subject: merge compound select grouping patch from trunk (ticket #623) X-Git-Tag: rel_0_4_6~174 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8b89aa795c0c2f3fbfbec7f79f9f89c6270ca7b7;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git merge compound select grouping patch from trunk (ticket #623) --- diff --git a/CHANGES b/CHANGES index c7c8be6a85..b49dec627b 100644 --- a/CHANGES +++ b/CHANGES @@ -91,6 +91,10 @@ 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 .in_() (i.e. with no arguments) will return diff --git a/lib/sqlalchemy/sql.py b/lib/sqlalchemy/sql.py index 15d46889ad..aaac096d06 100644 --- a/lib/sqlalchemy/sql.py +++ b/lib/sqlalchemy/sql.py @@ -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): diff --git a/test/sql/query.py b/test/sql/query.py index f27c7624c2..8648555c78 100644 --- a/test/sql/query.py +++ b/test/sql/query.py @@ -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( diff --git a/test/sql/select.py b/test/sql/select.py index 80b86fec51..7d9a2a8ca3 100644 --- a/test/sql/select.py +++ b/test/sql/select.py @@ -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