]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- column.in_(someselect) can now be used as
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 16 Sep 2008 18:18:15 +0000 (18:18 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 16 Sep 2008 18:18:15 +0000 (18:18 +0000)
a columns-clause expression without the subquery
bleeding into the FROM clause [ticket:1074]

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

diff --git a/CHANGES b/CHANGES
index 5ba1b1eb899a120af35c9e4e7a67e40818828da7..d84aaff7d8b138dbc11b9ab43610942ca9e69f9b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -13,6 +13,11 @@ CHANGES
       SessionExtension.before_flush() will take
       effect for that flush.
 
+- sql
+    - column.in_(someselect) can now be used as 
+      a columns-clause expression without the subquery
+      bleeding into the FROM clause [ticket:1074]
+      
 - mysql
     - Added MSMediumInteger type [ticket:1146].
 
index 867fdd69c3ce5e6be7d2a14957c31b5a456edf19..364c0a5ef65350916ac6b8e110e6422dcbed1c84 100644 (file)
@@ -1334,14 +1334,18 @@ class _CompareMixin(ColumnOperators):
 
     def _in_impl(self, op, negate_op, *other):
         # Handle old style *args argument passing
-        if len(other) != 1 or not isinstance(other[0], Selectable) and (not hasattr(other[0], '__iter__') or isinstance(other[0], basestring)):
+        if len(other) != 1 or not isinstance(other[0], (_ScalarSelect, Selectable)) and (not hasattr(other[0], '__iter__') or isinstance(other[0], basestring)):
             util.warn_deprecated('passing in_ arguments as varargs is deprecated, in_ takes a single argument that is a sequence or a selectable')
             seq_or_selectable = other
         else:
             seq_or_selectable = other[0]
 
-        if isinstance(seq_or_selectable, Selectable):
-            return self.__compare( op, seq_or_selectable, negate=negate_op)
+        if isinstance(seq_or_selectable, _ScalarSelect):
+             return self.__compare( op, seq_or_selectable, negate=negate_op)
+        elif isinstance(seq_or_selectable, _SelectBaseMixin):
+             return self.__compare( op, seq_or_selectable.as_scalar(), negate=negate_op)
+        elif isinstance(seq_or_selectable, Selectable):
+             return self.__compare( op, seq_or_selectable, negate=negate_op)
 
         # Handle non selectable arguments as sequences
         args = []
@@ -2862,7 +2866,7 @@ class _ScalarSelect(_Grouping):
 
     def __init__(self, elem):
         self.elem = elem
-        cols = list(elem.inner_columns)
+        cols = list(elem.c)
         if len(cols) != 1:
             raise exceptions.InvalidRequestError("Scalar select can only be created from a Select object that has exactly one column expression.")
         self.type = cols[0].type
@@ -2905,7 +2909,7 @@ class CompoundSelect(_SelectBaseMixin, FromClause):
                 self.selects.append(s)
 
         _SelectBaseMixin.__init__(self, **kwargs)
-        
+
     def self_group(self, against=None):
         return _FromGrouping(self)
 
index f00d035308d4eccbe9812818497ac7285c352bbb..450b9a96546894325fef217cad6d50bf120aa584 100644 (file)
@@ -1131,13 +1131,13 @@ UNION SELECT mytable.myid FROM mytable"
 
         self.assert_compile(select([table1], table1.c.myid.in_(
             union(
-                  select([table1], table1.c.myid == 5),
-                  select([table1], table1.c.myid == 12),
+                  select([table1.c.myid], table1.c.myid == 5),
+                  select([table1.c.myid], table1.c.myid == 12),
             )
         )), "SELECT mytable.myid, mytable.name, mytable.description FROM mytable \
 WHERE mytable.myid IN (\
-SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid = :myid_1 \
-UNION SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid = :myid_2)")
+SELECT mytable.myid FROM mytable WHERE mytable.myid = :myid_1 \
+UNION SELECT mytable.myid FROM mytable WHERE mytable.myid = :myid_2)")
 
         # test that putting a select in an IN clause does not blow away its ORDER BY clause
         self.assert_compile(
@@ -1156,6 +1156,15 @@ UNION SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE
         self.assert_compile(select([table1], table1.c.myid.in_([])),
         "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE (CASE WHEN (mytable.myid IS NULL) THEN NULL ELSE 0 END = 1)")
 
+        self.assert_compile(
+            select([table1.c.myid.in_(select([table2.c.otherid]))]),
+            "SELECT mytable.myid IN (SELECT myothertable.otherid FROM myothertable) AS anon_1 FROM mytable"
+        )
+        self.assert_compile(
+            select([table1.c.myid.in_(select([table2.c.otherid]).as_scalar())]),
+            "SELECT mytable.myid IN (SELECT myothertable.otherid FROM myothertable) AS anon_1 FROM mytable"
+        )
+
     def test_in_deprecated_api(self):
         self.assert_compile(select([table1], table1.c.myid.in_('abc')),
         "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid IN (:myid_1)")
@@ -1168,8 +1177,10 @@ UNION SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE
 
         self.assert_compile(select([table1], table1.c.myid.in_()),
         "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE (CASE WHEN (mytable.myid IS NULL) THEN NULL ELSE 0 END = 1)")
+
     test_in_deprecated_api = testing.uses_deprecated('passing in_')(test_in_deprecated_api)
 
+
     def test_cast(self):
         tbl = table('casttest',
                     column('id', Integer),