diff --git a/lib/private/Files/Cache/FileAccess.php b/lib/private/Files/Cache/FileAccess.php index 016ff6de46ec7..6de080e7fc704 100644 --- a/lib/private/Files/Cache/FileAccess.php +++ b/lib/private/Files/Cache/FileAccess.php @@ -81,11 +81,16 @@ private function rowsToEntries(array $rows): array { */ #[\Override] public function getByFileIds(array $fileIds): array { - $query = $this->getQuery()->selectFileCache(); - $query->andWhere($query->expr()->in('filecache.fileid', $query->createNamedParameter($fileIds, IQueryBuilder::PARAM_INT_ARRAY))); - - $rows = $query->executeQuery()->fetchAll(); - return $this->rowsToEntries($rows); + if (empty($fileIds)) { + return []; + } + $result = []; + foreach (array_chunk($fileIds, 1000) as $chunk) { + $query = $this->getQuery()->selectFileCache(); + $query->andWhere($query->expr()->in('filecache.fileid', $query->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY))); + $result += $this->rowsToEntries($query->executeQuery()->fetchAll()); + } + return $result; } /** @@ -95,13 +100,17 @@ public function getByFileIds(array $fileIds): array { */ #[\Override] public function getByFileIdsInStorage(array $fileIds, int $storageId): array { - $fileIds = array_values($fileIds); - $query = $this->getQuery()->selectFileCache(); - $query->andWhere($query->expr()->in('filecache.fileid', $query->createNamedParameter($fileIds, IQueryBuilder::PARAM_INT_ARRAY))); - $query->andWhere($query->expr()->eq('filecache.storage', $query->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); - - $rows = $query->executeQuery()->fetchAll(); - return $this->rowsToEntries($rows); + if (empty($fileIds)) { + return []; + } + $result = []; + foreach (array_chunk(array_values($fileIds), 1000) as $chunk) { + $query = $this->getQuery()->selectFileCache(); + $query->andWhere($query->expr()->in('filecache.fileid', $query->createNamedParameter($chunk, IQueryBuilder::PARAM_INT_ARRAY))); + $query->andWhere($query->expr()->eq('filecache.storage', $query->createNamedParameter($storageId, IQueryBuilder::PARAM_INT))); + $result += $this->rowsToEntries($query->executeQuery()->fetchAll()); + } + return $result; } #[\Override] diff --git a/lib/private/Files/SetupManager.php b/lib/private/Files/SetupManager.php index a8c46a20bd31a..184a9fc412924 100644 --- a/lib/private/Files/SetupManager.php +++ b/lib/private/Files/SetupManager.php @@ -604,12 +604,7 @@ public function setupForPath(string $path, bool $includeChildren = false): void array_merge(...array_values($authoritativeCachedMounts)), ); - $rootsMetadata = []; - foreach (array_chunk($rootIds, 1000) as $chunk) { - foreach ($this->fileAccess->getByFileIds($chunk) as $id => $fileMetadata) { - $rootsMetadata[$id] = $fileMetadata; - } - } + $rootsMetadata = $this->fileAccess->getByFileIds($rootIds); $this->setupMountProviderPaths[$mountPoint] = self::SETUP_WITH_CHILDREN; foreach ($authoritativeCachedMounts as $providerClass => $cachedMounts) { $providerArgs = array_values(array_filter(array_map( diff --git a/tests/lib/Files/Cache/FileAccessTest.php b/tests/lib/Files/Cache/FileAccessTest.php index 169a07180eeca..5355a7a9baff5 100644 --- a/tests/lib/Files/Cache/FileAccessTest.php +++ b/tests/lib/Files/Cache/FileAccessTest.php @@ -303,6 +303,71 @@ private function setUpTestDatabaseForGetByAncestorInStorage(): void { ->executeStatement(); } + public function testGetByFileIds(): void { + $result = $this->fileAccess->getByFileIds([1, 2, 3]); + + $this->assertCount(3, $result); + $this->assertArrayHasKey(1, $result); + $this->assertArrayHasKey(2, $result); + $this->assertArrayHasKey(3, $result); + } + + public function testGetByFileIdsWithEmptyArray(): void { + $result = $this->fileAccess->getByFileIds([]); + $this->assertCount(0, $result); + } + + public function testGetByFileIdsWithNonExistentIds(): void { + $result = $this->fileAccess->getByFileIds([9998, 9999]); + $this->assertCount(0, $result); + } + + public function testGetByFileIdsSpanningChunkBoundary(): void { + // 1001 IDs exceeds Oracle's 1000-element IN limit — verifies chunked queries return correct results + $ids = range(1, 1001); + $result = $this->fileAccess->getByFileIds($ids); + + // Only fileids 1–7 exist in the test data + $this->assertCount(7, $result); + foreach (range(1, 7) as $id) { + $this->assertArrayHasKey($id, $result); + } + } + + public function testGetByFileIdsInStorage(): void { + $result = $this->fileAccess->getByFileIdsInStorage([1, 2, 3], 1); + + $this->assertCount(3, $result); + $this->assertArrayHasKey(1, $result); + $this->assertArrayHasKey(2, $result); + $this->assertArrayHasKey(3, $result); + } + + public function testGetByFileIdsInStorageFiltersStorage(): void { + // fileids 6 and 7 belong to storage 2, not storage 1 + $result = $this->fileAccess->getByFileIdsInStorage([1, 6, 7], 1); + + $this->assertCount(1, $result); + $this->assertArrayHasKey(1, $result); + } + + public function testGetByFileIdsInStorageWithEmptyArray(): void { + $result = $this->fileAccess->getByFileIdsInStorage([], 1); + $this->assertCount(0, $result); + } + + public function testGetByFileIdsInStorageSpanningChunkBoundary(): void { + // 1001 IDs exceeds Oracle's 1000-element IN limit — verifies chunked queries return correct results + $ids = range(1, 1001); + $result = $this->fileAccess->getByFileIdsInStorage($ids, 1); + + // fileids 1–5 are in storage 1; 6 and 7 are in storage 2 + $this->assertCount(5, $result); + foreach (range(1, 5) as $id) { + $this->assertArrayHasKey($id, $result); + } + } + /** * Test fetching files by ancestor in storage. */