]> 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:12:30 +0000 (16:12 -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

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 5d4de4a3389596abff113c1914d6936bcd5e6d24..261ebe5c2850623318f93e421bd2bf1ace5ec345 100644 (file)
@@ -1612,7 +1612,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 6b3244c30bef6b11b1340b64ee1782ce68d2fda6..b0f58563a7b2b118a7aaab7fffa7e5e34c6e7b93 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
@@ -784,6 +785,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 fd093f2707988e4aba86448df656f2fe01e86e88..471e68f4c8b3c329768ec0482bc5bc1c628e74e0 100644 (file)
@@ -627,7 +627,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",
             )