Commit 04832e27 authored by beberlei's avatar beberlei

[2.0] DDC-125 - Query Hints are now included in both QueryCache and...

[2.0] DDC-125 - Query Hints are now included in both QueryCache and ResultCache - QueryCache now also uses firstResult and maxResults for the cache key - ResultCache was fixed to use "getSql()" instead of "getDql()"
parent ca23555c
......@@ -488,7 +488,7 @@ abstract class AbstractQuery
// Check result cache
if ($this->_useResultCache && $cacheDriver = $this->getResultCacheDriver()) {
$id = $this->getResultCacheId($params);
$id = $this->_getResultCacheId($params);
$cached = $this->_expireResultCache ? false : $cacheDriver->fetch($id);
if ($cached === false) {
......@@ -541,12 +541,14 @@ abstract class AbstractQuery
* @param array $params
* @return string $id
*/
public function getResultCacheId(array $params)
protected function _getResultCacheId(array $params)
{
if ($this->_resultCacheId) {
return $this->_resultCacheId;
} else {
return md5($this->getDql() . var_export($params, true));
$sql = $this->getSql();
ksort($this->_hints);
return md5(implode(";", (array)$sql) . var_export($params, true) . var_export($this->_hints, true));
}
}
......
......@@ -173,11 +173,7 @@ final class Query extends AbstractQuery
{
// Check query cache
if ($queryCache = $this->getQueryCacheDriver()) {
// Calculate hash for dql query.
// TODO: Probably need to include query hints in hash calculation, because query hints
// can have influence on the SQL.
// TODO: Include _maxResults and _firstResult in hash calculation
$hash = md5($this->getDql() . 'DOCTRINE_QUERY_CACHE_SALT');
$hash = $this->_getQueryCacheId();
$cached = ($this->_expireQueryCache) ? false : $queryCache->fetch($hash);
if ($cached === false) {
......@@ -438,4 +434,21 @@ final class Query extends AbstractQuery
$this->setHint(self::HINT_INTERNAL_ITERATION, true);
return parent::iterate($params, $hydrationMode);
}
/**
* Generate a cache id for the query cache - reusing the Result-Cache-Id generator.
*
* The query cache
*
* @return string
*/
protected function _getQueryCacheId()
{
ksort($this->_hints);
return md5(
$this->getDql() . var_export($this->_hints, true) .
'firstResult='.$this->_firstResult.'&maxResult='.$this->_maxResults.'DOCTRINE_QUERY_CACHE_SALT'
);
}
}
\ No newline at end of file
......@@ -19,38 +19,101 @@ class QueryCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
parent::setUp();
}
public function testQueryCache()
public function testQueryCache_DependsOnHints()
{
$this->_em->getConfiguration()->setQueryCacheImpl(null);
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$cache = new ArrayCache();
$query->setQueryCacheDriver($cache);
$user = new CmsUser;
$user->name = 'Roman';
$user->username = 'romanb';
$user->status = 'dev';
$this->_em->persist($user);
$this->_em->flush();
$query->getResult();
$this->assertEquals(1, count($cache->getIds()));
$query->setHint('foo', 'bar');
$query->getResult();
$this->assertEquals(2, count($cache->getIds()));
return $query;
}
/**
* @param <type> $query
* @depends testQueryCache_DependsOnHints
*/
public function testQueryCache_DependsOnFirstResult($query)
{
$cache = $query->getQueryCacheDriver();
$cacheCount = count($cache->getIds());
$query->setFirstResult(10);
$query->getResult();
$this->assertEquals($cacheCount + 1, count($cache->getIds()));
}
/**
* @param <type> $query
* @depends testQueryCache_DependsOnHints
*/
public function testQueryCache_DependsOnMaxResults($query)
{
$cache = $query->getQueryCacheDriver();
$cacheCount = count($cache->getIds());
$query->setMaxResults(10);
$query->getResult();
$this->assertEquals($cacheCount + 1, count($cache->getIds()));
}
public function testQueryCache_NoHitSaveParserResult()
{
$this->_em->getConfiguration()->setQueryCacheImpl(null);
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$cache = new ArrayCache;
$cache = $this->getMock('Doctrine\Common\Cache\AbstractCache', array('_doFetch', '_doContains', '_doSave', '_doDelete', 'getIds'));
$cache->expects($this->at(0))
->method('_doFetch')
->with($this->isType('string'))
->will($this->returnValue(false));
$cache->expects($this->at(1))
->method('_doSave')
->with($this->isType('string'), $this->isInstanceOf('Doctrine\ORM\Query\ParserResult'), $this->equalTo(null));
$query->setQueryCacheDriver($cache);
$users = $query->getResult();
}
$this->assertTrue($cache->contains(md5('select ux from Doctrine\Tests\Models\CMS\CmsUser uxDOCTRINE_QUERY_CACHE_SALT')));
$this->assertEquals(1, count($users));
$this->assertEquals('Roman', $users[0]->name);
public function testQueryCache_HitDoesNotSaveParserResult()
{
$this->_em->getConfiguration()->setQueryCacheImpl(null);
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$this->_em->clear();
$sqlExecMock = $this->getMock('Doctrine\ORM\Query\Exec\AbstractSqlExecutor', array('execute'));
$sqlExecMock->expects($this->once())
->method('execute')
->will($this->returnValue( 10 ));
$query2 = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$query2->setQueryCacheDriver($cache);
$parserResultMock = $this->getMock('Doctrine\ORM\Query\ParserResult');
$parserResultMock->expects($this->once())
->method('getSqlExecutor')
->will($this->returnValue($sqlExecMock));
$users = $query2->getResult();
$cache = $this->getMock('Doctrine\Common\Cache\AbstractCache', array('_doFetch', '_doContains', '_doSave', '_doDelete', 'getIds'));
$cache->expects($this->once())
->method('_doFetch')
->with($this->isType('string'))
->will($this->returnValue($parserResultMock));
$cache->expects($this->never())
->method('_doSave');
$this->assertTrue($cache->contains(md5('select ux from Doctrine\Tests\Models\CMS\CmsUser uxDOCTRINE_QUERY_CACHE_SALT')));
$this->assertEquals(1, count($users));
$this->assertEquals('Roman', $users[0]->name);
$query->setQueryCacheDriver($cache);
$users = $query->getResult();
}
}
......@@ -30,23 +30,27 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$cache = new ArrayCache;
$query->setResultCacheDriver($cache);
$cache = new ArrayCache();
$query->setResultCacheDriver($cache)->setResultCacheId('my_cache_id');
$this->assertFalse($cache->contains('my_cache_id'));
$users = $query->getResult();
$this->assertTrue($cache->contains($query->getResultCacheId(array())));
$this->assertTrue($cache->contains('my_cache_id'));
$this->assertEquals(1, count($users));
$this->assertEquals('Roman', $users[0]->name);
$this->_em->clear();
$query2 = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$query2->setResultCacheDriver($cache);
$query2->setResultCacheDriver($cache)->setResultCacheId('my_cache_id');
$users = $query2->getResult();
$this->assertTrue($cache->contains($query->getResultCacheId(array())));
$this->assertTrue($cache->contains('my_cache_id'));
$this->assertEquals(1, count($users));
$this->assertEquals('Roman', $users[0]->name);
}
......@@ -58,6 +62,9 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
$query = $this->_em->createQuery('select ux from Doctrine\Tests\Models\CMS\CmsUser ux');
$query->setResultCacheDriver($cache);
$query->setResultCacheId('testing_result_cache_id');
$this->assertFalse($cache->contains('testing_result_cache_id'));
$users = $query->getResult();
$this->assertTrue($cache->contains('testing_result_cache_id'));
......@@ -77,4 +84,51 @@ class ResultCacheTest extends \Doctrine\Tests\OrmFunctionalTestCase
$this->_em->getConfiguration()->setResultCacheImpl(null);
}
public function testNativeQueryResultCaching()
{
$rsm = new \Doctrine\ORM\Query\ResultSetMapping();
$rsm->addScalarResult('id', 'u');
$query = $this->_em->createNativeQuery('select u.id FROM cms_users u WHERE u.id = ?', $rsm);
$query->setParameter(1, 10);
$cache = new ArrayCache();
$query->setResultCacheDriver($cache)->useResultCache(true);
$this->assertEquals(0, count($cache->getIds()));
$query->getResult();
$this->assertEquals(1, count($cache->getIds()));
return $query;
}
/**
* @param <type> $query
* @depends testNativeQueryResultCaching
*/
public function testResultCacheDependsOnQueryHints($query)
{
$cache = $query->getResultCacheDriver();
$cacheCount = count($cache->getIds());
$query->setHint('foo', 'bar');
$query->getResult();
$this->assertEquals($cacheCount + 1, count($cache->getIds()));
}
/**
* @param <type> $query
* @depends testNativeQueryResultCaching
*/
public function testResultCacheDependsOnParameters($query)
{
$cache = $query->getResultCacheDriver();
$cacheCount = count($cache->getIds());
$query->setParameter(1, 50);
$query->getResult();
$this->assertEquals($cacheCount + 1, count($cache->getIds()));
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment