Skip to content

Commit

Permalink
Merge branch 'ralphschindler-feature/db-sql-select-union' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
ezimuel committed Jun 7, 2013
2 parents 87f22c1 + 7be41a0 commit e97cc0f
Show file tree
Hide file tree
Showing 3 changed files with 118 additions and 2 deletions.
76 changes: 74 additions & 2 deletions library/Zend/Db/Sql/Select.php
Original file line number Diff line number Diff line change
Expand Up @@ -47,12 +47,17 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface
const SQL_STAR = '*';
const ORDER_ASCENDING = 'ASC';
const ORDER_DESCENDING = 'DESC';
const COMBINE = 'combine';
const COMBINE_UNION = 'union';
const COMBINE_EXCEPT = 'except';
const COMBINE_INTERSECT = 'intersect';
/**#@-*/

/**
* @var array Specifications
*/
protected $specifications = array(
'statementStart' => '%1$s',
self::SELECT => array(
'SELECT %1$s FROM %2$s' => array(
array(1 => '%1$s', 2 => '%1$s AS %2$s', 'combinedby' => ', '),
Expand Down Expand Up @@ -82,7 +87,9 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface
)
),
self::LIMIT => 'LIMIT %1$s',
self::OFFSET => 'OFFSET %1$s'
self::OFFSET => 'OFFSET %1$s',
'statementEnd' => '%1$s',
self::COMBINE => '%1$s ( %2$s )',
);

/**
Expand Down Expand Up @@ -145,6 +152,11 @@ class Select extends AbstractSql implements SqlInterface, PreparableSqlInterface
*/
protected $offset = null;

/**
* @var array
*/
protected $combine = array();

/**
* Constructor
*
Expand Down Expand Up @@ -410,6 +422,26 @@ public function offset($offset)
return $this;
}

/**
* @param Select $select
* @param string $type
* @param string $modifier
* @return Select
* @throws Exception\InvalidArgumentException
*/
public function combine(Select $select, $type = self::COMBINE_UNION, $modifier = '')
{
if ($this->combine !== array()) {
throw new Exception\InvalidArgumentException('This Select object is already combined and cannot be combined with multiple Selects objects');
}
$this->combine = array(
'select' => $select,
'type' => $type,
'modifier' => $modifier
);
return $this;
}

/**
* @param string $part
* @return Select
Expand Down Expand Up @@ -453,6 +485,9 @@ public function reset($part)
case self::ORDER:
$this->order = null;
break;
case self::COMBINE:
$this->combine = array();
break;
}
return $this;
}
Expand All @@ -478,7 +513,8 @@ public function getRawState($key = null)
self::GROUP => $this->group,
self::HAVING => $this->having,
self::LIMIT => $this->limit,
self::OFFSET => $this->offset
self::OFFSET => $this->offset,
self::COMBINE => $this->combine
);
return (isset($key) && array_key_exists($key, $rawState)) ? $rawState[$key] : $rawState;
}
Expand Down Expand Up @@ -569,6 +605,20 @@ protected function renderTable($table, $alias = null)
return $sql;
}

protected function processStatementStart(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null)
{
if ($this->combine !== array()) {
return array('(');
}
}

protected function processStatementEnd(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null)
{
if ($this->combine !== array()) {
return array(')');
}
}

/**
* Process the select part
*
Expand Down Expand Up @@ -868,6 +918,28 @@ protected function processOffset(PlatformInterface $platform, DriverInterface $d
return array($platform->quoteValue($this->offset));
}

protected function processCombine(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null)
{
if ($this->combine == array()) {
return null;
}

$type = $this->combine['type'];
if ($this->combine['modifier']) {
$type .= ' ' . $this->combine['modifier'];
}
$type = strtoupper($type);

if ($driver) {
$sql = $this->processSubSelect($this->combine['select'], $platform, $driver, $parameterContainer);
return array($type, $sql);
}
return array(
$type,
$this->processSubSelect($this->combine['select'], $platform)
);
}

/**
* Variable overloading
*
Expand Down
3 changes: 3 additions & 0 deletions tests/ZendTest/Db/Metadata/Source/SqliteMetadataTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ class SqliteMetadataTest extends \PHPUnit_Framework_TestCase
*/
protected function setUp()
{
if (!extension_loaded('pdo_sqlite')) {
$this->markTestSkipped('I cannot test without the pdo_sqlite extension');
}
$this->adapter = new Adapter(array(
'driver' => 'Pdo',
'dsn' => 'sqlite::memory:'
Expand Down
41 changes: 41 additions & 0 deletions tests/ZendTest/Db/Sql/SelectTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -414,6 +414,34 @@ public function testGetRawStateViaHaving(Select $select)
$this->assertInstanceOf('Zend\Db\Sql\Having', $select->getRawState('having'));
}

/**
* @testdox unit test: Test combine() returns same Select object (is chainable)
* @covers Zend\Db\Sql\Select::combine
*/
public function testCombine()
{
$select = new Select;
$combine = new Select;
$return = $select->combine($combine, $select::COMBINE_UNION, 'ALL');
$this->assertSame($select, $return);

return $return;
}

/**
* @testdox unit test: Test getRawState() returns information populated via combine()
* @covers Zend\Db\Sql\Select::getRawState
* @depends testCombine
*/
public function testGetRawStateViaCombine(Select $select)
{
$state = $select->getRawState('combine');
$this->assertInstanceOf('Zend\Db\Sql\Select', $state['select']);
$this->assertNotSame($select, $state['select']);
$this->assertEquals(Select::COMBINE_UNION, $state['type']);
$this->assertEquals('ALL', $state['modifier']);
}

/**
* @testdox unit test: Test reset() resets internal stat of Select object, based on input
* @covers Zend\Db\Sql\Select::reset
Expand Down Expand Up @@ -558,6 +586,7 @@ public function test__clone()
* @covers Zend\Db\Sql\Select::processOrder
* @covers Zend\Db\Sql\Select::processLimit
* @covers Zend\Db\Sql\Select::processOffset
* @covers Zend\Db\Sql\Select::processCombine
*/
public function testProcessMethods(Select $select, $unused, $unused2, $unused3, $internalTests)
{
Expand Down Expand Up @@ -1041,6 +1070,17 @@ public function providerData()
'processSelect' => array(array(array('"bar"', '"bar"')), '"foo" AS "x"')
);

$select44 = new Select;
$select44->from('foo')->where('a = b');
$select44b = new Select;
$select44b->from('bar')->where('c = d');
$select44->combine($select44b, Select::COMBINE_UNION, 'ALL');
$sqlPrep44 = // same
$sqlStr44 = '( SELECT "foo".* FROM "foo" WHERE a = b ) UNION ALL ( SELECT "bar".* FROM "bar" WHERE c = d )';
$internalTests44 = array(
'processCombine' => array('UNION ALL', 'SELECT "bar".* FROM "bar" WHERE c = d')
);

/**
* $select = the select object
* $sqlPrep = the sql as a result of preparation
Expand Down Expand Up @@ -1095,6 +1135,7 @@ public function providerData()
array($select41, $sqlPrep41, array(), $sqlStr41, $internalTests41),
array($select42, $sqlPrep42, array(), $sqlStr42, $internalTests42),
array($select43, $sqlPrep43, array(), $sqlStr43, $internalTests43),
array($select44, $sqlPrep44, array(), $sqlStr44, $internalTests44),
);
}
}

0 comments on commit e97cc0f

Please sign in to comment.