diff --git a/src/engine/imap-db/imap-db-folder.vala b/src/engine/imap-db/imap-db-folder.vala index 489dc908..b6ff465c 100644 --- a/src/engine/imap-db/imap-db-folder.vala +++ b/src/engine/imap-db/imap-db-folder.vala @@ -882,16 +882,18 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics { }, cancellable); } - public async void detach_emails_before_timestamp(DateTime cutoff, + public async Gee.Collection? detach_emails_before_timestamp(DateTime cutoff, Cancellable? cancellable) throws Error { debug("Detaching emails before %s for folder ID %", cutoff.to_string(), this.folder_id.to_string()); + Gee.Collection? deleted_ids = null; yield db.exec_transaction_async(Db.TransactionType.WO, (cx) => { - // Query was found to be faster than other approaches. MessageLocationTable.ordering - // isn't relied on due to IMAP folder UIDs not guaranteed to be in order. + // MessageLocationTable.ordering isn't relied on due to IMAP folder + // UIDs not guaranteed to be in order. StringBuilder sql = new StringBuilder(); sql.append(""" - DELETE FROM MessageLocationTable + SELECT id, message_id, ordering + FROM MessageLocationTable WHERE folder_id = ? AND message_id IN ( SELECT id @@ -902,12 +904,45 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics { """); Db.Statement stmt = cx.prepare(sql.str); - stmt.bind_rowid(0, this.folder_id); + stmt.bind_rowid(0, folder_id); stmt.bind_int64(1, cutoff.to_unix()); - stmt.exec(cancellable); - return Db.TransactionOutcome.COMMIT; + Db.Result results = stmt.exec(cancellable); + + StringBuilder? ids_sql_sublist = null; + while (!results.finished) { + if (ids_sql_sublist == null) { + deleted_ids = new Gee.ArrayList(); + ids_sql_sublist = new StringBuilder(); + } else { + ids_sql_sublist.append(","); + } + + deleted_ids.add(new ImapDB.EmailIdentifier(results.int64_at(1), new Imap.UID(results.int64_at(2)))); + ids_sql_sublist.append(results.rowid_at(0).to_string()); + + results.next(cancellable); + } + + if (deleted_ids != null) { + sql = new StringBuilder(); + sql.append(""" + DELETE FROM MessageLocationTable + WHERE id IN ( + """); + sql.append(ids_sql_sublist.str); + sql.append(")"); + stmt = cx.prepare(sql.str); + + stmt.exec(cancellable); + + return Db.TransactionOutcome.COMMIT; + } else { + return Db.TransactionOutcome.DONE; + } }, cancellable); + + return deleted_ids; } public async void mark_email_async(Gee.Collection to_mark, diff --git a/src/engine/imap-engine/imap-engine-account-synchronizer.vala b/src/engine/imap-engine/imap-engine-account-synchronizer.vala index f0f2b84c..654ca039 100644 --- a/src/engine/imap-engine/imap-engine-account-synchronizer.vala +++ b/src/engine/imap-engine/imap-engine-account-synchronizer.vala @@ -247,7 +247,10 @@ private class Geary.ImapEngine.CheckFolderSync : RefreshFolderSync { // Detach older emails outside the prefetch window if (this.account.information.prefetch_period_days >= 0) { - yield local_folder.detach_emails_before_timestamp(prefetch_max_epoch, cancellable); + Gee.Collection? detached_ids = yield local_folder.detach_emails_before_timestamp(prefetch_max_epoch, cancellable); + if (detached_ids != null) { + this.folder.email_locally_removed(detached_ids); + } } // get oldest local email and its time, as well as number