]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Use _offset_clause and _limit_clause, which are always Visitable and usually a BindPa...
authorDobes Vandermeer <dvandermeer@roovy.com>
Fri, 25 Apr 2014 17:42:12 +0000 (10:42 -0700)
committerDobes Vandermeer <dvandermeer@roovy.com>
Fri, 25 Apr 2014 17:42:12 +0000 (10:42 -0700)
lib/sqlalchemy/dialects/firebird/base.py
lib/sqlalchemy/dialects/mssql/base.py
lib/sqlalchemy/dialects/mysql/base.py
lib/sqlalchemy/dialects/postgresql/base.py
lib/sqlalchemy/dialects/sqlite/base.py
lib/sqlalchemy/sql/compiler.py
lib/sqlalchemy/sql/selectable.py

index fdadb61c1d7db1683fa90b96535891a09a681524..431a16a6e0cc4af090e9f9f568a91a2e0ba18bbe 100644 (file)
@@ -300,10 +300,10 @@ class FBCompiler(sql.compiler.SQLCompiler):
         """
 
         result = ""
-        if select._limit:
-            result += "FIRST %s " % self.process(_literal_as_binds(select._limit))
-        if select._offset:
-            result += "SKIP %s " % self.process(_literal_as_binds(select._offset))
+        if select._limit_clause:
+            result += "FIRST %s " % self.process(select._limit_clause)
+        if select._offset_clause:
+            result += "SKIP %s " % self.process(select._offset_clause)
         if select._distinct:
             result += "DISTINCT "
         return result
index 9a8cddd9887b3c567cb022bcb51d5f030fcf4dff..6a13d1dca97daca59b5f23d3cc7aa3da9b86e201 100644 (file)
@@ -741,15 +741,16 @@ class MSSQLCompiler(compiler.SQLCompiler):
 
     def get_select_precolumns(self, select):
         """ MS-SQL puts TOP, it's version of LIMIT here """
-        if select._distinct or select._limit is not None:
+        limit = select._limit
+        if select._distinct or limit is not None:
             s = select._distinct and "DISTINCT " or ""
 
             # ODBC drivers and possibly others
             # don't support bind params in the SELECT clause on SQL Server.
             # so have to use literal here.
-            if select._limit is not None:
+            if limit is not None:
                 if not select._offset:
-                    s += "TOP %d " % select._limit
+                    s += "TOP %d " % limit
             return s
         return compiler.SQLCompiler.get_select_precolumns(self, select)
 
index ba6e7b62587fc7901316803387f386e1438262a3..4ad45f935196a367796d97371141a0c686b9e0aa 100644 (file)
@@ -1568,15 +1568,15 @@ class MySQLCompiler(compiler.SQLCompiler):
         # The latter is more readable for offsets but we're stuck with the
         # former until we can refine dialects by server revision.
 
-        limit, offset = select._limit, select._offset
+        limit_clause, offset_clause = select._limit_clause, select._offset_clause
 
-        if (limit, offset) == (None, None):
+        if (limit_clause, offset_clause) == (None, None):
             return ''
-        elif offset is not None:
+        elif offset_clause is not None:
             # As suggested by the MySQL docs, need to apply an
             # artificial limit if one wasn't provided
             # http://dev.mysql.com/doc/refman/5.0/en/select.html
-            if limit is None:
+            if limit_clause is None:
                 # hardwire the upper limit.  Currently
                 # needed by OurSQL with Python 3
                 # (https://bugs.launchpad.net/oursql/+bug/686232),
@@ -1584,15 +1584,15 @@ class MySQLCompiler(compiler.SQLCompiler):
                 # bound as part of MySQL's "syntax" for OFFSET with
                 # no LIMIT
                 return ' \n LIMIT %s, %s' % (
-                                self.process(sql.literal(offset)),
+                                self.process(offset_clause),
                                 "18446744073709551615")
             else:
                 return ' \n LIMIT %s, %s' % (
-                                self.process(sql.literal(offset)),
-                                self.process(sql.literal(limit)))
+                                self.process(offset_clause),
+                                self.process(limit_clause))
         else:
             # No offset provided, so just use the limit
