Honor convertToDatabaseValueSQL() in DQL query parameters
This commit is contained in:
parent
89ab4b3f48
commit
517cb7e2a2
3 changed files with 114 additions and 5 deletions
|
@ -130,6 +130,13 @@ final class Query extends AbstractQuery
|
||||||
*/
|
*/
|
||||||
private $_state = self::STATE_CLEAN;
|
private $_state = self::STATE_CLEAN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A snapshot of the parameter types the query was parsed with.
|
||||||
|
*
|
||||||
|
* @var array
|
||||||
|
*/
|
||||||
|
private $_parsedTypes = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cached DQL query.
|
* Cached DQL query.
|
||||||
*
|
*
|
||||||
|
@ -234,12 +241,20 @@ final class Query extends AbstractQuery
|
||||||
*/
|
*/
|
||||||
private function _parse()
|
private function _parse()
|
||||||
{
|
{
|
||||||
|
$types = array();
|
||||||
|
|
||||||
|
foreach ($this->parameters as $parameter) {
|
||||||
|
/** @var Query\Parameter $parameter */
|
||||||
|
$types[$parameter->getName()] = $parameter->getType();
|
||||||
|
}
|
||||||
|
|
||||||
// Return previous parser result if the query and the filter collection are both clean
|
// Return previous parser result if the query and the filter collection are both clean
|
||||||
if ($this->_state === self::STATE_CLEAN && $this->_em->isFiltersStateClean()) {
|
if ($this->_state === self::STATE_CLEAN && $this->_parsedTypes === $types && $this->_em->isFiltersStateClean()) {
|
||||||
return $this->_parserResult;
|
return $this->_parserResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->_state = self::STATE_CLEAN;
|
$this->_state = self::STATE_CLEAN;
|
||||||
|
$this->_parsedTypes = $types;
|
||||||
|
|
||||||
// Check query cache.
|
// Check query cache.
|
||||||
if ( ! ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver()))) {
|
if ( ! ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver()))) {
|
||||||
|
@ -250,7 +265,7 @@ final class Query extends AbstractQuery
|
||||||
return $this->_parserResult;
|
return $this->_parserResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
$hash = $this->_getQueryCacheId();
|
$hash = $this->_getQueryCacheId($types);
|
||||||
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
|
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
|
||||||
|
|
||||||
if ($cached instanceof ParserResult) {
|
if ($cached instanceof ParserResult) {
|
||||||
|
@ -678,11 +693,11 @@ final class Query extends AbstractQuery
|
||||||
/**
|
/**
|
||||||
* Generate a cache id for the query cache - reusing the Result-Cache-Id generator.
|
* Generate a cache id for the query cache - reusing the Result-Cache-Id generator.
|
||||||
*
|
*
|
||||||
* The query cache
|
* @param array $types The parameter types, indexed by parameter key.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function _getQueryCacheId()
|
protected function _getQueryCacheId(array $types)
|
||||||
{
|
{
|
||||||
ksort($this->_hints);
|
ksort($this->_hints);
|
||||||
|
|
||||||
|
@ -696,7 +711,7 @@ final class Query extends AbstractQuery
|
||||||
'&platform=' . $platform .
|
'&platform=' . $platform .
|
||||||
($this->_em->hasFilters() ? $this->_em->getFilters()->getHash() : '') .
|
($this->_em->hasFilters() ? $this->_em->getFilters()->getHash() : '') .
|
||||||
'&firstResult=' . $this->_firstResult . '&maxResult=' . $this->_maxResults .
|
'&firstResult=' . $this->_firstResult . '&maxResult=' . $this->_maxResults .
|
||||||
'&hydrationMode='.$this->_hydrationMode.'DOCTRINE_QUERY_CACHE_SALT'
|
'&hydrationMode=' . $this->_hydrationMode . '&types=' . serialize($types) . 'DOCTRINE_QUERY_CACHE_SALT'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2203,6 +2203,12 @@ class SqlWalker implements TreeWalker
|
||||||
{
|
{
|
||||||
$this->parserResult->addParameterMapping($inputParam->name, $this->sqlParamIndex++);
|
$this->parserResult->addParameterMapping($inputParam->name, $this->sqlParamIndex++);
|
||||||
|
|
||||||
|
$parameter = $this->query->getParameter($inputParam->name);
|
||||||
|
|
||||||
|
if ($parameter && Type::hasType($type = $parameter->getType())) {
|
||||||
|
return Type::getType($type)->convertToDatabaseValueSQL('?', $this->platform);
|
||||||
|
}
|
||||||
|
|
||||||
return '?';
|
return '?';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
88
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2224Test.php
Normal file
88
tests/Doctrine/Tests/ORM/Functional/Ticket/DDC2224Test.php
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Doctrine\Tests\ORM\Functional\Ticket;
|
||||||
|
|
||||||
|
use Doctrine\Common\Cache\ArrayCache;
|
||||||
|
use Doctrine\DBAL\Types\Type;
|
||||||
|
use Doctrine\DBAL\Platforms\AbstractPlatform;
|
||||||
|
use Doctrine\ORM\Query;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @group DDC-2224
|
||||||
|
*/
|
||||||
|
class DDC2224Test extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||||
|
{
|
||||||
|
public static function setUpBeforeClass()
|
||||||
|
{
|
||||||
|
\Doctrine\DBAL\Types\Type::addType('DDC2224Type', __NAMESPACE__ . '\DDC2224Type');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testIssue()
|
||||||
|
{
|
||||||
|
$dql = 'SELECT e FROM ' . __NAMESPACE__ . '\DDC2224Entity e WHERE e.field = :field';
|
||||||
|
$query = $this->_em->createQuery($dql);
|
||||||
|
$query->setQueryCacheDriver(new ArrayCache());
|
||||||
|
|
||||||
|
$query->setParameter('field', 'test', 'DDC2224Type');
|
||||||
|
$this->assertStringEndsWith('.field = FUNCTION(?)', $query->getSQL());
|
||||||
|
|
||||||
|
return $query;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @depends testIssue
|
||||||
|
*/
|
||||||
|
public function testCacheMissWhenTypeChanges(Query $query)
|
||||||
|
{
|
||||||
|
$query->setParameter('field', 'test', 'string');
|
||||||
|
$this->assertStringEndsWith('.field = ?', $query->getSQL());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DDC2224Type extends Type
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function getSQLDeclaration(array $fieldDeclaration, AbstractPlatform $platform)
|
||||||
|
{
|
||||||
|
return $platform->getVarcharTypeDeclarationSQL($fieldDeclaration);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getName()
|
||||||
|
{
|
||||||
|
return 'DDC2224Type';
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function canRequireSQLConversion()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritdoc}
|
||||||
|
*/
|
||||||
|
public function convertToDatabaseValueSQL($sqlExpr, AbstractPlatform $platform)
|
||||||
|
{
|
||||||
|
return sprintf('FUNCTION(%s)', $sqlExpr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Entity
|
||||||
|
*/
|
||||||
|
class DDC2224Entity
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Id @GeneratedValue @Column(type="integer")
|
||||||
|
*/
|
||||||
|
public $id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Column(type="DDC2224Type")
|
||||||
|
*/
|
||||||
|
public $field;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue