Commit 68629452 authored by Jakub Kania's avatar Jakub Kania
Browse files

MDL-49482 mssql: Implement support of Offset/Fetch in SQL Server 2012+.

parent 3377cbc3
...@@ -40,6 +40,11 @@ class mssql_native_moodle_database extends moodle_database { ...@@ -40,6 +40,11 @@ class mssql_native_moodle_database extends moodle_database {
protected $mssql = null; protected $mssql = null;
protected $last_error_reporting; // To handle mssql driver default verbosity protected $last_error_reporting; // To handle mssql driver default verbosity
protected $collation; // current DB collation cache protected $collation; // current DB collation cache
/**
* Does the used db version support ANSI way of limiting (2012 and higher)
* @var bool
*/
protected $supportsoffsetfetch;
/** /**
* Detects if all needed PHP stuff installed. * Detects if all needed PHP stuff installed.
...@@ -229,6 +234,10 @@ class mssql_native_moodle_database extends moodle_database { ...@@ -229,6 +234,10 @@ class mssql_native_moodle_database extends moodle_database {
$this->free_result($result); $this->free_result($result);
$serverinfo = $this->get_server_info();
// Fetch/offset is supported staring from SQL Server 2012.
$this->supportsoffsetfetch = $serverinfo['version'] > '11';
// Connection stabilised and configured, going to instantiate the temptables controller // Connection stabilised and configured, going to instantiate the temptables controller
$this->temptables = new mssql_native_moodle_temptables($this); $this->temptables = new mssql_native_moodle_temptables($this);
...@@ -737,13 +746,28 @@ class mssql_native_moodle_database extends moodle_database { ...@@ -737,13 +746,28 @@ class mssql_native_moodle_database extends moodle_database {
list($limitfrom, $limitnum) = $this->normalise_limit_from_num($limitfrom, $limitnum); list($limitfrom, $limitnum) = $this->normalise_limit_from_num($limitfrom, $limitnum);
if ($limitfrom or $limitnum) { if ($limitfrom or $limitnum) {
if ($limitnum >= 1) { // Only apply TOP clause if we have any limitnum (limitfrom offset is handled later) if (!$this->supportsoffsetfetch) {
$fetch = $limitfrom + $limitnum; if ($limitnum >= 1) { // Only apply TOP clause if we have any limitnum (limitfrom offset is handled later).
if (PHP_INT_MAX - $limitnum < $limitfrom) { // Check PHP_INT_MAX overflow $fetch = $limitfrom + $limitnum;
$fetch = PHP_INT_MAX; if (PHP_INT_MAX - $limitnum < $limitfrom) { // Check PHP_INT_MAX overflow.
$fetch = PHP_INT_MAX;
}
$sql = preg_replace('/^([\s(])*SELECT([\s]+(DISTINCT|ALL))?(?!\s*TOP\s*\()/i',
"\\1SELECT\\2 TOP $fetch", $sql);
}
} else {
$sql = (substr($sql, -1) === ';') ? substr($sql, 0, -1) : $sql;
// We need order by to use FETCH/OFFSET.
// Ordering by first column shouldn't break anything if there was no order in the first place.
if (!strpos(strtoupper($sql), "ORDER BY")) {
$sql .= " ORDER BY 1";
}
$sql .= " OFFSET ".$limitfrom." ROWS ";
if ($limitnum > 0) {
$sql .= " FETCH NEXT ".$limitnum." ROWS ONLY";
} }
$sql = preg_replace('/^([\s(])*SELECT([\s]+(DISTINCT|ALL))?(?!\s*TOP\s*\()/i',
"\\1SELECT\\2 TOP $fetch", $sql);
} }
} }
...@@ -754,7 +778,7 @@ class mssql_native_moodle_database extends moodle_database { ...@@ -754,7 +778,7 @@ class mssql_native_moodle_database extends moodle_database {
$result = mssql_query($rawsql, $this->mssql); $result = mssql_query($rawsql, $this->mssql);
$this->query_end($result); $this->query_end($result);
if ($limitfrom) { // Skip $limitfrom records if ($limitfrom && !$this->supportsoffsetfetch) { // Skip $limitfrom records.
if (!@mssql_data_seek($result, $limitfrom)) { if (!@mssql_data_seek($result, $limitfrom)) {
// Nothing, most probably seek past the end. // Nothing, most probably seek past the end.
mssql_free_result($result); mssql_free_result($result);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment