]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- Query will convert an OFFSET of zero when
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 6 Aug 2011 19:03:33 +0000 (15:03 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 6 Aug 2011 19:03:33 +0000 (15:03 -0400)
slicing into None, so that needless OFFSET
clauses are not invoked.
- mssql: "0" is accepted as an argument for limit() which
will produce "TOP 0". [ticket:2222]
- add tests to default compiler test for LIMIT/OFFSET generation

CHANGES
lib/sqlalchemy/dialects/mssql/base.py
lib/sqlalchemy/orm/query.py
test/dialect/test_mssql.py
test/sql/test_compiler.py

diff --git a/CHANGES b/CHANGES
index 9b8dc256d0e5f527a324150d49c28424fc7edbc1..15ed949fc85c2f1ec9c7ef14c4d9cfe82c03c7da 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -21,6 +21,10 @@ CHANGES
     twice.  Thanks *much* to Dave Vitek 
     for the excellent fix here.  [ticket:2247]
 
+  - Query will convert an OFFSET of zero when
+    slicing into None, so that needless OFFSET
+    clauses are not invoked.
+
 - sqlite
   - Ensured that the same ValueError is raised for
     illegal date/time/datetime string parsed from
@@ -32,6 +36,10 @@ CHANGES
     source for server side cursor names; 
     conflicts have been reported in rare cases.
 
+- mssql
+  - "0" is accepted as an argument for limit() which
+    will produce "TOP 0". [ticket:2222]
+
 - ext
   - Added local_attr, remote_attr, attr accessors
     to AssociationProxy, providing quick access
index 3817e6087216c79129454fc6b716388663ae9750..015c346eb111f234ba9e47cedc28e58f68471c59 100644 (file)
@@ -754,13 +754,13 @@ class MSSQLCompiler(compiler.SQLCompiler):
 
     def get_select_precolumns(self, select):
         """ MS-SQL puts TOP, it's version of LIMIT here """
-        if select._distinct or select._limit:
+        if select._distinct or select._limit is not None:
             s = select._distinct and "DISTINCT " or ""
 
             # ODBC drivers and possibly others
             # don't support bind params in the SELECT clause on SQL Server.
             # so have to use literal here.
-            if select._limit:
+            if select._limit is not None:
                 if not select._offset:
                     s += "TOP %d " % select._limit
             return s
index 437199ac81f18171033414db4e1de40a397e5506..cd958d502dec2bd8b003e525908c331ef0148f48 100644 (file)
@@ -1859,6 +1859,9 @@ class Query(object):
         elif start is not None and stop is None:
             self._offset = (self._offset or 0) + start
 
+        if self._offset == 0:
+            self._offset = None
+
     @_generative(_no_statement_condition)
     def limit(self, limit):
         """Apply a ``LIMIT`` to the query and return the newly resulting
index ef5d26195930af3c99639ccc8c268329ea735240..4cce395b8e974d7d724f713644e78a72297e0aa3 100644 (file)
@@ -287,7 +287,18 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
         self.assert_compile(
             s,
             "SELECT TOP 10 t.x, t.y FROM t WHERE t.x = :x_1 ORDER BY t.y",
-            {u'x_1': 5}
+            checkparams={u'x_1': 5}
+        )
+
+    def test_limit_zero_using_top(self):
+        t = table('t', column('x', Integer), column('y', Integer))
+
+        s = select([t]).where(t.c.x==5).order_by(t.c.y).limit(0)
+
+        self.assert_compile(
+            s,
+            "SELECT TOP 0 t.x, t.y FROM t WHERE t.x = :x_1 ORDER BY t.y",
+            checkparams={u'x_1': 5}
         )
 
     def test_offset_using_window(self):
@@ -301,7 +312,7 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
             "AS y, ROW_NUMBER() OVER (ORDER BY t.y) AS "
             "mssql_rn FROM t WHERE t.x = :x_1) AS "
             "anon_1 WHERE mssql_rn > :mssql_rn_1",
-            {u'mssql_rn_1': 20, u'x_1': 5}
+            checkparams={u'mssql_rn_1': 20, u'x_1': 5}
         )
 
     def test_limit_offset_using_window(self):
@@ -317,7 +328,21 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
             "FROM t "
             "WHERE t.x = :x_1) AS anon_1 "
             "WHERE mssql_rn > :mssql_rn_1 AND mssql_rn <= :mssql_rn_2",
-            {u'mssql_rn_1': 20, u'mssql_rn_2': 30, u'x_1': 5}
+            checkparams={u'mssql_rn_1': 20, u'mssql_rn_2': 30, u'x_1': 5}
+        )
+
+    def test_limit_zero_offset_using_window(self):
+        t = table('t', column('x', Integer), column('y', Integer))
+
+        s = select([t]).where(t.c.x==5).order_by(t.c.y).limit(0).offset(0)
+
+        # render the LIMIT of zero, but not the OFFSET
+        # of zero, so produces TOP 0
+        self.assert_compile(
+            s,
+            "SELECT TOP 0 t.x, t.y FROM t "
+            "WHERE t.x = :x_1 ORDER BY t.y",
+            checkparams={u'x_1': 5}
         )
 
 
index 7e95f83efa811142af428e668cd74141a59ea275..5c6d163a5effe55ced31b9764a8e4e42ec476a33 100644 (file)
@@ -124,6 +124,21 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL):
         assert_raises(ValueError, select, offset="foo")
         assert_raises(ValueError, select, limit="foo")
 
+    def test_limit_offset(self):
+        for lim, offset, exp, params in [
+            (5, 10, "LIMIT :param_1 OFFSET :param_2", 
+                                {'param_1':5, 'param_2':10}),
+            (None, 10, "LIMIT -1 OFFSET :param_1", {'param_1':10}),
+            (5, None, "LIMIT :param_1", {'param_1':5}),
+            (0, 0, "LIMIT :param_1 OFFSET :param_2", 
+                                {'param_1':0, 'param_2':0}),
+        ]:
+            self.assert_compile(
+                select([1]).limit(lim).offset(offset),
+                "SELECT 1 " + exp,
+                checkparams =params
+            )
+
     def test_from_subquery(self):
         """tests placing select statements in the column clause of another select, for the
         purposes of selecting from the exported columns of that select."""