Skip to content
This repository has been archived by the owner on Jan 29, 2020. It is now read-only.

Add support for LIMIT OFFSET for db2 #275

Merged
merged 5 commits into from Nov 23, 2017
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
41 changes: 40 additions & 1 deletion src/Sql/Platform/IbmDb2/SelectDecorator.php
Expand Up @@ -27,7 +27,13 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface
*/
protected $subject = null;

/**
/**
* @var bool
*/
protected $supportsLimitOffset = false;


/**
* @return bool
*/
public function getIsSelectContainDistinct()
Expand All @@ -51,6 +57,22 @@ public function setSubject($select)
$this->subject = $select;
}

/**
* @return bool
*/
public function getSupportsLimitOffset()
{
return $this->supportsLimitOffset;
}

/**
* @param bool $supportsLimitOffset
*/
public function setSupportsLimitOffset($supportsLimitOffset)
{
$this->supportsLimitOffset = $supportsLimitOffset;
}

/**
* @see Select::renderTable
*/
Expand Down Expand Up @@ -82,6 +104,23 @@ protected function processLimitOffset(PlatformInterface $platform, DriverInterfa
return;
}

if ($this->supportsLimitOffset) {
// Note: db2_prepare/db2_execute fails with positional parameters, for LIMIT & OFFSET
$limit = (int)$this->limit;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space after the cast.

if (! $limit) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

no space after the !

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

most of zf code has space after !, I think already part of zf cs /cc @webimpress

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mwillbanks
@samsonasik is right. See zendframework/zend-coding-standard#1 - Generic.Formatting.SpaceAfterNot

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mwillbanks
Yes, and this is even part of current version of zend-coding-standard (1.0.0): https://github.com/zendframework/zend-coding-standard/blob/master/ruleset.xml#L12

return;
}

$offset = (int)$this->offset;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

space after the cast.

if ($offset) {
array_push($sqls, sprintf("LIMIT %s OFFSET %s", $limit, $offset));
return;
}

array_push($sqls, sprintf("LIMIT %s", $limit));
return;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think deep if can be simplified with return early:

if (! $this->limit) {
    return;
}

if ($this->offset) {
    array_push($sqls, sprintf("LIMIT %s OFFSET %s", $limit, $offset));
    return; 
}

array_push($sqls, sprintf("LIMIT %s", $limit));
return;

}

$selectParameters = $parameters[self::SELECT];

$starSuffix = $platform->getIdentifierSeparator() . self::SQL_STAR;
Expand Down
30 changes: 23 additions & 7 deletions test/Sql/Platform/IbmDb2/SelectDecoratorTest.php
Expand Up @@ -24,7 +24,7 @@ class SelectDecoratorTest extends \PHPUnit_Framework_TestCase
* @covers Zend\Db\Sql\Platform\SqlServer\SelectDecorator::processLimitOffset
* @dataProvider dataProvider
*/
public function testPrepareStatement(Select $select, $expectedPrepareSql, $expectedParams, $notUsed)
public function testPrepareStatement(Select $select, $expectedPrepareSql, $expectedParams, $notUsed, $supportsLimitOffset)
{
$driver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface');
$driver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?'));
Expand All @@ -47,6 +47,7 @@ public function testPrepareStatement(Select $select, $expectedPrepareSql, $expec

$selectDecorator = new SelectDecorator;
$selectDecorator->setSubject($select);
$selectDecorator->setSupportsLimitOffset($supportsLimitOffset);
$selectDecorator->prepareStatement($adapter, $statement);

$this->assertEquals($expectedParams, $parameterContainer->getNamedArray());
Expand All @@ -57,14 +58,15 @@ public function testPrepareStatement(Select $select, $expectedPrepareSql, $expec
* @covers Zend\Db\Sql\Platform\IbmDb2\SelectDecorator::getSqlString
* @dataProvider dataProvider
*/
public function testGetSqlString(Select $select, $ignored0, $ignored1, $expectedSql)
public function testGetSqlString(Select $select, $ignored0, $ignored1, $expectedSql, $supportsLimitOffset)
{
$parameterContainer = new ParameterContainer;
$statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface');
$statement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer));

$selectDecorator = new SelectDecorator;
$selectDecorator->setSubject($select);
$selectDecorator->setSupportsLimitOffset($supportsLimitOffset);

$this->assertEquals($expectedSql, @$selectDecorator->getSqlString(new IbmDb2Platform));
}
Expand Down Expand Up @@ -109,12 +111,26 @@ public function dataProvider()
$expectedPrepareSql4 = 'SELECT * FROM ( SELECT "x".*, ROW_NUMBER() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" WHERE "x"."id" > ? AND "x"."id" < ? ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN ? AND ?';
$expectedSql4 = 'SELECT * FROM ( SELECT "x".*, ROW_NUMBER() OVER () AS ZEND_DB_ROWNUM FROM "foo" "x" WHERE "x"."id" > \'10\' AND "x"."id" < \'31\' ) AS ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION WHERE ZEND_IBMDB2_SERVER_LIMIT_OFFSET_EMULATION.ZEND_DB_ROWNUM BETWEEN 0 AND 5';

$select5 = new Select;
$select5->from(['x' => 'foo'])->limit(5);
$expectedParams5 = [];
$expectedPrepareSql5 = 'SELECT "x".* FROM "foo" "x" LIMIT 5';
$expectedSql5 = 'SELECT "x".* FROM "foo" "x" LIMIT 5';

$select6 = new Select;
$select6->columns([new Expression('DISTINCT(id) as id')])->from(['x' => 'foo'])->limit(5)->offset(10);
$expectedParams6 = [];
$expectedPrepareSql6 = 'SELECT DISTINCT(id) as id FROM "foo" "x" LIMIT 5 OFFSET 10';
$expectedSql6 = 'SELECT DISTINCT(id) as id FROM "foo" "x" LIMIT 5 OFFSET 10';

return [
[$select0, $expectedPrepareSql0, $expectedParams0, $expectedSql0],
[$select1, $expectedPrepareSql1, $expectedParams1, $expectedSql1],
[$select2, $expectedPrepareSql2, $expectedParams2, $expectedSql2],
[$select3, $expectedPrepareSql3, $expectedParams3, $expectedSql3],
[$select4, $expectedPrepareSql4, $expectedParams4, $expectedSql4],
[$select0, $expectedPrepareSql0, $expectedParams0, $expectedSql0, false],
[$select1, $expectedPrepareSql1, $expectedParams1, $expectedSql1, false],
[$select2, $expectedPrepareSql2, $expectedParams2, $expectedSql2, false],
[$select3, $expectedPrepareSql3, $expectedParams3, $expectedSql3, false],
[$select4, $expectedPrepareSql4, $expectedParams4, $expectedSql4, false],
[$select5, $expectedPrepareSql5, $expectedParams5, $expectedSql5, true],
[$select6, $expectedPrepareSql6, $expectedParams6, $expectedSql6, true],
];
}
}