diff --git a/appinfo/info.xml b/appinfo/info.xml
index 2e73f5125..1141c153b 100644
--- a/appinfo/info.xml
+++ b/appinfo/info.xml
@@ -9,7 +9,7 @@
Photos
Your memories under your control
Your memories under your control
- 3.0.1
+ 3.0.2
agpl
John Molakvoæ
Photos
@@ -22,7 +22,6 @@
https://github.com/nextcloud/photos
https://github.com/nextcloud/photos/issues
https://github.com/nextcloud/photos.git
-
diff --git a/lib/Migration/Version30000Date20240417075404.php b/lib/Migration/Version30000Date20240417075405.php
similarity index 75%
rename from lib/Migration/Version30000Date20240417075404.php
rename to lib/Migration/Version30000Date20240417075405.php
index 2ec038d22..ed3c59b9a 100644
--- a/lib/Migration/Version30000Date20240417075404.php
+++ b/lib/Migration/Version30000Date20240417075405.php
@@ -11,6 +11,7 @@
use Closure;
use OCP\DB\ISchemaWrapper;
+use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
@@ -18,7 +19,7 @@
/**
* Migrate the photosSourceFolder user config to photosSourceFolders
*/
-class Version30000Date20240417075404 extends SimpleMigrationStep {
+class Version30000Date20240417075405 extends SimpleMigrationStep {
public function __construct(
private IDBConnection $db,
) {
@@ -36,13 +37,26 @@ public function postSchemaChange(IOutput $output, Closure $schemaClosure, array
->where($select->expr()->eq('appid', $select->expr()->literal('photos')))
->andWhere($select->expr()->eq('configkey', $select->expr()->literal('photosSourceFolders')));
+ $result = $select->executeQuery();
+ $alreadyMigrated = array_map(static fn (array $row) => $row['userid'], $result->fetchAll());
+ $result->closeCursor();
+
// Remove old entries for users who already have the new one
$delete = $this->db->getQueryBuilder();
$delete->delete('preferences')
->where($delete->expr()->eq('appid', $delete->expr()->literal('photos')))
->andWhere($delete->expr()->eq('configkey', $delete->expr()->literal('photosSourceFolder')))
- ->andWhere($delete->expr()->in('userid', $delete->createFunction($select->getSQL())))
- ->executeStatement();
+ ->andWhere($delete->expr()->in(
+ 'userid',
+ $delete->createParameter('chunk'),
+ IQueryBuilder::PARAM_STR
+ ));
+
+ $chunks = array_chunk($alreadyMigrated, 1000);
+ foreach ($chunks as $chunk) {
+ $delete->setParameter('chunk', $chunk, IQueryBuilder::PARAM_STR_ARRAY);
+ $delete->executeStatement();
+ }
// Update remaining old entries to new ones
$update = $this->db->getQueryBuilder();
diff --git a/tests/Migration/Version30000Date20240417075405Test.php b/tests/Migration/Version30000Date20240417075405Test.php
new file mode 100644
index 000000000..4d0d73055
--- /dev/null
+++ b/tests/Migration/Version30000Date20240417075405Test.php
@@ -0,0 +1,102 @@
+connection = \OCP\Server::get(IDBConnection::class);
+ }
+
+ protected function tearDown(): void {
+ $this->deleteTestEntries();
+ parent::tearDown();
+ }
+
+ protected function deleteTestEntries(): void {
+ $delete = $this->connection->getQueryBuilder();
+ $delete->delete('preferences')
+ ->where($delete->expr()->like('userid', $delete->createNamedParameter('Version30000Date20240417075405Test%')));
+ $delete->executeStatement();
+ }
+
+ protected function createTestEntries(): void {
+ $this->deleteTestEntries();
+
+ $insert = $this->connection->getQueryBuilder();
+ $insert->insert('preferences')
+ ->values([
+ 'userid' => $insert->createParameter('userid'),
+ 'appid' => $insert->createNamedParameter('photos'),
+ 'configkey' => $insert->createParameter('configkey'),
+ 'configvalue' => $insert->createNamedParameter('value'),
+ ]);
+
+ $this->connection->beginTransaction();
+ for ($i = 1; $i <= 3000; $i++) {
+ $mod = $i % 3;
+ if ($mod !== 0) {
+ $insert->setParameter('userid', 'Version30000Date20240417075405Test#' . $i)
+ ->setParameter('configkey', 'photosSourceFolder');
+ $insert->executeStatement();
+ }
+ if ($mod !== 1) {
+ $insert->setParameter('userid', 'Version30000Date20240417075405Test#' . $i)
+ ->setParameter('configkey', 'photosSourceFolders');
+ $insert->executeStatement();
+ }
+ }
+ $this->connection->commit();
+ }
+
+ public function testPostSchemaChange(): void {
+ $migration = new Version30000Date20240417075405($this->connection);
+
+ $this->createTestEntries();
+
+
+ $migration->postSchemaChange(
+ $this->createMock(IOutput::class),
+ \Closure::fromCallable(fn () => false),
+ []
+ );
+
+ $select = $this->connection->getQueryBuilder();
+ $select->select($select->func()->count())
+ ->from('preferences')
+ ->where($select->expr()->like('userid', $select->createNamedParameter('Version30000Date20240417075405Test%')))
+ ->andWhere($select->expr()->eq('appid', $select->expr()->literal('photos')))
+ ->andWhere($select->expr()->eq('configkey', $select->expr()->literal('photosSourceFolder')));
+ $result = $select->executeQuery();
+ $this->assertEquals(0, $result->fetchOne());
+ $result->closeCursor();
+
+ $select = $this->connection->getQueryBuilder();
+ $select->select($select->func()->count())
+ ->from('preferences')
+ ->where($select->expr()->like('userid', $select->createNamedParameter('Version30000Date20240417075405Test%')))
+ ->andWhere($select->expr()->eq('appid', $select->expr()->literal('photos')))
+ ->andWhere($select->expr()->eq('configkey', $select->expr()->literal('photosSourceFolders')));
+ $result = $select->executeQuery();
+ $this->assertEquals(3000, $result->fetchOne());
+ $result->closeCursor();
+ }
+}