]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
dont qualify literal_binds with literal_execute
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 7 Aug 2021 15:02:59 +0000 (11:02 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 7 Aug 2021 16:13:57 +0000 (12:13 -0400)
this appears to be unnecessary and prevents end-user
literal_binds case from working.

Fixed issue where the ``literal_binds`` compiler flag, as used externally
to render bound parameters inline, would fail to work when used with a
certain class of parameters known as "literal_execute", which covers things
like LIMIT and OFFSET values for dialects where the drivers don't allow a
bound parameter, such as SQL Server's "TOP" clause.  The issue locally
seemed to affect only the MSSQL dialect.

Fixes: #6863
Change-Id: Ia74cff5b0107b129a11b9b965883552b2962e449

doc/build/changelog/unreleased_14/6863.rst [new file with mode: 0644]
lib/sqlalchemy/sql/compiler.py
test/dialect/mssql/test_compiler.py
test/dialect/oracle/test_compiler.py
test/sql/test_compiler.py

diff --git a/doc/build/changelog/unreleased_14/6863.rst b/doc/build/changelog/unreleased_14/6863.rst
new file mode 100644 (file)
index 0000000..8dc90c4
--- /dev/null
@@ -0,0 +1,10 @@
+.. change::
+    :tags: bug, mssql, sql
+    :tickets: 6863
+
+    Fixed issue where the ``literal_binds`` compiler flag, as used externally
+    to render bound parameters inline, would fail to work when used with a
+    certain class of parameters known as "literal_execute", which covers things
+    like LIMIT and OFFSET values for dialects where the drivers don't allow a
+    bound parameter, such as SQL Server's "TOP" clause.  The issue locally
+    seemed to affect only the MSSQL dialect.
index a81507acb94415f7f67f9b3656aece679e0ac875..af15de16421a992ee492a5c9af6f70585041386a 100644 (file)
@@ -2297,7 +2297,7 @@ class SQLCompiler(Compiled):
         else:
             post_compile = False
 
-        if not literal_execute and (literal_binds):
+        if literal_binds:
             ret = self.render_literal_bindparam(
                 bindparam, within_columns_clause=True, **kwargs
             )
index c512ae44182b541c936ae1cd984f0bdf0d053dbe..a37eaa21c65d6bedc6f47647e5eb9096993027bb 100644 (file)
@@ -36,6 +36,7 @@ from sqlalchemy.testing import AssertsCompiledSQL
 from sqlalchemy.testing import eq_
 from sqlalchemy.testing import fixtures
 from sqlalchemy.testing import is_
+from sqlalchemy.testing.assertions import eq_ignore_whitespace
 
 tbl = table("t", column("a"))
 
@@ -967,6 +968,22 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
             checkparams={"x_1": 5, "param_1": 10},
         )
 
+    def test_limit_using_top_literal_binds(self):
+        """test #6863"""
+        t = table("t", column("x", Integer), column("y", Integer))
+
+        s = select(t).where(t.c.x == 5).order_by(t.c.y).limit(10)
+
+        eq_ignore_whitespace(
+            str(
+                s.compile(
+                    dialect=mssql.dialect(),
+                    compile_kwargs={"literal_binds": True},
+                )
+            ),
+            "SELECT TOP 10 t.x, t.y FROM t WHERE t.x = 5 ORDER BY t.y",
+        )
+
     def test_limit_zero_using_top(self):
         t = table("t", column("x", Integer), column("y", Integer))
 
index e41a770ed493b851898f627baeac6327ad27c02e..08158eed4707655ed26fae64109ef2202f0f2551 100644 (file)
@@ -36,6 +36,7 @@ from sqlalchemy.testing import assert_raises_message
 from sqlalchemy.testing import AssertsCompiledSQL
 from sqlalchemy.testing import eq_
 from sqlalchemy.testing import fixtures
+from sqlalchemy.testing.assertions import eq_ignore_whitespace
 from sqlalchemy.testing.schema import Column
 from sqlalchemy.testing.schema import Table
 
@@ -173,6 +174,28 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
         eq_(len(c._result_columns), 2)
         assert t.c.col1 in set(c._create_result_map()["col1"][1])
 
+    def test_limit_one_literal_binds(self):
+        """test for #6863.
+
+        the bug does not appear to have affected Oracle's case.
+
+        """
+        t = table("sometable", column("col1"), column("col2"))
+        s = select(t).limit(10).offset(20)
+        c = s.compile(
+            dialect=oracle.OracleDialect(),
+            compile_kwargs={"literal_binds": True},
+        )
+
+        eq_ignore_whitespace(
+            str(c),
+            "SELECT anon_1.col1, anon_1.col2 FROM "
+            "(SELECT anon_2.col1 AS col1, anon_2.col2 AS col2, "
+            "ROWNUM AS ora_rn FROM (SELECT sometable.col1 AS col1, "
+            "sometable.col2 AS col2 FROM sometable) anon_2 "
+            "WHERE ROWNUM <= 10 + 20) anon_1 WHERE ora_rn > 20",
+        )
+
     def test_limit_one_firstrows(self):
         t = table("sometable", column("col1"), column("col2"))
         s = select(t)
index d270218b24346f8fbf9d6fba815415914ae9a278..b150b9f64357278624da77b5be3734ee101677d9 100644 (file)
@@ -4449,6 +4449,24 @@ class BindParameterTest(AssertsCompiledSQL, fixtures.TestBase):
             literal_binds=True,
         )
 
+    def test_render_literal_execute_sent_parameter_literal_binds(self):
+        """test #6863"""
+
+        stmt = select(table1.c.myid).where(
+            table1.c.myid == bindparam("foo", 5, literal_execute=True)
+        )
+        eq_ignore_whitespace(
+            str(
+                stmt.compile(
+                    compile_kwargs={
+                        "literal_binds": True,
+                        "literal_execute": True,
+                    }
+                )
+            ),
+            "SELECT mytable.myid FROM mytable WHERE mytable.myid = 5",
+        )
+
     def test_render_literal_execute_parameter_render_postcompile(self):
         self.assert_compile(
             select(table1.c.myid).where(