Commit 68f1f4a8 authored by Stefan Bürk's avatar Stefan Bürk Committed by Oliver Bartsch
Browse files

[BUGFIX] Avoid unreliable 'rowCount()' in IndexSearchRepository

rowCount() on result sets for SELECT queries are not reliable across
all DBMS, which doctrine/dbal comments in the docblock. See:
https://github.com/doctrine/dbal/blob/110ab13/src/Driver/Result.php#L77

Because of "rowCount()"'s unreliable behaviour for some dbms like
sqlite, this should be avoided to ensure cross dbms support.

'\TYPO3\CMS\IndexedSearch\Domain\Repository\IndexSearchRepository'
uses 'rowCount()' in 'doSearch()' which fails on sqlite, making it
impossible to get any result in the frontend search.

Doing a count() query as replacement is not possible and needs a
bigger architectural change, which is not feasable as bugfix.
Thus fallback to retrieve the result into an array and counting
the array is used as a intermediate solution to ensure index_search
is working across all supported database systems.

The architectural change will be done in a dedicated patch.

Resolves: #97460
Releases: main, 11.5
Change-Id: Id7afa9f95fefbba07acb7c0dda1267dd2fce92db
Reviewed-on: https://review.typo3.org/c/Packages/TYPO3.CMS/+/74380

Tested-by: core-ci's avatarcore-ci <typo3@b13.com>
Tested-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Tested-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
Reviewed-by: Benni Mack's avatarBenni Mack <benni@typo3.org>
Reviewed-by: Oliver Bartsch's avatarOliver Bartsch <bo@cedev.de>
parent 6f7514f5
......@@ -181,6 +181,8 @@ class IndexSearchRepository
$useMysqlFulltext = (bool)GeneralUtility::makeInstance(ExtensionConfiguration::class)->get('indexed_search', 'useMysqlFulltext');
// Getting SQL result pointer:
$this->getTimeTracker()->push('Searching result');
// @todo Change hook and method signatures to return the QueryBuilder instead the Result. Consider to move
// from hook to a proper PSR-14 event.
if ($hookObj = $this->hookRequest('getResultRows_SQLpointer')) {
$result = $hookObj->getResultRows_SQLpointer($searchWords, $freeIndexUid);
} elseif ($useMysqlFulltext) {
......@@ -191,8 +193,14 @@ class IndexSearchRepository
$this->getTimeTracker()->pull();
// Organize and process result:
if ($result) {
// We need the result row count beforehand for the pointer calculation. Using $result->rowCount() for
// select queries is not reliable across dbms systems, and in case of sqlite this will return 0 here,
// even if there is a result set, we need to retrieve all rows and doing a count on the array.
// @todo Change this to second count() query call, after getResultRows_SQLpointer() signatures/hook has
// been changed to return QueryBuilder instead of the Result.
$rows = $result->fetchAllAssociative();
// Total search-result count
$count = $result->rowCount();
$count = count($rows);
// The pointer is set to the result page that is currently being viewed
$pointer = MathUtility::forceIntegerInRange($this->resultpagePointer, 0, (int)floor($count / $this->numberOfResults));
// Initialize result accumulation variables:
......@@ -209,7 +217,9 @@ class IndexSearchRepository
// Now, traverse result and put the rows to be displayed into an array
// Each row should contain the fields from 'ISEC.*, IP.*' combined
// + artificial fields "show_resume" (bool) and "result_number" (counter)
while ($row = $result->fetchAssociative()) {
// @todo Change this back to while($row = $result->fetchAssociative()) after changing
// getResultRows_SQLpointer() returning QueryBuilder instead of a Result.
foreach ($rows as $row) {
// Set first row
if (!$c) {
$firstRow = $row;
......@@ -253,8 +263,6 @@ class IndexSearchRepository
}
}
$result->free();
return [
'resultRows' => $resultRows,
'firstRow' => $firstRow,
......
Supports Markdown
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