From: Mike Bayer Date: Tue, 16 Sep 2008 18:18:15 +0000 (+0000) Subject: - column.in_(someselect) can now be used as X-Git-Tag: rel_0_4_8~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4a98ddde1676d91b9eadf9b59de11c132c1abf4f;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - column.in_(someselect) can now be used as a columns-clause expression without the subquery bleeding into the FROM clause [ticket:1074] --- diff --git a/CHANGES b/CHANGES index 5ba1b1eb89..d84aaff7d8 100644 --- 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]. diff --git a/lib/sqlalchemy/sql/expression.py b/lib/sqlalchemy/sql/expression.py index 867fdd69c3..364c0a5ef6 100644 --- a/lib/sqlalchemy/sql/expression.py +++ b/lib/sqlalchemy/sql/expression.py @@ -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) diff --git a/test/sql/select.py b/test/sql/select.py index f00d035308..450b9a9654 100644 --- a/test/sql/select.py +++ b/test/sql/select.py @@ -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),