]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Interpret empty LIMIT, expression LIMIT correctly
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 9 Nov 2019 21:12:30 +0000 (16:12 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 9 Nov 2019 21:13:13 +0000 (16:13 -0500)
Fixed issue in MSSQL dialect where an expression-based OFFSET value in a
SELECT would be rejected, even though the dialect can render this
expression inside of a ROW NUMBER-oriented LIMIT/OFFSET construct.

Fixes: #4973
Change-Id: I040d34f781791c4ed5a727e1b8fb98c68ddd0622
(cherry picked from commit b3c3562ecf67ae7c94091287504579fcace6a500)

doc/build/changelog/unreleased_13/4973.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mssql/base.py
test/dialect/mssql/test_compiler.py
test/requirements.py

diff --git a/doc/build/changelog/unreleased_13/4973.rst b/doc/build/changelog/unreleased_13/4973.rst
new file mode 100644 (file)
index 0000000..06498e9
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, mssql
+    :tickets: 4973
+
+    Fixed issue in MSSQL dialect where an expression-based OFFSET value in a
+    SELECT would be rejected, even though the dialect can render this
+    expression inside of a ROW NUMBER-oriented LIMIT/OFFSET construct.
+
index 3f468163564f34ab26fc91bee68db38c5c69a3bb..b89f558cdc3588393ff4ef3c109623dd859930e9 100644 (file)
@@ -1598,7 +1598,10 @@ class MSSQLCompiler(compiler.SQLCompiler):
         if select._distinct:
             s += "DISTINCT "
 
-        if select._simple_int_limit and not select._offset:
+        if select._simple_int_limit and (
+            select._offset_clause is None
+            or (select._simple_int_offset and select._offset == 0)
+        ):
             # ODBC drivers and possibly others
             # don't support bind params in the SELECT clause on SQL Server.
             # so have to use literal here.
index eb7ce0ac3d0a60baed2d59dfca8f4c7561ad4503..1865fd589b1ef29e0408658d3a1fa3d872ab8cc5 100644 (file)
@@ -8,6 +8,7 @@ from sqlalchemy import Index
 from sqlalchemy import insert
 from sqlalchemy import Integer
 from sqlalchemy import literal
+from sqlalchemy import literal_column
 from sqlalchemy import MetaData
 from sqlalchemy import PrimaryKeyConstraint
 from sqlalchemy import schema
@@ -782,6 +783,28 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
             eq_(len(c._result_columns), 2)
             assert t.c.x in set(c._create_result_map()["x"][1])
 
+    def test_simple_limit_expression_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(10)
+            .offset(literal_column("20"))
+        )
+
+        self.assert_compile(
+            s,
+            "SELECT anon_1.x, anon_1.y "
+            "FROM (SELECT t.x AS x, t.y 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 > 20 AND mssql_rn <= :param_1 + 20",
+            checkparams={"param_1": 10, "x_1": 5},
+        )
+
     def test_limit_offset_using_window(self):
         t = table("t", column("x", Integer), column("y", Integer))
 
index 1e7c9be7e1b695b808740a470e6b97d82d1974e3..f64ccf53e961e76cccb6be6840d9df5e1a98c559 100644 (file)
@@ -613,7 +613,7 @@ class DefaultRequirements(SuiteRequirements):
     def sql_expression_limit_offset(self):
         return (
             fails_if(
-                ["mysql", "mssql"],
+                ["mysql"],
                 "Target backend can't accommodate full expressions in "
                 "OFFSET or LIMIT",
             )