summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2014-09-03 19:42:38 -0400
committerMike Bayer <mike_mp@zzzcomputing.com>2014-09-03 19:42:38 -0400
commit2b10aa45a101acfcc6090a3801af998ef8fc1a2d (patch)
tree60329bc3771b31910eb3d1e51412525ed4222066
parent4399431b53e5d132672431205c654d7d6b32dd77 (diff)
downloadsqlalchemy-2b10aa45a101acfcc6090a3801af998ef8fc1a2d.tar.gz
- ensure literal_binds works with LIMIT clause, FOR UPDATE
-rw-r--r--doc/build/changelog/changelog_10.rst6
-rw-r--r--lib/sqlalchemy/dialects/mssql/base.py2
-rw-r--r--lib/sqlalchemy/dialects/mysql/base.py12
-rw-r--r--lib/sqlalchemy/dialects/oracle/base.py6
-rw-r--r--lib/sqlalchemy/dialects/postgresql/base.py10
-rw-r--r--lib/sqlalchemy/dialects/sqlite/base.py10
-rw-r--r--lib/sqlalchemy/dialects/sybase/base.py2
-rw-r--r--lib/sqlalchemy/sql/compiler.py12
-rw-r--r--lib/sqlalchemy/testing/suite/test_select.py15
-rw-r--r--test/sql/test_compiler.py2
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()