diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-09-03 19:42:38 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2014-09-03 19:42:38 -0400 |
commit | 2b10aa45a101acfcc6090a3801af998ef8fc1a2d (patch) | |
tree | 60329bc3771b31910eb3d1e51412525ed4222066 | |
parent | 4399431b53e5d132672431205c654d7d6b32dd77 (diff) | |
download | sqlalchemy-2b10aa45a101acfcc6090a3801af998ef8fc1a2d.tar.gz |
- ensure literal_binds works with LIMIT clause, FOR UPDATE
-rw-r--r-- | doc/build/changelog/changelog_10.rst | 6 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/mssql/base.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/mysql/base.py | 12 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/oracle/base.py | 6 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/postgresql/base.py | 10 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/sqlite/base.py | 10 | ||||
-rw-r--r-- | lib/sqlalchemy/dialects/sybase/base.py | 2 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/compiler.py | 12 | ||||
-rw-r--r-- | lib/sqlalchemy/testing/suite/test_select.py | 15 | ||||
-rw-r--r-- | test/sql/test_compiler.py | 2 |
10 files changed, 48 insertions, 29 deletions
diff --git a/doc/build/changelog/changelog_10.rst b/doc/build/changelog/changelog_10.rst index 715936068..e9b78fe78 100644 --- a/doc/build/changelog/changelog_10.rst +++ b/doc/build/changelog/changelog_10.rst @@ -375,7 +375,11 @@ 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:: diff --git a/lib/sqlalchemy/dialects/mssql/base.py b/lib/sqlalchemy/dialects/mssql/base.py index d1d4cb9ca..ba3050ae5 100644 --- a/lib/sqlalchemy/dialects/mssql/base.py +++ b/lib/sqlalchemy/dialects/mssql/base.py @@ -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 "" diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index 012d178e7..4dccd2760 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -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) diff --git a/lib/sqlalchemy/dialects/oracle/base.py b/lib/sqlalchemy/dialects/oracle/base.py index 40ba051f7..81a9f1a95 100644 --- a/lib/sqlalchemy/dialects/oracle/base.py +++ b/lib/sqlalchemy/dialects/oracle/base.py @@ -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 ) diff --git a/lib/sqlalchemy/dialects/postgresql/base.py b/lib/sqlalchemy/dialects/postgresql/base.py index f1418f903..575d2a6dd 100644 --- a/lib/sqlalchemy/dialects/postgresql/base.py +++ b/lib/sqlalchemy/dialects/postgresql/base.py @@ -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 ) diff --git a/lib/sqlalchemy/dialects/sqlite/base.py b/lib/sqlalchemy/dialects/sqlite/base.py index 3c8b2d4f7..af793d275 100644 --- a/lib/sqlalchemy/dialects/sqlite/base.py +++ b/lib/sqlalchemy/dialects/sqlite/base.py @@ -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 '' diff --git a/lib/sqlalchemy/dialects/sybase/base.py b/lib/sqlalchemy/dialects/sybase/base.py index 26f5ef04a..f65a76a27 100644 --- a/lib/sqlalchemy/dialects/sybase/base.py +++ b/lib/sqlalchemy/dialects/sybase/base.py @@ -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 "" diff --git a/lib/sqlalchemy/sql/compiler.py b/lib/sqlalchemy/sql/compiler.py index 23e5456a7..e92520620 100644 --- a/lib/sqlalchemy/sql/compiler.py +++ b/lib/sqlalchemy/sql/compiler.py @@ -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, diff --git a/lib/sqlalchemy/testing/suite/test_select.py b/lib/sqlalchemy/testing/suite/test_select.py index 3f14ada05..68dadd0a9 100644 --- a/lib/sqlalchemy/testing/suite/test_select.py +++ b/lib/sqlalchemy/testing/suite/test_select.py @@ -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 diff --git a/test/sql/test_compiler.py b/test/sql/test_compiler.py index 4977611c5..4f8ced72c 100644 --- a/test/sql/test_compiler.py +++ b/test/sql/test_compiler.py @@ -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() |