From ea15efa5c1c8af12a77e2de95095cc6433c34db8 Mon Sep 17 00:00:00 2001 From: Rob Allen Date: Fri, 13 Oct 2017 20:57:51 +0100 Subject: [PATCH 1/5] Add support for LIMIT OFFSET for db2 --- src/Sql/Platform/IbmDb2/SelectDecorator.php | 38 ++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Sql/Platform/IbmDb2/SelectDecorator.php b/src/Sql/Platform/IbmDb2/SelectDecorator.php index 28602b20e4..2994cd9bb0 100644 --- a/src/Sql/Platform/IbmDb2/SelectDecorator.php +++ b/src/Sql/Platform/IbmDb2/SelectDecorator.php @@ -27,7 +27,13 @@ class SelectDecorator extends Select implements PlatformDecoratorInterface */ protected $subject = null; - /** + /** + * @var bool + */ + protected $supportsLimitOffset = false; + + + /** * @return bool */ public function getIsSelectContainDistinct() @@ -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 */ @@ -82,6 +104,20 @@ 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; + $offset = (int)$this->offset; + if ($this->limit) { + if ($this->offset) { + array_push($sqls, sprintf("LIMIT %s OFFSET %s", $limit, $offset)); + } else { + array_push($sqls, sprintf("LIMIT %s", $limit)); + } + } + return; + } + $selectParameters = $parameters[self::SELECT]; $starSuffix = $platform->getIdentifierSeparator() . self::SQL_STAR; From ead49e6adc3c16e2d5d382f549127aa4dbd81a11 Mon Sep 17 00:00:00 2001 From: Rob Allen Date: Fri, 13 Oct 2017 21:12:52 +0100 Subject: [PATCH 2/5] Add tests for DB2 limit offset --- .../Platform/IbmDb2/SelectDecoratorTest.php | 30 ++++++++++++++----- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/test/Sql/Platform/IbmDb2/SelectDecoratorTest.php b/test/Sql/Platform/IbmDb2/SelectDecoratorTest.php index 4c9e939d06..c6d925dc6c 100644 --- a/test/Sql/Platform/IbmDb2/SelectDecoratorTest.php +++ b/test/Sql/Platform/IbmDb2/SelectDecoratorTest.php @@ -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('?')); @@ -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()); @@ -57,7 +58,7 @@ 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'); @@ -65,6 +66,7 @@ public function testGetSqlString(Select $select, $ignored0, $ignored1, $expected $selectDecorator = new SelectDecorator; $selectDecorator->setSubject($select); + $selectDecorator->setSupportsLimitOffset($supportsLimitOffset); $this->assertEquals($expectedSql, @$selectDecorator->getSqlString(new IbmDb2Platform)); } @@ -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], ]; } } From 0d7d8efbc05e3e1d56838cb843fb6b348c575599 Mon Sep 17 00:00:00 2001 From: Rob Allen Date: Mon, 16 Oct 2017 10:21:34 +0100 Subject: [PATCH 3/5] Return early --- src/Sql/Platform/IbmDb2/SelectDecorator.php | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/src/Sql/Platform/IbmDb2/SelectDecorator.php b/src/Sql/Platform/IbmDb2/SelectDecorator.php index 2994cd9bb0..015d25bd5d 100644 --- a/src/Sql/Platform/IbmDb2/SelectDecorator.php +++ b/src/Sql/Platform/IbmDb2/SelectDecorator.php @@ -108,13 +108,17 @@ protected function processLimitOffset(PlatformInterface $platform, DriverInterfa // Note: db2_prepare/db2_execute fails with positional parameters, for LIMIT & OFFSET $limit = (int)$this->limit; $offset = (int)$this->offset; - if ($this->limit) { - if ($this->offset) { - array_push($sqls, sprintf("LIMIT %s OFFSET %s", $limit, $offset)); - } else { - array_push($sqls, sprintf("LIMIT %s", $limit)); - } + + if (! $limit) { + return; + } + + if ($offset) { + array_push($sqls, sprintf("LIMIT %s OFFSET %s", $limit, $offset)); + return; } + + array_push($sqls, sprintf("LIMIT %s", $limit)); return; } From fecf111a94a6ec1e3d56ef21a4274a41cd85b301 Mon Sep 17 00:00:00 2001 From: Rob Allen Date: Mon, 16 Oct 2017 15:18:37 +0100 Subject: [PATCH 4/5] Only define $offset if needed --- src/Sql/Platform/IbmDb2/SelectDecorator.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Sql/Platform/IbmDb2/SelectDecorator.php b/src/Sql/Platform/IbmDb2/SelectDecorator.php index 015d25bd5d..f11b4eedc2 100644 --- a/src/Sql/Platform/IbmDb2/SelectDecorator.php +++ b/src/Sql/Platform/IbmDb2/SelectDecorator.php @@ -107,12 +107,11 @@ protected function processLimitOffset(PlatformInterface $platform, DriverInterfa if ($this->supportsLimitOffset) { // Note: db2_prepare/db2_execute fails with positional parameters, for LIMIT & OFFSET $limit = (int)$this->limit; - $offset = (int)$this->offset; - if (! $limit) { return; } + $offset = (int)$this->offset; if ($offset) { array_push($sqls, sprintf("LIMIT %s OFFSET %s", $limit, $offset)); return; From 547215b9a584b7e430e07aaab7a29364e9d27d66 Mon Sep 17 00:00:00 2001 From: Rob Allen Date: Fri, 20 Oct 2017 07:31:37 +0100 Subject: [PATCH 5/5] Add a space after cast --- src/Sql/Platform/IbmDb2/SelectDecorator.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Sql/Platform/IbmDb2/SelectDecorator.php b/src/Sql/Platform/IbmDb2/SelectDecorator.php index f11b4eedc2..f55fa73f93 100644 --- a/src/Sql/Platform/IbmDb2/SelectDecorator.php +++ b/src/Sql/Platform/IbmDb2/SelectDecorator.php @@ -106,12 +106,12 @@ protected function processLimitOffset(PlatformInterface $platform, DriverInterfa if ($this->supportsLimitOffset) { // Note: db2_prepare/db2_execute fails with positional parameters, for LIMIT & OFFSET - $limit = (int)$this->limit; + $limit = (int) $this->limit; if (! $limit) { return; } - $offset = (int)$this->offset; + $offset = (int) $this->offset; if ($offset) { array_push($sqls, sprintf("LIMIT %s OFFSET %s", $limit, $offset)); return;