]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- calling expr.in_([]), i.e. with an empty list, emits a warning
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 29 Dec 2009 23:20:48 +0000 (23:20 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 29 Dec 2009 23:20:48 +0000 (23:20 +0000)
before issuing the usual "expr != expr" clause.  The
"expr != expr" can be very expensive, and it's preferred
that the user not issue in_() if the list is empty,
instead simply not querying, or modifying the criterion
as appropriate for more complex situations.
[ticket:1628]

CHANGES
lib/sqlalchemy/sql/expression.py
test/sql/test_query.py
test/sql/test_select.py

diff --git a/CHANGES b/CHANGES
index 66ecdbf08ce17bde801e676b76642b50348e18f5..ae6e839595dc0d1737ae839b1fed5904e1e0e218 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -260,7 +260,15 @@ CHANGES
       named "tablename_id" - this is because
       the labeling logic is always applied to all columns
       so a naming conflict will never occur.
-      
+    
+    - calling expr.in_([]), i.e. with an empty list, emits a warning
+      before issuing the usual "expr != expr" clause.  The
+      "expr != expr" can be very expensive, and it's preferred
+      that the user not issue in_() if the list is empty,
+      instead simply not querying, or modifying the criterion
+       as appropriate for more complex situations.
+       [ticket:1628]
+       
     - Deprecated or removed:
         * "scalar" flag on select() is removed, use 
           select.as_scalar().
index 2f0ac90af2b7517ba6f65c25fd3d8cc6527a3914..acfb3d7c4b602cd536999e1c25abac05c772fdd8 100644 (file)
@@ -1498,7 +1498,15 @@ class _CompareMixin(ColumnOperators):
             args.append(o)
 
         if len(args) == 0:
-            # Special case handling for empty IN's, behave like comparison against zero row selectable
+            # Special case handling for empty IN's, behave like comparison 
+            # against zero row selectable.  We use != to build the 
+            # contradiction as it handles NULL values appropriately, i.e.
+            # "not (x IN ())" should not return NULL values for x.
+            util.warn("The IN-predicate on \"%s\" was invoked with an empty sequence. "
+                       "This results in a contradiction, which nonetheless can be "
+                       "expensive to evaluate.  Consider alternative strategies for "
+                       "improved performance." % self)
+                       
             return self != self
 
         return self.__compare(op, ClauseList(*args).self_group(against=op), negate=negate_op)
index 0e1787e9e54b5d83adf27bb96966d1be16b883a2..c711819f96108fecdd045cd88bdfb084978b5b90 100644 (file)
@@ -721,6 +721,7 @@ class QueryTest(TestBase):
         finally:
             shadowed.drop(checkfirst=True)
 
+    @testing.emits_warning('.*empty sequence.*')
     def test_in_filtering(self):
         """test the behavior of the in_() function."""
 
@@ -747,6 +748,7 @@ class QueryTest(TestBase):
         # Null values are not outside any set
         assert len(r) == 0
 
+    @testing.emits_warning('.*empty sequence.*')
     @testing.fails_on('firebird', "kinterbasdb doesn't send full type information")
     def test_bind_in(self):
         users.insert().execute(user_id = 7, user_name = 'jack')
@@ -761,6 +763,7 @@ class QueryTest(TestBase):
         r = s.execute(search_key=None).fetchall()
         assert len(r) == 0
 
+    @testing.emits_warning('.*empty sequence.*')
     @testing.fails_on('firebird', 'FIXME: unknown')
     @testing.fails_on('maxdb', 'FIXME: unknown')
     @testing.fails_on('oracle', 'FIXME: unknown')
index 42998ee02f5d8bb184a329fd3f3c5c6093f91a18..d063bd2d9744883356d896f7ec2f7937c359d1cf 100644 (file)
@@ -1265,6 +1265,7 @@ UNION SELECT mytable.myid FROM mytable"
         
         assert [str(c) for c in s.c] == ["id", "hoho"]
 
+    @testing.emits_warning('.*empty sequence.*')
     def test_in(self):
         self.assert_compile(select([table1], table1.c.myid.in_(['a'])),
         "SELECT mytable.myid, mytable.name, mytable.description FROM mytable WHERE mytable.myid IN (:myid_1)")