]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- ensure literal_binds works with LIMIT clause, FOR UPDATE
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 3 Sep 2014 23:42:38 +0000 (19:42 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 3 Sep 2014 23:42:38 +0000 (19:42 -0400)
doc/build/changelog/changelog_10.rst
lib/sqlalchemy/dialects/mssql/base.py
lib/sqlalchemy/dialects/mysql/base.py
lib/sqlalchemy/dialects/oracle/base.py
lib/sqlalchemy/dialects/postgresql/base.py
lib/sqlalchemy/dialects/sqlite/base.py
lib/sqlalchemy/dialects/sybase/base.py
lib/sqlalchemy/sql/compiler.py
lib/sqlalchemy/testing/suite/test_select.py
test/sql/test_compiler.py

index 715936068c117a9b4d2b0fce68359a0a686049f7..e9b78fe78663c9fb951a726ae186e45c98ab60b1 100644 (file)
                here is fully backwards compatible with existing third party dialects,
                however those dialects which implement special LIMIT/OFFSET systems
                will need modification in order to take advantage of the new
-               capabilities.  Work on this feature is courtesy of Dobes Vandermeer.
+               capabilities.  Limit and offset also support "literal_binds" mode,
+        where bound parameters are rendered inline as strings based on
+        a compile-time option.
+        Work on this feature is courtesy of Dobes Vandermeer.
+
 
                .. seealso::
 
index d1d4cb9ca6115b8ee13da9d2b8391ca8826a820d..ba3050ae5d9e7b6b2df209b5f8ab78acd59fe329 100644 (file)
@@ -924,7 +924,7 @@ class MSSQLCompiler(compiler.SQLCompiler):
     def get_crud_hint_text(self, table, text):
         return text
 
-    def limit_clause(self, select):
+    def limit_clause(self, select, **kw):
         # Limit in mssql is after the select keyword
         return ""
 
index 012d178e7bf08d2ee577be3f0b6cc2a87d4a0f89..4dccd2760eb3059be120277e39bef7225dd098ce 100644 (file)
@@ -1662,13 +1662,13 @@ class MySQLCompiler(compiler.SQLCompiler):
              " ON ",
              self.process(join.onclause, **kwargs)))
 
-    def for_update_clause(self, select):
+    def for_update_clause(self, select, **kw):
         if select._for_update_arg.read:
             return " LOCK IN SHARE MODE"
         else:
             return " FOR UPDATE"
 
-    def limit_clause(self, select):
+    def limit_clause(self, select, **kw):
         # MySQL supports:
         #   LIMIT <limit>
         #   LIMIT <offset>, <limit>
@@ -1694,15 +1694,15 @@ class MySQLCompiler(compiler.SQLCompiler):
                 # bound as part of MySQL's "syntax" for OFFSET with
                 # no LIMIT
                 return ' \n LIMIT %s, %s' % (
-                    self.process(offset_clause),
+                    self.process(offset_clause, **kw),
                     "18446744073709551615")
             else:
                 return ' \n LIMIT %s, %s' % (
-                    self.process(offset_clause),
-                    self.process(limit_clause))
+                    self.process(offset_clause, **kw),
+                    self.process(limit_clause, **kw))
         else:
             # No offset provided, so just use the limit
-            return ' \n LIMIT %s' % (self.process(limit_clause),)
+            return ' \n LIMIT %s' % (self.process(limit_clause, **kw),)
 
     def update_limit_clause(self, update_stmt):
         limit = update_stmt.kwargs.get('%s_limit' % self.dialect.name, None)
index 40ba051f7f618603b881bbbb972f4df962022850..81a9f1a957618b1c96ac17d375f7702fc5e23987 100644 (file)
@@ -740,10 +740,10 @@ class OracleCompiler(compiler.SQLCompiler):
         kwargs['iswrapper'] = getattr(select, '_is_wrapper', False)
         return compiler.SQLCompiler.visit_select(self, select, **kwargs)
 
-    def limit_clause(self, select):
+    def limit_clause(self, select, **kw):
         return ""
 
-    def for_update_clause(self, select):
+    def for_update_clause(self, select, **kw):
         if self.is_subquery():
             return ""
 
@@ -751,7 +751,7 @@ class OracleCompiler(compiler.SQLCompiler):
 
         if select._for_update_arg.of:
             tmp += ' OF ' + ', '.join(
-                self.process(elem) for elem in
+                self.process(elem, **kw) for elem in
                 select._for_update_arg.of
             )
 
index f1418f90357c91902fe9e548ecea4851ad3607f1..575d2a6ddde2b8bc5db761fc47ea7b4dcc01c5a5 100644 (file)
@@ -1309,14 +1309,14 @@ class PGCompiler(compiler.SQLCompiler):
     def visit_sequence(self, seq):
         return "nextval('%s')" % self.preparer.format_sequence(seq)
 
-    def limit_clause(self, select):
+    def limit_clause(self, select, **kw):
         text = ""
         if select._limit_clause is not None:
-            text += " \n LIMIT " + self.process(select._limit_clause)
+            text += " \n LIMIT " + self.process(select._limit_clause, **kw)
         if select._offset_clause is not None:
             if select._limit_clause is None:
                 text += " \n LIMIT ALL"
-            text += " OFFSET " + self.process(select._offset_clause)
+            text += " OFFSET " + self.process(select._offset_clause, **kw)
         return text
 
     def format_from_hint_text(self, sqltext, table, hint, iscrud):
