Commit 81dd0b7a authored by Sergei Morozov's avatar Sergei Morozov

Handle arbitrary whitespaces when parsing SQL in order to apply LIMIT for MS SQL Server

parent a6d3d162
...@@ -117,7 +117,7 @@ class SQLServer2012Platform extends SQLServer2008Platform ...@@ -117,7 +117,7 @@ class SQLServer2012Platform extends SQLServer2008Platform
// Find the position of the last instance of ORDER BY and ensure it is not within a parenthetical statement // Find the position of the last instance of ORDER BY and ensure it is not within a parenthetical statement
// but can be in a newline // but can be in a newline
$matches = array(); $matches = array();
$matchesCount = preg_match_all("/[\\s]+order by /i", $query, $matches, PREG_OFFSET_CAPTURE); $matchesCount = preg_match_all("/[\\s]+order\\s+by\\s/im", $query, $matches, PREG_OFFSET_CAPTURE);
$orderByPos = false; $orderByPos = false;
if ($matchesCount > 0) { if ($matchesCount > 0) {
$orderByPos = $matches[0][($matchesCount - 1)][1]; $orderByPos = $matches[0][($matchesCount - 1)][1];
...@@ -126,7 +126,7 @@ class SQLServer2012Platform extends SQLServer2008Platform ...@@ -126,7 +126,7 @@ class SQLServer2012Platform extends SQLServer2008Platform
if ($orderByPos === false if ($orderByPos === false
|| substr_count($query, "(", $orderByPos) - substr_count($query, ")", $orderByPos) || substr_count($query, "(", $orderByPos) - substr_count($query, ")", $orderByPos)
) { ) {
if (stripos($query, 'SELECT DISTINCT') === 0) { if (preg_match('/^SELECT\s+DISTINCT/im', $query)) {
// SQL Server won't let us order by a non-selected column in a DISTINCT query, // SQL Server won't let us order by a non-selected column in a DISTINCT query,
// so we have to do this madness. This says, order by the first column in the // so we have to do this madness. This says, order by the first column in the
// result. SQL Server's docs say that a nonordered query's result order is non- // result. SQL Server's docs say that a nonordered query's result order is non-
......
...@@ -1192,7 +1192,7 @@ class SQLServerPlatform extends AbstractPlatform ...@@ -1192,7 +1192,7 @@ class SQLServerPlatform extends AbstractPlatform
// Even if the TOP n is very large, the use of a CTE will // Even if the TOP n is very large, the use of a CTE will
// allow the SQL Server query planner to optimize it so it doesn't // allow the SQL Server query planner to optimize it so it doesn't
// actually scan the entire range covered by the TOP clause. // actually scan the entire range covered by the TOP clause.
$selectPattern = '/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/i'; $selectPattern = '/^(\s*SELECT\s+(?:DISTINCT\s+)?)(.*)$/im';
$replacePattern = sprintf('$1%s $2', "TOP $end"); $replacePattern = sprintf('$1%s $2', "TOP $end");
$query = preg_replace($selectPattern, $replacePattern, $query); $query = preg_replace($selectPattern, $replacePattern, $query);
......
...@@ -124,6 +124,26 @@ class ModifyLimitQueryTest extends \Doctrine\Tests\DbalFunctionalTestCase ...@@ -124,6 +124,26 @@ class ModifyLimitQueryTest extends \Doctrine\Tests\DbalFunctionalTestCase
$this->assertLimitResult(array(2, 1), $sql, 2, 2); $this->assertLimitResult(array(2, 1), $sql, 2, 2);
} }
public function testModifyLimitQueryLineBreaks()
{
$this->_conn->insert('modify_limit_table', array('test_int' => 1));
$this->_conn->insert('modify_limit_table', array('test_int' => 2));
$this->_conn->insert('modify_limit_table', array('test_int' => 3));
$sql = <<<SQL
SELECT
*
FROM
modify_limit_table
ORDER
BY
test_int
ASC
SQL;
$this->assertLimitResult(array(2), $sql, 1, 1);
}
public function assertLimitResult($expectedResults, $sql, $limit, $offset, $deterministic = true) public function assertLimitResult($expectedResults, $sql, $limit, $offset, $deterministic = true)
{ {
$p = $this->_conn->getDatabasePlatform(); $p = $this->_conn->getDatabasePlatform();
......
Markdown is supported
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