Honor convertToDatabaseValueSQL() in DQL query parameters
This commit is contained in:
parent
89ab4b3f48
commit
517cb7e2a2
@ -130,6 +130,13 @@ final class Query extends AbstractQuery
|
||||
*/
|
||||
private $_state = self::STATE_CLEAN;
|
||||
|
||||
/**
|
||||
* A snapshot of the parameter types the query was parsed with.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $_parsedTypes = array();
|
||||
|
||||
/**
|
||||
* Cached DQL query.
|
||||
*
|
||||
@ -234,12 +241,20 @@ final class Query extends AbstractQuery
|
||||
*/
|
||||
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
|
||||
if ($this->_state === self::STATE_CLEAN && $this->_em->isFiltersStateClean()) {
|
||||
if ($this->_state === self::STATE_CLEAN && $this->_parsedTypes === $types && $this->_em->isFiltersStateClean()) {
|
||||
return $this->_parserResult;
|
||||
}
|
||||
|
||||
$this->_state = self::STATE_CLEAN;
|
||||
$this->_parsedTypes = $types;
|
||||
|
||||
// Check query cache.
|
||||
if ( ! ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver()))) {
|
||||
@ -250,7 +265,7 @@ final class Query extends AbstractQuery
|
||||
return $this->_parserResult;
|
||||
}
|
||||
|
||||
$hash = $this->_getQueryCacheId();
|
||||
$hash = $this->_getQueryCacheId($types);
|
||||
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
|
||||
|
||||
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.
|
||||
*
|
||||
* The query cache
|
||||
* @param array $types The parameter types, indexed by parameter key.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function _getQueryCacheId()
|
||||
protected function _getQueryCacheId(array $types)
|
||||
{
|
||||
ksort($this->_hints);
|
||||
|
||||
@ -696,7 +711,7 @@ final class Query extends AbstractQuery
|
||||
'&platform=' . $platform .
|
||||
($this->_em->hasFilters() ? $this->_em->getFilters()->getHash() : '') .
|
||||
'&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++);
|
||||
|
||||
$parameter = $this->query->getParameter($inputParam->name);
|
||||
|
||||
if ($parameter && Type::hasType($type = $parameter->getType())) {
|
||||
return Type::getType($type)->convertToDatabaseValueSQL('?', $this->platform);
|
||||
}
|
||||
|
||||
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…
Reference in New Issue
Block a user