Permalink
Browse files

Zend\Db\Sql

* Added platform abstraction for mysql's LIMIT and OFFSET so values are not quoted
* Fixes: #2516, #2545, #2244
  • Loading branch information...
1 parent 54ace42 commit 17c00ebcfff68105cdf393b04763e8bf3f41ab5e @ralphschindler ralphschindler committed Oct 16, 2012
@@ -69,7 +69,7 @@ public function prepareStatement(Adapter $adapter, StatementContainerInterface $
$decoratorForType = false;
foreach ($this->decorators as $type => $decorator) {
if ($this->subject instanceof $type && $decorator instanceof PreparableSqlInterface) {
- /** @var $decoratorForType PreparableSqlInterface */
+ /** @var $decoratorForType PreparableSqlInterface|PlatformDecoratorInterface */
$decoratorForType = $decorator;
break;
}
@@ -96,7 +96,7 @@ public function getSqlString(PlatformInterface $adapterPlatform = null)
$decoratorForType = false;
foreach ($this->decorators as $type => $decorator) {
if ($this->subject instanceof $type && $decorator instanceof SqlInterface) {
- /** @var $decoratorForType SqlInterface */
+ /** @var $decoratorForType SqlInterface|PlatformDecoratorInterface */
$decoratorForType = $decorator;
break;
}
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Db
+ */
+
+namespace Zend\Db\Sql\Platform\Mysql;
+
+use Zend\Db\Sql\Platform\AbstractPlatform;
+
+class Mysql extends AbstractPlatform
+{
+
+ public function __construct(SelectDecorator $selectDecorator = null)
+ {
+ $this->setTypeDecorator('Zend\Db\Sql\Select', ($selectDecorator) ?: new SelectDecorator());
+ }
+
+}
@@ -0,0 +1,90 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Db
+ */
+
+namespace Zend\Db\Sql\Platform\Mysql;
+
+use Zend\Db\Adapter\Adapter;
+use Zend\Db\Adapter\ParameterContainer;
+use Zend\Db\Adapter\Platform\PlatformInterface;
+use Zend\Db\Sql\Platform\PlatformDecoratorInterface;
+use Zend\Db\Adapter\StatementContainerInterface;
+use Zend\Db\Sql\Select;
+
+class SelectDecorator extends Select implements PlatformDecoratorInterface
+{
+ /**
+ * @var Select
+ */
+ protected $select = null;
+
+ /**
+ * @param Select $select
+ */
+ public function setSubject($select)
+ {
+ $this->select = $select;
+ }
+
+ /**
+ * @param Adapter $adapter
+ * @param StatementContainerInterface $statementContainer
+ */
+ public function prepareStatement(Adapter $adapter, StatementContainerInterface $statementContainer)
+ {
+ // localize variables
+ foreach (get_object_vars($this->select) as $name => $value) {
+ $this->{$name} = $value;
+ }
+ parent::prepareStatement($adapter, $statementContainer);
+ }
+
+ /**
+ * @param PlatformInterface $platform
+ * @return string
+ */
+ public function getSqlString(PlatformInterface $platform = null)
+ {
+ // localize variables
+ foreach (get_object_vars($this->select) as $name => $value) {
+ $this->{$name} = $value;
+ }
+ return parent::getSqlString($platform);
+ }
+
+ protected function processLimit(PlatformInterface $platform, Adapter $adapter = null, ParameterContainer $parameterContainer = null)
+ {
+ if ($this->limit === null) {
+ return null;
+ }
+ if ($adapter) {
+ $driver = $adapter->getDriver();
+ $sql = $driver->formatParameterName('limit');
+ $parameterContainer->offsetSet('limit', $this->limit, ParameterContainer::TYPE_INTEGER);
+ } else {
+ $sql = $this->limit;
+ }
+
+ return array($sql);
+ }
+
+ protected function processOffset(PlatformInterface $platform, Adapter $adapter = null, ParameterContainer $parameterContainer = null)
+ {
+ if ($this->offset === null) {
+ return null;
+ }
+ if ($adapter) {
+ $parameterContainer->offsetSet('offset', $this->offset, ParameterContainer::TYPE_INTEGER);
+ return array($adapter->getDriver()->formatParameterName('offset'));
+ } else {
+ return array($this->offset);
+ }
+ }
+
+}
@@ -25,6 +25,10 @@ public function __construct(Adapter $adapter)
$this->adapter = $adapter;
$platform = $adapter->getPlatform();
switch (strtolower($platform->getName())) {
+ case 'mysql':
+ $platform = new Mysql\Mysql();
+ $this->decorators = $platform->decorators;
+ break;
case 'sqlserver':
$platform = new SqlServer\SqlServer();
$this->decorators = $platform->decorators;
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Db
+ */
+
+namespace ZendTest\Db\Sql\Platform\Mysql;
+
+use Zend\Db\Sql\Platform\Mysql\Mysql;
+
+class SqlServerTest extends \PHPUnit_Framework_TestCase
+{
+ /**
+ * @testdox unit test / object test: Test SqlServer object has Select proxy
+ * @covers Zend\Db\Sql\Platform\SqlServer\SqlServer::__construct
+ */
+ public function testConstruct()
+ {
+ $mysql = new Mysql;
+ $decorators = $mysql->getDecorators();
+
+ list($type, $decorator) = each($decorators);
+ $this->assertEquals('Zend\Db\Sql\Select', $type);
+ $this->assertInstanceOf('Zend\Db\Sql\Platform\Mysql\SelectDecorator', $decorator);
+ }
+
+}
@@ -0,0 +1,85 @@
+<?php
+/**
+ * Zend Framework (http://framework.zend.com/)
+ *
+ * @link http://github.com/zendframework/zf2 for the canonical source repository
+ * @copyright Copyright (c) 2005-2012 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license http://framework.zend.com/license/new-bsd New BSD License
+ * @package Zend_Db
+ */
+
+namespace ZendTest\Db\Sql\Platform\Mysql;
+
+use Zend\Db\Sql\Platform\Mysql\SelectDecorator;
+use Zend\Db\Sql\Select;
+use Zend\Db\Adapter\ParameterContainer;
+use Zend\Db\Adapter\Platform\Mysql as MysqlPlatform;
+
+class SelectDecoratorTest extends \PHPUnit_Framework_TestCase
+{
+
+ /**
+ * @testdox integration test: Testing SelectDecorator will use Select an internal state to prepare a proper limit/offset sql statement
+ * @covers Zend\Db\Sql\Platform\SqlServer\SelectDecorator::prepareStatement
+ * @covers Zend\Db\Sql\Platform\SqlServer\SelectDecorator::processLimitOffset
+ * @dataProvider dataProvider
+ */
+ public function testPrepareStatement(Select $select, $expectedSql, $expectedParams)
+ {
+ $driver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface');
+ $driver->expects($this->any())->method('formatParameterName')->will($this->returnValue('?'));
+
+ // test
+ $adapter = $this->getMock(
+ 'Zend\Db\Adapter\Adapter',
+ null,
+ array(
+ $driver,
+ new MysqlPlatform()
+ )
+ );
+
+ $parameterContainer = new ParameterContainer;
+ $statement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface');
+ $statement->expects($this->any())->method('getParameterContainer')->will($this->returnValue($parameterContainer));
+
+ $statement->expects($this->once())->method('setSql')->with($expectedSql);
+
+ $selectDecorator = new SelectDecorator;
+ $selectDecorator->setSubject($select);
+ $selectDecorator->prepareStatement($adapter, $statement);
+
+ $this->assertEquals($expectedParams, $parameterContainer->getNamedArray());
+ }
+
+ /**
+ * @testdox integration test: Testing SelectDecorator will use Select an internal state to prepare a proper limit/offset sql statement
+ * @covers Zend\Db\Sql\Platform\SqlServer\SelectDecorator::getSqlString
+ * @covers Zend\Db\Sql\Platform\SqlServer\SelectDecorator::processLimitOffset
+ * @dataProvider dataProvider
+ */
+ public function testGetSqlString(Select $select, $notUsed, $notUsed, $expectedSql)
+ {
+ $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);
+ $this->assertEquals($expectedSql, $selectDecorator->getSqlString(new MysqlPlatform));
+ }
+
+ public function dataProvider()
+ {
+ $select0 = new Select;
+ $select0->from('foo')->limit(5)->offset(10);
+ $expectedPrepareSql0 = 'SELECT `foo`.* FROM `foo` LIMIT ? OFFSET ?';
+ $expectedParams0 = array('offset' => 10, 'limit' => 5);
+ $expectedSql0 = 'SELECT `foo`.* FROM `foo` LIMIT 5 OFFSET 10';
+
+ return array(
+ array($select0, $expectedPrepareSql0, $expectedParams0, $expectedSql0),
+ );
+ }
+
+}

0 comments on commit 17c00eb

Please sign in to comment.