From: Mike Bayer Date: Sat, 6 Aug 2011 19:03:33 +0000 (-0400) Subject: - Query will convert an OFFSET of zero when X-Git-Tag: rel_0_7_3~95 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5751eb17f134715d80534531898c091f23cd216b;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Query will convert an OFFSET of zero when 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 --- diff --git a/CHANGES b/CHANGES index 9b8dc256d0..15ed949fc8 100644 --- 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 diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index 3817e60872..015c346eb1 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -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 diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index 437199ac81..cd958d502d 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -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 diff --git a/test/dialect/test_mssql.py b/test/dialect/test_mssql.py index ef5d261959..4cce395b8e 100644 --- a/test/dialect/test_mssql.py +++ b/test/dialect/test_mssql.py @@ -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} ) diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py index 7e95f83efa..5c6d163a5e 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -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."""