-            return ' \n LIMIT %s' % (self.process(sql.literal(limit)),)
+            return ' \n LIMIT %s' % (self.process(limit_clause),)
 
     def update_limit_clause(self, update_stmt):
         limit = update_stmt.kwargs.get('%s_limit' % self.dialect.name, None)
index d63e3ed8791265480828a33c607f030f6b5af844..4e5f9d703f25a580840df7bd5240981122a20f1b 100644 (file)
@@ -1144,12 +1144,12 @@ class PGCompiler(compiler.SQLCompiler):
 
     def limit_clause(self, select):
         text = ""
-        if select._limit is not None:
-            text += " \n LIMIT " + self.process(_literal_as_binds(select._limit))
-        if select._offset is not None:
-            if select._limit is None:
+        if select._limit_clause is not None:
+            text += " \n LIMIT " + self.process(select._limit_clause)
+        if select._offset_clause is not None:
+            if select._limit_clause is None:
                 text += " \n LIMIT ALL"
-            text += " OFFSET " + self.process(_literal_as_binds(select._offset))
+            text += " OFFSET " + self.process(select._offset_clause)
         return text
 
     def format_from_hint_text(self, sqltext, table, hint, iscrud):
index 1ae56523269474922f7aea1a7682970375b4e0db..02582709b536ac69968056ef360bfacef7c61c69 100644 (file)
@@ -520,12 +520,12 @@ class SQLiteCompiler(compiler.SQLCompiler):
 
     def limit_clause(self, select):
         text = ""
-        if select._limit is not None:
-            text += "\n LIMIT " + self.process(_literal_as_binds(select._limit))
-        if select._offset is not None:
-            if select._limit is None:
+        if select._limit_clause is not None:
+            text += "\n LIMIT " + self.process(select._limit_clause)
+        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(_literal_as_binds(select._offset))
+            text += " OFFSET " + self.process(select._offset_clause)
         else:
             text += " OFFSET " + self.process(sql.literal(0))
         return text
index b59e8a941ca00c51d7bbcf75b8b56eab9b4685c5..557ab153166bac73a1fe16ec4a23198186679491 100644 (file)
@@ -774,7 +774,7 @@ class SQLCompiler(Compiled):
             text += " GROUP BY " + group_by
 
         text += self.order_by_clause(cs, **kwargs)
-        text += (cs._limit is not None or cs._offset is not None) and \
+        text += (cs._limit_clause is not None or cs._offset_clause is not None) and \
                         self.limit_clause(cs) or ""
 
         if self.ctes and \
@@ -1557,7 +1557,7 @@ class SQLCompiler(Compiled):
             text += self.order_by_clause(select,
                             order_by_select=order_by_select, **kwargs)
 
-        if select._limit is not None or select._offset is not None:
+        if select._limit_clause is not None or select._offset_clause is not None:
             text += self.limit_clause(select)
 
         if select._for_update_arg is not None:
@@ -1625,12 +1625,12 @@ class SQLCompiler(Compiled):
 
     def limit_clause(self, select):
         text = ""
-        if select._limit is not None:
-            text += "\n LIMIT " + self.process(_literal_as_binds(select._limit))
-        if select._offset is not None:
-            if select._limit is None:
+        if select._limit_clause is not None:
+            text += "\n LIMIT " + self.process(select._limit_clause)
+        if select._offset_clause is not None:
+            if select._limit_clause is None:
                 text += "\n LIMIT -1"
