fix: handle cases where non-binary operators are mixed in for optimizing search queries

Signed-off-by: Robin Appelman <robin@icewind.nl>
pull/43975/head
Robin Appelman 3 months ago
parent 3971313d4c
commit 6fb447676e

@ -18,21 +18,19 @@ use OCP\Files\Search\ISearchOperator;
*/
class MergeDistributiveOperations extends ReplacingOptimizerStep {
public function processOperator(ISearchOperator &$operator): bool {
if (
$operator instanceof SearchBinaryOperator &&
$this->isAllSameBinaryOperation($operator->getArguments())
) {
if ($operator instanceof SearchBinaryOperator) {
// either 'AND' or 'OR'
$topLevelType = $operator->getType();
// split the arguments into groups that share a first argument
// (we already know that all arguments are binary operators with at least 1 child)
$groups = $this->groupBinaryOperatorsByChild($operator->getArguments(), 0);
$outerOperations = array_map(function (array $operators) use ($topLevelType) {
// no common operations, no need to change anything
if (count($operators) === 1) {
return $operators[0];
}
// for groups with size >1 we know they are binary operators with at least 1 child
/** @var ISearchBinaryOperator $firstArgument */
$firstArgument = $operators[0];
@ -72,46 +70,25 @@ class MergeDistributiveOperations extends ReplacingOptimizerStep {
return parent::processOperator($operator);
}
/**
* Check that a list of operators is all the same type of (non-empty) binary operators
*
* @param ISearchOperator[] $operators
* @return bool
* @psalm-assert-if-true SearchBinaryOperator[] $operators
*/
private function isAllSameBinaryOperation(array $operators): bool {
$operation = null;
foreach ($operators as $operator) {
if (!$operator instanceof SearchBinaryOperator) {
return false;
}
if (!$operator->getArguments()) {
return false;
}
if ($operation === null) {
$operation = $operator->getType();
} else {
if ($operation !== $operator->getType()) {
return false;
}
}
}
return true;
}
/**
* Group a list of binary search operators that have a common argument
*
* @param SearchBinaryOperator[] $operators
* @return SearchBinaryOperator[][]
* Non-binary operators, or empty binary operators will each get their own 1-sized group
*
* @param ISearchOperator[] $operators
* @return ISearchOperator[][]
*/
private function groupBinaryOperatorsByChild(array $operators, int $index = 0): array {
$result = [];
foreach ($operators as $operator) {
/** @var SearchBinaryOperator|SearchComparison $child */
$child = $operator->getArguments()[$index];
$childKey = (string) $child;
$result[$childKey][] = $operator;
if ($operator instanceof ISearchBinaryOperator && count($operator->getArguments()) > 0) {
/** @var SearchBinaryOperator|SearchComparison $child */
$child = $operator->getArguments()[$index];
$childKey = (string)$child;
$result[$childKey][] = $operator;
} else {
$result[] = [$operator];
}
}
return array_values($result);
}

Loading…
Cancel
Save