Skip to content

Commit

Permalink
Process LIMIT and OFFSET individually by using >= and <= instead of B…
Browse files Browse the repository at this point in the history
…ETWEEN
  • Loading branch information
morozov authored and deeky666 committed Jan 16, 2017
1 parent b9a3b08 commit 0f7bf0c
Show file tree
Hide file tree
Showing 3 changed files with 30 additions and 12 deletions.
24 changes: 16 additions & 8 deletions lib/Doctrine/DBAL/Platforms/DB2Platform.php
Original file line number Diff line number Diff line change
Expand Up @@ -772,18 +772,26 @@ public function getTemporaryTableName($tableName)
*/
protected function doModifyLimitQuery($query, $limit, $offset = null)
{
if ($limit === null && $offset === null) {
return $query;
$where = array();

if ($offset > 0) {
$where[] = sprintf('db22.DC_ROWNUM >= %d', $offset + 1);
}

$limit = (int) $limit;
$offset = (int) (($offset)?:0);
if ($limit !== null) {
$where[] = sprintf('db22.DC_ROWNUM <= %d', $offset + $limit);
}

// Todo OVER() needs ORDER BY data!
$sql = 'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM '.
'FROM (' . $query . ') db21) db22 WHERE db22.DC_ROWNUM BETWEEN ' . ($offset+1) .' AND ' . ($offset+$limit);
if (empty($where)) {
return $query;
}

return $sql;
// Todo OVER() needs ORDER BY data!
return sprintf(
'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (%s) db21) db22 WHERE %s',
$query,
implode(' AND ', $where)
);
}

/**
Expand Down
10 changes: 10 additions & 0 deletions tests/Doctrine/Tests/DBAL/Functional/ModifyLimitQueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,16 @@ public function testModifyLimitQuerySubSelect()
$this->assertLimitResult(array(2, 1), $sql, 2, 2, false);
}

public function testModifyLimitQueryZeroOffsetNoLimit()
{
$this->_conn->insert('modify_limit_table', array('test_int' => 1));
$this->_conn->insert('modify_limit_table', array('test_int' => 2));

$sql = "SELECT test_int FROM modify_limit_table ORDER BY test_int ASC";

$this->assertLimitResult(array(1, 2), $sql, null, 0);
}

public function assertLimitResult($expectedResults, $sql, $limit, $offset, $deterministic = true)
{
$p = $this->_conn->getDatabasePlatform();
Expand Down
8 changes: 4 additions & 4 deletions tests/Doctrine/Tests/DBAL/Platforms/DB2PlatformTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -358,21 +358,21 @@ public function testModifiesLimitQuery()
);

$this->assertEquals(
'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM BETWEEN 1 AND 10',
'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM <= 10',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 0)
);

$this->assertEquals(
'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM BETWEEN 1 AND 10',
'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM <= 10',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 10)
);

$this->assertEquals(
'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM BETWEEN 6 AND 15',
'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM >= 6 AND db22.DC_ROWNUM <= 15',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 10, 5)
);
$this->assertEquals(
'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM BETWEEN 6 AND 5',
'SELECT db22.* FROM (SELECT db21.*, ROW_NUMBER() OVER() AS DC_ROWNUM FROM (SELECT * FROM user) db21) db22 WHERE db22.DC_ROWNUM >= 6 AND db22.DC_ROWNUM <= 5',
$this->_platform->modifyLimitQuery('SELECT * FROM user', 0, 5)
);
}
Expand Down

0 comments on commit 0f7bf0c

Please sign in to comment.