]> source.dussan.org Git - nextcloud-server.git/commitdiff
do cachejail search filtering in sql
authorRobin Appelman <robin@icewind.nl>
Thu, 14 Jan 2021 18:03:39 +0000 (19:03 +0100)
committerDaniel Kesselberg <mail@danielkesselberg.de>
Tue, 16 Mar 2021 14:22:22 +0000 (15:22 +0100)
Signed-off-by: Robin Appelman <robin@icewind.nl>
lib/private/Files/Cache/Cache.php
lib/private/Files/Cache/QuerySearchHelper.php
lib/private/Files/Cache/Wrapper/CacheJail.php
tests/lib/Files/Cache/Wrapper/CacheJailTest.php

index 6de3c41e56aafa519421bf309ffc027018555774..b8ca9e6e1b75dc154131198fd4e5a79ddbac5341 100644 (file)
@@ -113,7 +113,7 @@ class Cache implements ICache {
                $this->querySearchHelper = new QuerySearchHelper($this->mimetypeLoader);
        }
 
-       private function getQueryBuilder() {
+       protected function getQueryBuilder() {
                return new CacheQueryBuilder(
                        $this->connection,
                        \OC::$server->getSystemConfig(),
index 574b4c18d5dffb1742d2d18d01336002ff6e34a3..5e33ad235a083984b20f95077aa31b99ca80eec2 100644 (file)
@@ -175,6 +175,7 @@ class QuerySearchHelper {
                        'mimetype' => 'string',
                        'mtime' => 'integer',
                        'name' => 'string',
+                       'path' => 'string',
                        'size' => 'integer',
                        'tagname' => 'string',
                        'favorite' => 'boolean',
@@ -184,6 +185,7 @@ class QuerySearchHelper {
                        'mimetype' => ['eq', 'like'],
                        'mtime' => ['eq', 'gt', 'lt', 'gte', 'lte'],
                        'name' => ['eq', 'like'],
+                       'path' => ['eq', 'like'],
                        'size' => ['eq', 'gt', 'lt', 'gte', 'lte'],
                        'tagname' => ['eq', 'like'],
                        'favorite' => ['eq'],
index 6c1c17be028c201f2f8f0abc79f7c0dab5e48780..27590fb74180f0e56ce5a9124bf7d6d03946fa97 100644 (file)
 namespace OC\Files\Cache\Wrapper;
 
 use OC\Files\Cache\Cache;
+use OC\Files\Search\SearchBinaryOperator;
+use OC\Files\Search\SearchComparison;
 use OC\Files\Search\SearchQuery;
+use OCP\DB\QueryBuilder\IQueryBuilder;
 use OCP\Files\Cache\ICacheEntry;
+use OCP\Files\Search\ISearchBinaryOperator;
+use OCP\Files\Search\ISearchComparison;
 use OCP\Files\Search\ISearchQuery;
 
 /**
@@ -49,6 +54,8 @@ class CacheJail extends CacheWrapper {
        public function __construct($cache, $root) {
                parent::__construct($cache);
                $this->root = $root;
+               $this->connection = \OC::$server->getDatabaseConnection();
+               $this->mimetypeLoader = \OC::$server->getMimeTypeLoader();
        }
 
        protected function getRoot() {
@@ -221,7 +228,26 @@ class CacheJail extends CacheWrapper {
         * @return array an array of file data
         */
        public function search($pattern) {
-               $results = $this->getCache()->search($pattern);
+               // normalize pattern
+               $pattern = $this->normalize($pattern);
+
+               if ($pattern === '%%') {
+                       return [];
+               }
+
+               $query = $this->getQueryBuilder();
+               $query->selectFileCache()
+                       ->whereStorageId()
+                       ->andWhere($query->expr()->like('path', $query->createNamedParameter($this->getRoot() . '/%')))
+                       ->andWhere($query->expr()->iLike('name', $query->createNamedParameter($pattern)));
+
+               $result = $query->execute();
+               $files = $result->fetchAll();
+               $result->closeCursor();
+
+               $results = array_map(function (array $data) {
+                       return self::cacheEntryFromData($data, $this->mimetypeLoader);
+               }, $files);
                return $this->formatSearchResults($results);
        }
 
@@ -232,12 +258,40 @@ class CacheJail extends CacheWrapper {
         * @return array
         */
        public function searchByMime($mimetype) {
-               $results = $this->getCache()->searchByMime($mimetype);
+               $mimeId = $this->mimetypeLoader->getId($mimetype);
+
+               $query = $this->getQueryBuilder();
+               $query->selectFileCache()
+                       ->whereStorageId()
+                       ->andWhere($query->expr()->like('path', $query->createNamedParameter($this->getRoot() . '/%')));
+
+               if (strpos($mimetype, '/')) {
+                       $query->andWhere($query->expr()->eq('mimetype', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT)));
+               } else {
+                       $query->andWhere($query->expr()->eq('mimepart', $query->createNamedParameter($mimeId, IQueryBuilder::PARAM_INT)));
+               }
+
+               $result = $query->execute();
+               $files = $result->fetchAll();
+               $result->closeCursor();
+
+               $results = array_map(function (array $data) {
+                       return self::cacheEntryFromData($data, $this->mimetypeLoader);
+               }, $files);
                return $this->formatSearchResults($results);
        }
 
        public function searchQuery(ISearchQuery $query) {
-               $simpleQuery = new SearchQuery($query->getSearchOperation(), 0, 0, $query->getOrder(), $query->getUser());
+               $prefixFilter = new SearchComparison(
+                       ISearchComparison::COMPARE_LIKE,
+                       'path',
+                       $this->getRoot() . '/%'
+               );
+               $operation = new SearchBinaryOperator(
+                       ISearchBinaryOperator::OPERATOR_AND,
+                       [$prefixFilter, $query->getSearchOperation()]
+               );
+               $simpleQuery = new SearchQuery($operation, 0, 0, $query->getOrder(), $query->getUser());
                $results = $this->getCache()->searchQuery($simpleQuery);
                $results = $this->formatSearchResults($results);
 
index f0943ba5a034e2626813d46c12ac8e27e3f184c0..83173efd3b61ece4b26f5cf20ce722495d41c47c 100644 (file)
@@ -9,6 +9,11 @@
 namespace Test\Files\Cache\Wrapper;
 
 use OC\Files\Cache\Wrapper\CacheJail;
+use OC\Files\Search\SearchComparison;
+use OC\Files\Search\SearchQuery;
+use OC\User\User;
+use OCP\Files\Search\ISearchComparison;
+use Symfony\Component\EventDispatcher\EventDispatcherInterface;
 use Test\Files\Cache\CacheTest;
 
 /**
@@ -46,6 +51,38 @@ class CacheJailTest extends CacheTest {
                $this->assertEquals('foobar', $result[0]['path']);
        }
 
+       public function testSearchMimeOutsideJail() {
+               $file1 = 'foo/foobar';
+               $file2 = 'folder/foobar';
+               $data1 = ['size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder'];
+
+               $this->sourceCache->put($file1, $data1);
+               $this->sourceCache->put($file2, $data1);
+
+               $this->assertCount(2, $this->sourceCache->searchByMime('foo/folder'));
+
+               $result = $this->cache->search('%foobar%');
+               $this->assertCount(1, $result);
+               $this->assertEquals('foobar', $result[0]['path']);
+       }
+
+       public function testSearchQueryOutsideJail() {
+               $file1 = 'foo/foobar';
+               $file2 = 'folder/foobar';
+               $data1 = ['size' => 100, 'mtime' => 50, 'mimetype' => 'foo/folder'];
+
+               $this->sourceCache->put($file1, $data1);
+               $this->sourceCache->put($file2, $data1);
+
+               $user = new User('foo', null, $this->createMock(EventDispatcherInterface::class));
+               $query = new SearchQuery(new SearchComparison(ISearchComparison::COMPARE_EQUAL, 'name', 'foobar'), 10, 0, [], $user);
+               $this->assertCount(2, $this->sourceCache->searchQuery($query));
+
+               $result = $this->cache->search('%foobar%');
+               $this->assertCount(1, $result);
+               $this->assertEquals('foobar', $result[0]['path']);
+       }
+
        public function testClearKeepEntriesOutsideJail() {
                $file1 = 'foo/foobar';
                $file2 = 'foo/foobar/asd';