From b375a411d7222075fb3df01e8d9f78e49e0613b7 Mon Sep 17 00:00:00 2001 From: Michael James Gratton Date: Fri, 14 Oct 2016 12:00:19 +1100 Subject: [PATCH] Work around for UPDATE causing FTS search table corruption. Bug 772522. * src/engine/imap-db/imap-db-folder.vala (Folder::do_merge_email_in_search_table): Instead of doing an UPDATE, which will lkely corrupt MessageSearchTable, do a SELECT/DELETE/INSERT. --- src/engine/imap-db/imap-db-folder.vala | 92 ++++++++++++++++---------- 1 file changed, 57 insertions(+), 35 deletions(-) diff --git a/src/engine/imap-db/imap-db-folder.vala b/src/engine/imap-db/imap-db-folder.vala index 9d0b90be..d059222e 100644 --- a/src/engine/imap-db/imap-db-folder.vala +++ b/src/engine/imap-db/imap-db-folder.vala @@ -1809,63 +1809,85 @@ private class Geary.ImapDB.Folder : BaseObject, Geary.ReferenceSemantics { do_update_contact(cx, contact, cancellable); updated_contacts = message_addresses.contacts; } - + private void do_merge_email_in_search_table(Db.Connection cx, int64 message_id, Geary.Email.Field new_fields, Geary.Email email, Cancellable? cancellable) throws Error { + + // We can't simply issue an UPDATE here for the changed + // fields, since it will likely corrupt the + // MessageSearchTable. So instead do a SELECT to get the + // existing data, then do a DELETE and INSERT. See Bug 772522. + + Db.Statement select = cx.prepare(""" + SELECT body, attachment, subject, from_field, receivers, cc, bcc + FROM MessageSearchTable + WHERE docid=? + """); + select.bind_rowid(0, message_id); + Db.Result row = select.exec(cancellable); + + string? body = row.string_at(0); + string? attachments = row.string_at(1); + string? subject = row.string_at(2); + string? from = row.string_at(3); + string? recipients = row.string_at(4); + string? cc = row.string_at(5); + string? bcc = row.string_at(6); + if (new_fields.is_any_set(Geary.Email.REQUIRED_FOR_MESSAGE) && email.fields.is_all_set(Geary.Email.REQUIRED_FOR_MESSAGE)) { - string? body = null; try { body = email.get_message().get_searchable_body(); } catch (Error e) { // Ignore. } - string? recipients = null; try { recipients = email.get_message().get_searchable_recipients(); } catch (Error e) { // Ignore. } - - Db.Statement stmt = cx.prepare( - "UPDATE MessageSearchTable SET body=?, attachment=?, receivers=? WHERE docid=?"); - stmt.bind_string(0, body); - stmt.bind_string(1, email.get_searchable_attachment_list()); - stmt.bind_string(2, recipients); - stmt.bind_rowid(3, message_id); - - stmt.exec(cancellable); } - + if (new_fields.is_any_set(Geary.Email.Field.SUBJECT)) { - Db.Statement stmt = cx.prepare( - "UPDATE MessageSearchTable SET subject=? WHERE docid=?"); - stmt.bind_string(0, (email.subject != null ? email.subject.to_searchable_string() : null)); - stmt.bind_rowid(1, message_id); - - stmt.exec(cancellable); + if (email.subject != null) + email.subject.to_searchable_string(); } - + if (new_fields.is_any_set(Geary.Email.Field.ORIGINATORS)) { - Db.Statement stmt = cx.prepare( - "UPDATE MessageSearchTable SET from_field=? WHERE docid=?"); - stmt.bind_string(0, (email.from != null ? email.from.to_searchable_string() : null)); - stmt.bind_rowid(1, message_id); - - stmt.exec(cancellable); + if (email.from != null) + from = email.from.to_searchable_string(); } - + if (new_fields.is_any_set(Geary.Email.Field.RECEIVERS)) { - Db.Statement stmt = cx.prepare( - "UPDATE MessageSearchTable SET cc=?, bcc=? WHERE docid=?"); - stmt.bind_string(0, (email.cc != null ? email.cc.to_searchable_string() : null)); - stmt.bind_string(1, (email.bcc != null ? email.bcc.to_searchable_string() : null)); - stmt.bind_rowid(2, message_id); - - stmt.exec(cancellable); + if (email.cc != null) + cc = email.cc.to_searchable_string(); + if (email.bcc != null) + bcc = email.bcc.to_searchable_string(); } + + Db.Statement del = cx.prepare( + "DELETE FROM MessageSearchTable WHERE docid=?" + ); + del.bind_rowid(0, message_id); + del.exec(cancellable); + + Db.Statement insert = cx.prepare(""" + INSERT INTO MessageSearchTable + (docid, body, attachment, subject, from_field, receivers, cc, bcc) + VALUES (?, ?, ?, ?, ?, ?, ?, ?) + """); + insert.bind_rowid(0, message_id); + insert.bind_string(1, body); + insert.bind_string(2, attachments); + insert.bind_string(3, subject); + insert.bind_string(4, from); + insert.bind_string(5, recipients); + insert.bind_string(6, cc); + insert.bind_string(7, bcc); + + insert.exec_insert(cancellable); } - + // This *replaces* the stored flags, it does not OR them ... this is simply a fast-path over // do_merge_email(), as updating FLAGS happens often and doesn't require a lot of extra work private void do_merge_email_flags(Db.Connection cx, LocationIdentifier location, Geary.Email email,