@@ -1337,7 +1337,7 @@ class PGCompiler(compiler.SQLCompiler):
         else:
             return ""
 
-    def for_update_clause(self, select):
+    def for_update_clause(self, select, **kw):
 
         if select._for_update_arg.read:
             tmp = " FOR SHARE"
@@ -1349,7 +1349,7 @@ class PGCompiler(compiler.SQLCompiler):
                 c.table if isinstance(c, expression.ColumnClause)
                 else c for c in select._for_update_arg.of)
             tmp += " OF " + ", ".join(
-                self.process(table, ashint=True)
+                self.process(table, ashint=True, **kw)
                 for table in tables
             )
 
index 3c8b2d4f7e8bafc2942a69de84af52ce80f4c224..af793d27575c8d39da36db1cd9a814ae54e53789 100644 (file)
@@ -591,19 +591,19 @@ class SQLiteCompiler(compiler.SQLCompiler):
             raise exc.CompileError(
                 "%s is not a valid extract argument." % extract.field)
 
-    def limit_clause(self, select):
+    def limit_clause(self, select, **kw):
         text = ""
         if select._limit_clause is not None:
-            text += "\n LIMIT " + self.process(select._limit_clause)
+            text += "\n LIMIT " + self.process(select._limit_clause, **kw)
         if select._offset_clause is not None:
             if select._limit_clause is None:
                 text += "\n LIMIT " + self.process(sql.literal(-1))
-            text += " OFFSET " + self.process(select._offset_clause)
+            text += " OFFSET " + self.process(select._offset_clause, **kw)
         else:
-            text += " OFFSET " + self.process(sql.literal(0))
+            text += " OFFSET " + self.process(sql.literal(0), **kw)
         return text
 
-    def for_update_clause(self, select):
+    def for_update_clause(self, select, **kw):
         # sqlite has no "FOR UPDATE" AFAICT
         return ''
 
index 26f5ef04ac56f0851e3bf1329255de737420c32d..f65a76a271cbb9e36d4d16c7febe1a03038f35b0 100644 (file)
@@ -346,7 +346,7 @@ class SybaseSQLCompiler(compiler.SQLCompiler):
     def get_from_hint_text(self, table, text):
         return text
 
-    def limit_clause(self, select):
+    def limit_clause(self, select, **kw):
         # Limit in sybase is after the select keyword
         return ""
 
index 23e5456a7dbeea2c5189d5e697977c5773cc6d8f..e9252062084841c90ba3e4284e3f0b63d7590a78 100644 (file)
@@ -1593,10 +1593,10 @@ class SQLCompiler(Compiled):
 
         if (select._limit_clause is not None or
                 select._offset_clause is not None):
-            text += self.limit_clause(select)
+            text += self.limit_clause(select, **kwargs)
 
         if select._for_update_arg is not None:
-            text += self.for_update_clause(select)
+            text += self.for_update_clause(select, **kwargs)
 
         if self.ctes and \
                 compound_index == 0 and toplevel:
@@ -1653,7 +1653,7 @@ class SQLCompiler(Compiled):
         else:
             return ""
 
-    def for_update_clause(self, select):
+    def for_update_clause(self, select, **kw):
         return " FOR UPDATE"
 
     def returning_clause(self, stmt, returning_cols):
@@ -1661,14 +1661,14 @@ class SQLCompiler(Compiled):
             "RETURNING is not supported by this "
             "dialect's statement compiler.")
 
-    def limit_clause(self, select):
+    def limit_clause(self, select, **kw):
         text = ""
         if select._limit_clause is not None:
-            text += "\n LIMIT " + self.process(select._limit_clause)
+            text += "\n LIMIT " + self.process(select._limit_clause, **kw)
         if select._offset_clause is not None:
             if select._limit_clause is None:
                 text += "\n LIMIT -1"
-            text += " OFFSET " + self.process(select._offset_clause)
+            text += " OFFSET " + self.process(select._offset_clause, **kw)
         return text
 
     def visit_table(self, table, asfrom=False, iscrud=False, ashint=False,
index 3f14ada053a5c35a584cef3187b7dd64421e6abd..68dadd0a9144fbd3d537b49f72cd6dff89222935 100644 (file)
@@ -136,6 +136,21 @@ class LimitOffsetTest(fixtures.TablesTest):
             [(2, 2, 3), (3, 3, 4)]
         )
 
+    def test_limit_offset_nobinds(self):
+        """test that 'literal binds' mode works - no bound params."""
+
+        table = self.tables.some_table
+        stmt = select([table]).order_by(table.c.id).limit(2).offset(1)
+        sql = stmt.compile(
+            dialect=config.db.dialect,
+            compile_kwargs={"literal_binds": True})
+        sql = str(sql)
+
+        self._assert_result(
+            sql,
+            [(2, 2, 3), (3, 3, 4)]
+        )
+
     @testing.requires.bound_limit_offset
     def test_bound_limit(self):
         table = self.tables.some_table
index 4977611c53b09198210b35f7c76341a5bb9a38be..4f8ced72c00c2b0c73274e1c5814d0864d262f94 100644 (file)
@@ -256,7 +256,7 @@ class SelectTest(fixtures.TestBase, AssertsCompiledSQL):
                             select._offset))
                 return result
 
-            def limit_clause(self, select):
+            def limit_clause(self, select, **kw):
                 return ""
 
         dialect = default.DefaultDialect()