]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- sending a selectable to an IN no longer creates a "union" out of multiple
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 29 Nov 2006 22:13:58 +0000 (22:13 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 29 Nov 2006 22:13:58 +0000 (22:13 +0000)
selects; only one selectable to an IN is allowed now (make a union yourself
if union is needed; explicit better than implicit, dont guess, etc.)

CHANGES
lib/sqlalchemy/sql.py
test/sql/select.py

diff --git a/CHANGES b/CHANGES
index 979041842acbf21be82ce7eadc90243b8e47e17d..df487cf267b3593eb7eb2cf99d90dd571e1a2d3d 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,9 @@ to create a scalar subquery.
 - added extra check to "stop" cascading on save/update/save-update if
 an instance is detected to be already in the session.
 - fix to session.update() to preserve "dirty" status of incoming object
+- sending a selectable to an IN no longer creates a "union" out of multiple
+selects; only one selectable to an IN is allowed now (make a union yourself
+if union is needed; explicit better than implicit, dont guess, etc.)
 
 0.3.1
 - Engine/Pool:
index 17c0a25f7605826df4bf0f103b42e0a55ac22b0b..acdba2c700f101a6577c94f8b3bfd5abc12f6f22 100644 (file)
@@ -545,10 +545,12 @@ class _CompareMixin(object):
         elif _is_literal(other[0]):
             return self._compare('IN', ClauseList(parens=True, *[self._bind_param(o) for o in other]), negate='NOT IN')
         else:
-            # assume *other is a list of selects.
-            # so put them in a UNION.  if theres only one, you just get one SELECT 
-            # statement out of it.
-            return self._compare('IN', union(parens=True, *other), negate='NOT IN')
+            # assume *other is a single select.
+            # originally, this assumed possibly multiple selects and created a UNION, 
+            # but we are now forcing explictness if a UNION is desired.
+            if len(other) > 1:
+                raise exceptions.InvalidRequestException("in() function accepts only multiple literal values, or a single selectable as an argument")
+            return self._compare('IN', other[0], negate='NOT IN')
     def startswith(self, other):
         return self._compare('LIKE', other + "%")
     def endswith(self, other):
@@ -1366,6 +1368,7 @@ class CompoundSelect(_SelectBaseMixin, FromClause):
 
         self.selects = selects
 
+        # some DBs do not like ORDER BY in the inner queries of a UNION, etc.
         for s in selects:
             s.group_by(None)
             s.order_by(None)
index 1c8927e6b19b3e15bd2e6145fc2aed9ef9b69e3b..c422c63fbe664b081c54db89d2f53172252ae7e8 100644 (file)
@@ -572,6 +572,18 @@ FROM mytable, myothertable WHERE mytable.myid = myothertable.otherid AND mytable
 
         self.runtest(select([table1], ~table1.c.myid.in_(select([table2.c.otherid]))),
         "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid NOT IN (SELECT myothertable.otherid AS otherid FROM myothertable)")
+        
+        # test that putting a select in an IN clause does not blow away its ORDER BY clause
+        self.runtest(
+            select([table1, table2], 
+                table2.c.otherid.in_(
+                    select([table2.c.otherid], order_by=[table2.c.othername], limit=10, correlate=False)
+                ),
+                from_obj=[table1.join(table2, table1.c.myid==table2.c.otherid)], order_by=[table1.c.myid]
+            ),
+            "SELECT mytable.myid, mytable.name, mytable.description, myothertable.otherid, myothertable.othername FROM mytable JOIN myothertable ON mytable.myid = myothertable.otherid WHERE myothertable.otherid IN (SELECT myothertable.otherid AS otherid FROM myothertable ORDER BY myothertable.othername  LIMIT 10) ORDER BY mytable.myid"
+        )
+        
     
     def testlateargs(self):
         """tests that a SELECT clause will have extra "WHERE" clauses added to it at compile time if extra arguments