-            text += " OFFSET " + self.process(_literal_as_binds(select._offset))
+            text += " OFFSET " + self.process(select._offset_clause)
         return text
 
     def visit_table(self, table, asfrom=False, iscrud=False, ashint=False,
index 5995c1f8aee24b005207426415341620c9a1465c..46c36e0fc5e938ccc68ee26c7f45a60f920fdda8 100644 (file)
@@ -10,7 +10,7 @@ SQL tables and derived rowsets.
 """
 
 from .elements import ClauseElement, TextClause, ClauseList, \
-        and_, Grouping, UnaryExpression, literal_column
+        and_, Grouping, UnaryExpression, literal_column, _literal_as_binds, BindParameter, Null
 from .elements import _clone, \
         _literal_as_text, _interpret_as_column_or_from, _expand_cloned,\
         _select_iterables, _anonymous_label, _clause_element_as_expr,\
@@ -28,6 +28,8 @@ import operator
 import collections
 from .annotation import Annotated
 import itertools
+from sqlalchemy.sql.visitors import Visitable
+
 
 def _interpret_as_from(element):
     insp = inspection.inspect(element, raiseerr=False)
@@ -46,6 +48,22 @@ def _interpret_as_select(element):
         element = element.select()
     return element
 
+def _offset_or_limit_clause(element, name=None, type_=None):
+    """
+    If the element is a custom clause of some sort, returns (None, element)
+    If the element is a BindParameter, return (element.effective_value, element)
+    Otherwise, assume element is an int and create a new bindparam and return (asint(element), BindParameter(...))
+    """
+    if element is None:
+        return None
+    if hasattr(element, '__clause_element__'):
+        return element.__clause_element__()
+    if isinstance(element, Visitable):
+        return element
+
+    value = util.asint(element)
+    return BindParameter(name, value, type_=type_, unique=True)
+
 def subquery(alias, *args, **kwargs):
     """Return an :class:`.Alias` object derived
     from a :class:`.Select`.
@@ -1536,8 +1554,8 @@ class GenerativeSelect(SelectBase):
     """
     _order_by_clause = ClauseList()
     _group_by_clause = ClauseList()
-    _limit = None
-    _offset = None
+    _limit_clause = None
+    _offset_clause = None
     _for_update_arg = None
 
     def __init__(self,
@@ -1562,9 +1580,9 @@ class GenerativeSelect(SelectBase):
                 self._execution_options.union(
                   {'autocommit': autocommit})
         if limit is not None:
-            self._limit = limit
+            self._limit_clause = _offset_or_limit_clause(limit)
         if offset is not None:
-            self._offset = offset
+            self._offset_clause = _offset_or_limit_clause(offset)
         self._bind = bind
 
         if order_by is not None:
@@ -1639,19 +1657,31 @@ class GenerativeSelect(SelectBase):
         """
         self.use_labels = True
 
+    @property
+    def _limit(self):
+        if not isinstance(self._limit_clause, BindParameter):
+            return None
+        return util.asint(self._limit_clause.effective_value)
+
+    @property
+    def _offset(self):
+        if not isinstance(self._offset_clause, BindParameter):
+            return None
+        return util.asint(self._offset_clause.effective_value)
+
     @_generative
     def limit(self, limit):
         """return a new selectable with the given LIMIT criterion
         applied."""
 
-        self._limit = limit
+        self._limit_clause = _offset_or_limit_clause(limit)
 
     @_generative
     def offset(self, offset):
         """return a new selectable with the given OFFSET criterion
         applied."""
 
-        self._offset = offset
+        self._offset_clause = _offset_or_limit_clause(offset)
 
     @_generative
     def order_by(self, *clauses):
@@ -1713,10 +1743,10 @@ class GenerativeSelect(SelectBase):
 
 
     def _copy_internals(self, clone=_clone, **kw):
-        if isinstance(self._limit, ClauseElement):
-            self._limit = clone(self._limit)
-        if isinstance(self._offset, ClauseElement):
-            self._offset = clone(self._offset)
+        if self._limit_clause is not None:
+            self._limit_clause = clone(self._limit_clause, **kw)
+        if self._offset_clause is not None:
+            self._offset_clause = clone(self._offset_clause, **kw)
 
 class CompoundSelect(GenerativeSelect):
     """Forms the basis of ``UNION``, ``UNION ALL``, and other