return text
def limit_clause(self, select, **kw):
- # Limit in mssql is after the select keyword
- return ""
+ """ MSSQL 2012 supports OFFSET/FETCH operators
+ Use it instead subquery with row_number
+
+ """
+
+ if self.dialect._supports_offset_fetch and (
+ (
+ not select._simple_int_limit
+ and select._limit_clause is not None
+ )
+ or (
+ select._offset_clause is not None
+ and not select._simple_int_offset
+ or select._offset
+ )
+ ):
+ # OFFSET are FETCH are options of the ORDER BY clause
+ if not select._order_by_clause.clauses:
+ raise exc.CompileError(
+ "MSSQL requires an order_by when "
+ "using an OFFSET or a non-simple "
+ "LIMIT clause"
+ )
+
+ text = ""
+
+ if select._offset_clause is not None:
+ offset_str = self.process(select._offset_clause, **kw)
+ else:
+ offset_str = '0'
+ text += "\n OFFSET %s ROWS" % offset_str
+
+ if select._limit_clause is not None:
+ text += "\n FETCH NEXT %s ROWS ONLY " % self.process(
+ select._limit_clause, **kw
+ )
+ return text
+ else:
+ return ""
def visit_try_cast(self, element, **kw):
return "TRY_CAST (%s AS %s)" % (
def visit_select(self, select, **kwargs):
"""Look for ``LIMIT`` and OFFSET in a select statement, and if
so tries to wrap it in a subquery with ``row_number()`` criterion.
+ MSSQL 2012 and above are excluded
"""
- if (
+ if not self.dialect._supports_offset_fetch and (
(not select._simple_int_limit and select._limit_clause is not None)
or (
select._offset_clause is not None
non_native_boolean_check_constraint = False
supports_unicode_binds = True
postfetch_lastrowid = True
+ _supports_offset_fetch = False
server_version_info = ()
self.server_version_info >= MS_2012_VERSION
)
+ self._supports_offset_fetch = (
+ self.server_version_info and self.server_version_info[0] >= 11)
+
def _get_default_schema_name(self, connection):
if self.server_version_info < MS_2005_VERSION:
return self.schema_name
assert t.c.x in set(c._create_result_map()["x"][1])
assert t.c.y in set(c._create_result_map()["y"][1])
+ def test_limit_offset_using_offset_fetch(self):
+ t = table("t", column("x", Integer), column("y", Integer))
+ dialect_2012 = mssql.base.MSDialect()
+ dialect_2012._supports_offset_fetch = True
+
+ s = select([t]).where(t.c.x == 5).order_by(t.c.y).limit(10).offset(20)
+
+ self.assert_compile(
+ s,
+ "SELECT t.x, t.y "
+ "FROM t "
+ "WHERE t.x = :x_1 ORDER BY t.y "
+ "OFFSET :param_1 ROWS "
+ "FETCH NEXT :param_2 ROWS ONLY ",
+ checkparams={"param_1": 20, "param_2": 10, "x_1": 5},
+ dialect=dialect_2012
+ )
+
+ c = s.compile(dialect=dialect_2012)
+ eq_(len(c._result_columns), 2)
+ assert t.c.x in set(c._create_result_map()["x"][1])
+ assert t.c.y in set(c._create_result_map()["y"][1])
+
def test_limit_offset_w_ambiguous_cols(self):
t = table("t", column("x", Integer), column("y", Integer))