From 00e7b2b956e2901a9c3baa13af3948f1cd67378e Mon Sep 17 00:00:00 2001 From: Joas Schilling Date: Thu, 4 Jun 2020 10:23:23 +0200 Subject: [PATCH] Reduce load of the contacts search when we know it can't match Signed-off-by: Joas Schilling --- apps/dav/lib/CardDAV/CardDavBackend.php | 30 +++++++++++++++---- .../tests/unit/CardDAV/CardDavBackendTest.php | 2 +- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/apps/dav/lib/CardDAV/CardDavBackend.php b/apps/dav/lib/CardDAV/CardDavBackend.php index 40b48f69ae0..8fb48d062d0 100644 --- a/apps/dav/lib/CardDAV/CardDavBackend.php +++ b/apps/dav/lib/CardDAV/CardDavBackend.php @@ -949,20 +949,38 @@ class CardDavBackend implements BackendInterface, SyncSupport { * @return array an array of contacts which are arrays of key-value-pairs */ public function search($addressBookId, $pattern, $searchProperties, $options = []) { - $query2 = $this->db->getQueryBuilder(); + $escapePattern = !\array_key_exists('escape_like_param', $options) || $options['escape_like_param'] !== false; - $query2->selectDistinct('cp.cardid') - ->from($this->dbCardsPropertiesTable, 'cp') - ->andWhere($query2->expr()->eq('cp.addressbookid', $query2->createNamedParameter($addressBookId))); + $query2 = $this->db->getQueryBuilder(); $or = $query2->expr()->orX(); foreach ($searchProperties as $property) { + if ($escapePattern) { + if ($property === 'EMAIL' && strpos($pattern, ' ') !== false) { + // There can be no spaces in emails + continue; + } + + if ($property === 'CLOUD' && preg_match('/[^a-zA-Z0-9 _.@\-\']/', $pattern) === 1) { + // There can be no chars in cloud ids which are not valid for user ids + continue; + } + } + $or->add($query2->expr()->eq('cp.name', $query2->createNamedParameter($property))); } - $query2->andWhere($or); + + if ($or->count() === 0) { + return []; + } + + $query2->selectDistinct('cp.cardid') + ->from($this->dbCardsPropertiesTable, 'cp') + ->andWhere($query2->expr()->eq('cp.addressbookid', $query2->createNamedParameter($addressBookId))) + ->andWhere($or); // No need for like when the pattern is empty if ('' !== $pattern) { - if (\array_key_exists('escape_like_param', $options) && $options['escape_like_param'] === false) { + if (!$escapePattern) { $query2->andWhere($query2->expr()->ilike('cp.value', $query2->createNamedParameter($pattern))); } else { $query2->andWhere($query2->expr()->ilike('cp.value', $query2->createNamedParameter('%' . $this->db->escapeLikeParameter($pattern) . '%'))); diff --git a/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php b/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php index 27139dfd470..c32aad5a056 100644 --- a/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php +++ b/apps/dav/tests/unit/CardDAV/CardDavBackendTest.php @@ -762,7 +762,7 @@ class CardDavBackendTest extends TestCase { 'limit' => ['john', ['FN'], ['limit' => 1], [['uri0', 'John Doe']]], 'limit and offset' => ['john', ['FN'], ['limit' => 1, 'offset' => 1], [['uri1', 'John M. Doe']]], 'find "_" escaped' => ['_', ['CLOUD'], [], [['uri2', 'find without options']]], - 'find not empty ClOUD' => ['%_%', ['CLOUD'], ['escape_like_param'=>false], [['uri0', 'John Doe'], ['uri2', 'find without options']]], + 'find not empty CLOUD' => ['%_%', ['CLOUD'], ['escape_like_param'=>false], [['uri0', 'John Doe'], ['uri2', 'find without options']]], ]; } -- 2.39.5