Permalink
Browse files

DBAL-171 - Fix bug where params where resorted but types where not in…

… DQL Query
  • Loading branch information...
1 parent 0d4e062 commit 9e8a950f2eba86a655b7446735049596b9cf03ac @beberlei beberlei committed Nov 18, 2011
View
@@ -44,38 +44,38 @@
* is called.
*/
const STATE_DIRTY = 2;
-
+
/* Query HINTS */
/**
* The refresh hint turns any query into a refresh query with the result that
* any local changes in entities are overridden with the fetched values.
- *
+ *
* @var string
*/
const HINT_REFRESH = 'doctrine.refresh';
-
-
+
+
/**
* Internal hint: is set to the proxy entity that is currently triggered for loading
- *
+ *
* @var string
*/
const HINT_REFRESH_ENTITY = 'doctrine.refresh.entity';
-
+
/**
* The forcePartialLoad query hint forces a particular query to return
* partial objects.
- *
+ *
* @var string
* @todo Rename: HINT_OPTIMIZE
*/
const HINT_FORCE_PARTIAL_LOAD = 'doctrine.forcePartialLoad';
/**
* The includeMetaColumns query hint causes meta columns like foreign keys and
* discriminator columns to be selected and returned as part of the query result.
- *
+ *
* This hint does only apply to non-object queries.
- *
+ *
* @var string
*/
const HINT_INCLUDE_META_COLUMNS = 'doctrine.includeMetaColumns';
@@ -122,12 +122,12 @@
* @var Doctrine\ORM\Query\ParserResult The parser result that holds DQL => SQL information.
*/
private $_parserResult;
-
+
/**
* @var integer The first result to return (the "offset").
*/
private $_firstResult = null;
-
+
/**
* @var integer The maximum number of results to return (the "limit").
*/
@@ -147,7 +147,7 @@
* @var int Query Cache lifetime.
*/
private $_queryCacheTTL;
-
+
/**
* @var boolean Whether to use a query cache, if available. Defaults to TRUE.
*/
@@ -191,7 +191,7 @@ public function getAST()
/**
* Parses the DQL query, if necessary, and stores the parser result.
- *
+ *
* Note: Populates $this->_parserResult as a side-effect.
*
* @return Doctrine\ORM\Query\ParserResult
@@ -201,12 +201,12 @@ private function _parse()
if ($this->_state === self::STATE_CLEAN) {
return $this->_parserResult;
}
-
+
// Check query cache.
if ($this->_useQueryCache && ($queryCache = $this->getQueryCacheDriver())) {
$hash = $this->_getQueryCacheId();
$cached = $this->_expireQueryCache ? false : $queryCache->fetch($hash);
-
+
if ($cached === false) {
// Cache miss.
$parser = new Parser($this);
@@ -220,9 +220,9 @@ private function _parse()
$parser = new Parser($this);
$this->_parserResult = $parser->parse();
}
-
+
$this->_state = self::STATE_CLEAN;
-
+
return $this->_parserResult;
}
@@ -244,55 +244,62 @@ protected function _doExecute()
}
list($sqlParams, $types) = $this->processParameterMappings($paramMappings);
-
+
if ($this->_resultSetMapping === null) {
$this->_resultSetMapping = $this->_parserResult->getResultSetMapping();
}
return $executor->execute($this->_em->getConnection(), $sqlParams, $types);
}
-
+
/**
* Processes query parameter mappings
- *
+ *
* @param array $paramMappings
* @return array
*/
private function processParameterMappings($paramMappings)
{
$sqlParams = $types = array();
-
+
foreach ($this->_params as $key => $value) {
if ( ! isset($paramMappings[$key])) {
throw QueryException::unknownParameter($key);
}
-
+
if (isset($this->_paramTypes[$key])) {
foreach ($paramMappings[$key] as $position) {
$types[$position] = $this->_paramTypes[$key];
}
}
-
+
$sqlPositions = $paramMappings[$key];
$value = array_values($this->processParameterValue($value));
$countValue = count($value);
-
+
for ($i = 0, $l = count($sqlPositions); $i < $l; $i++) {
$sqlParams[$sqlPositions[$i]] = $value[($i % $countValue)];
}
}
-
+
+ if (count($sqlParams) != count($types)) {
+ throw QueryException::parameterTypeMissmatch();
+ }
+
if ($sqlParams) {
ksort($sqlParams);
$sqlParams = array_values($sqlParams);
+
+ ksort($types);
+ $types = array_values($types);
}
return array($sqlParams, $types);
}
-
+
/**
* Process an individual parameter value
- *
+ *
* @param mixed $value
* @return array
*/
@@ -308,7 +315,7 @@ private function processParameterValue($value)
}
return array($value);
-
+
case is_object($value) && $this->_em->getMetadataFactory()->hasMetadataFor(get_class($value)):
if ($this->_em->getUnitOfWork()->getEntityState($value) === UnitOfWork::STATE_MANAGED) {
return array_values($this->_em->getUnitOfWork()->getEntityIdentifier($value));
@@ -317,7 +324,7 @@ private function processParameterValue($value)
$class = $this->_em->getClassMetadata(get_class($value));
return array_values($class->getIdentifierValues($value));
-
+
default:
return array($value);
}
@@ -334,10 +341,10 @@ public function setQueryCacheDriver($queryCache)
$this->_queryCache = $queryCache;
return $this;
}
-
+
/**
* Defines whether the query should make use of a query cache, if available.
- *
+ *
* @param boolean $bool
* @return @return Query This query instance.
*/
@@ -471,7 +478,7 @@ public function contains($dql)
{
return stripos($this->getDQL(), $dql) === false ? false : true;
}
-
+
/**
* Sets the position of the first result to retrieve (the "offset").
*
@@ -484,21 +491,21 @@ public function setFirstResult($firstResult)
$this->_state = self::STATE_DIRTY;
return $this;
}
-
+
/**
* Gets the position of the first result the query object was set to retrieve (the "offset").
* Returns NULL if {@link setFirstResult} was not applied to this query.
- *
+ *
* @return integer The position of the first result.
*/
public function getFirstResult()
{
return $this->_firstResult;
}
-
+
/**
* Sets the maximum number of results to retrieve (the "limit").
- *
+ *
* @param integer $maxResults
* @return Query This query object.
*/
@@ -508,11 +515,11 @@ public function setMaxResults($maxResults)
$this->_state = self::STATE_DIRTY;
return $this;
}
-
+
/**
* Gets the maximum number of results the query object was set to retrieve (the "limit").
* Returns NULL if {@link setMaxResults} was not applied to this query.
- *
+ *
* @return integer Maximum number of results.
*/
public function getMaxResults()
@@ -533,7 +540,7 @@ public function iterate(array $params = array(), $hydrationMode = self::HYDRATE_
$this->setHint(self::HINT_INTERNAL_ITERATION, true);
return parent::iterate($params, $hydrationMode);
}
-
+
/**
* {@inheritdoc}
*/
@@ -542,7 +549,7 @@ public function setHint($name, $value)
$this->_state = self::STATE_DIRTY;
return parent::setHint($name, $value);
}
-
+
/**
* {@inheritdoc}
*/
@@ -597,7 +604,7 @@ protected function _getQueryCacheId()
ksort($this->_hints);
return md5(
- $this->getDql() . var_export($this->_hints, true) .
+ $this->getDql() . var_export($this->_hints, true) .
'&firstResult=' . $this->_firstResult . '&maxResult=' . $this->_maxResults .
'&hydrationMode='.$this->_hydrationMode.'DOCTRINE_QUERY_CACHE_SALT'
);
@@ -77,6 +77,11 @@ public static function unknownParameter($key)
return new self("Invalid parameter: token ".$key." is not defined in the query.");
}
+ public static function parameterTypeMissmatch()
+ {
+ return new self("DQL Query parameter and type numbers missmatch, but have to be exactly equal.");
+ }
+
public static function invalidPathExpression($pathExpr)
{
return new self(
@@ -140,7 +145,7 @@ public static function associationPathCompositeKeyNotSupported()
"in the query."
);
}
-
+
public static function instanceOfUnrelatedClass($className, $rootClass)
{
return new self("Cannot check if a child of '" . $rootClass . "' is instanceof '" . $className . "', " .
Oops, something went wrong.

0 comments on commit 9e8a950

Please sign in to comment.