[BUGFIX] preparseQuery wrongly computes cache hash of a query 56/28656/7
authorXavier Perseguers <xavier@typo3.org>
Sun, 23 Mar 2014 08:54:36 +0000 (09:54 +0100)
committerXavier Perseguers <xavier@typo3.org>
Sun, 23 Mar 2014 17:08:53 +0000 (18:08 +0100)
preparseQuery only takes query's parameters to compute its hash but
not the operators used. As such, those two queries result into the
same cache hash:

SELECT * FROM fe_groups WHERE uid = :uid

SELECT * FROM fe_groups WHERE uid IN (:uid)

Fixes: #57173
Releases: 6.2
Change-Id: I6a65ba0be81da73f55c2e6a73f508728567064c3
Reviewed-on: https://review.typo3.org/28656
Reviewed-by: Felix Oertel
Tested-by: Felix Oertel
Reviewed-by: Markus Klein
Reviewed-by: Philipp Gampe
Tested-by: Philipp Gampe
typo3/sysext/extbase/Classes/Persistence/Generic/Storage/Typo3DbQueryParser.php
typo3/sysext/extbase/Tests/Functional/Persistence/QueryParserTest.php [new file with mode: 0644]

index 7afd27f..46303f6 100644 (file)
@@ -99,11 +99,12 @@ class Typo3DbQueryParser {
         * @return array the hash and the parameters
         */
        public function preparseQuery(\TYPO3\CMS\Extbase\Persistence\QueryInterface $query) {
-               $parameters = $this->preparseComparison($query->getConstraint());
+               list($parameters, $operators) = $this->preparseComparison($query->getConstraint());
                $hashPartials = array(
                        $query->getQuerySettings(),
                        $query->getSource(),
                        array_keys($parameters),
+                       $operators,
                        $query->getOrderings(),
                );
                $hash = md5(serialize($hashPartials));
@@ -121,11 +122,12 @@ class Typo3DbQueryParser {
         *
         * @param object $comparison The constraint. Could be And-, Or-, Not- or ComparisonInterface
         * @param string $qomPath current position of the child in the qom
-        * @return array string representation of constraint and array of parameters
+        * @return array Array of parameters and operators
         * @throws \Exception
         */
        protected function preparseComparison($comparison, $qomPath = '') {
                $parameters = array();
+               $operators = array();
                $objectsToParse = array();
 
                if ($comparison instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\AndInterface) {
@@ -140,22 +142,27 @@ class Typo3DbQueryParser {
                } elseif ($comparison instanceof \TYPO3\CMS\Extbase\Persistence\Generic\Qom\ComparisonInterface) {
                        $parameterIdentifier = $this->normalizeParameterIdentifier($qomPath . $comparison->getOperand1()->getPropertyName());
                        $comparison->setParameterIdentifier($parameterIdentifier);
+                       $operators[] = $comparison->getOperator();
                        $parameters[$parameterIdentifier] = $comparison->getOperand2();
                } elseif (!is_object($comparison)) {
-                       return array(array(), $comparison);
+                       $parameters = array(array(), $comparison);
+                       return array($parameters, $operators);
                } else {
                        throw new \Exception('Can not hash Query Component "' . get_class($comparison) . '".', 1392840462);
                }
 
                $childObjectIterator = 0;
                foreach ($objectsToParse as $objectToParse) {
-                       $preparsedParameters = $this->preparseComparison($objectToParse, $qomPath . $delimiter . $childObjectIterator++);
+                       list($preparsedParameters, $preparsedOperators) = $this->preparseComparison($objectToParse, $qomPath . $delimiter . $childObjectIterator++);
                        if (!empty($preparsedParameters)) {
                                $parameters = array_merge($parameters, $preparsedParameters);
                        }
+                       if (!empty($preparsedOperators)) {
+                               $operators = array_merge($operators, $preparsedOperators);
+                       }
                }
 
-               return $parameters;
+               return array($parameters, $operators);
        }
 
        /**
diff --git a/typo3/sysext/extbase/Tests/Functional/Persistence/QueryParserTest.php b/typo3/sysext/extbase/Tests/Functional/Persistence/QueryParserTest.php
new file mode 100644 (file)
index 0000000..1af535f
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+namespace TYPO3\CMS\Extbase\Tests\Functional\Persistence;
+
+/***************************************************************
+ *  Copyright notice
+ *
+ *  (c) 2014 Felix Oertel <typo3@foertel.com>
+ *  All rights reserved
+ *
+ *  This script is part of the TYPO3 project. The TYPO3 project is
+ *  free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  The GNU General Public License can be found at
+ *  http://www.gnu.org/copyleft/gpl.html.
+ *
+ *  This script is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  This copyright notice MUST APPEAR in all copies of the script!
+ ***************************************************************/
+
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+use TYPO3\CMS\Extbase\Persistence\ObjectStorage;
+
+class QueryParserTest extends \TYPO3\CMS\Core\Tests\FunctionalTestCase {
+
+       /**
+        * @var \TYPO3\CMS\Extbase\Persistence\Generic\Storage\Typo3DbQueryParser
+        */
+       protected $queryParser;
+
+       /**
+        * @var array
+        */
+       protected $testExtensionsToLoad = array('typo3/sysext/extbase/Tests/Functional/Fixtures/Extensions/blog_example');
+
+       /**
+        * @var array
+        */
+       protected $coreExtensionsToLoad = array('extbase', 'fluid');
+
+       /**
+        * @var \TYPO3\CMS\Extbase\Object\ObjectManagerInterface The object manager
+        */
+       protected $objectManager;
+
+       /**
+        * Sets up this test suite.
+        */
+       public function setUp() {
+               parent::setUp();
+
+               $this->objectManager = GeneralUtility::makeInstance('TYPO3\\CMS\\Extbase\\Object\\ObjectManager');
+               $this->queryParser = $this->objectManager->get('TYPO3\\CMS\\Extbase\\Persistence\\Generic\\Storage\\Typo3DbQueryParser');
+               $this->blogRepository = $this->objectManager->get('ExtbaseTeam\\BlogExample\\Domain\\Repository\\BlogRepository');
+       }
+
+       /**
+        * @test
+        */
+       public function preparseQueryTakesOperatorsIntoHash() {
+               $queryWithEquals = $this->blogRepository->createQuery();
+
+               $queryWithEquals->matching(
+                       $queryWithEquals->equals('uid', 1)
+               );
+
+               list($hashWithEquals) = $this->queryParser->preparseQuery($queryWithEquals);
+
+               $queryWithIn = $this->blogRepository->createQuery();
+
+               $queryWithIn->matching(
+                       $queryWithIn->in('uid', array(1))
+               );
+
+               list($hashWithIn) = $this->queryParser->preparseQuery($queryWithIn);
+
+               $this->assertNotSame($hashWithEquals, $hashWithIn);
+       }
+}