Clears duplicate folders and prevents new ones from being created

An old bug was causing duplicate folders to be created in the
database.  Fortunately the duplicate folders will, due to other
logic, not become the parent of other folders or hold messages.
This patch removes the duplicate folders and prevents them from
being created again.

This work is necessary in preparation for #3704, which uses the
database a little differently in regards to folders.
This commit is contained in:
Jim Nelson 2012-06-21 19:17:05 -07:00
parent ed235a106b
commit 331cc1d983
2 changed files with 69 additions and 4 deletions

View file

@ -118,6 +118,7 @@ private abstract class Geary.GenericImapAccount : Geary.EngineAccount {
return yield remote.folder_exists_async(path, cancellable);
}
// TODO: This needs to be made into a single transaction
public override async Geary.Folder fetch_folder_async(Geary.FolderPath path,
Cancellable? cancellable = null) throws Error {

View file

@ -44,6 +44,9 @@ private class Geary.Sqlite.Account : Object {
db.post_upgrade.connect(on_post_upgrade);
db.upgrade();
// Need to clear duplicate folders (due to ticket #nnnn)
clear_duplicate_folders();
} catch (Error err) {
warning("Unable to open database: %s", err.message);
@ -103,10 +106,31 @@ private class Geary.Sqlite.Account : Object {
Transaction transaction = yield db.begin_transaction_async("Account.clone_folder_async",
cancellable);
int64 parent_id = yield fetch_parent_id_async(transaction, imap_folder.get_path(), cancellable);
int64 folder_id = Row.INVALID_ID;
int64 parent_id = Row.INVALID_ID;
for (int index = 0; index < imap_folder.get_path().get_path_length(); index++) {
Geary.FolderPath? current_path = imap_folder.get_path().get_folder_at(index);
assert(current_path != null);
int64 current_id = Row.INVALID_ID;
try {
current_id = yield fetch_id_async(transaction, current_path, cancellable);
} catch (Error err) {
if (!(err is EngineError.NOT_FOUND))
throw err;
}
if (current_id == Row.INVALID_ID) {
folder_id = yield folder_table.create_async(transaction, new FolderRow(folder_table,
current_path.basename, parent_id), cancellable);
} else {
folder_id = current_id;
}
parent_id = folder_id;
}
int64 folder_id = yield folder_table.create_async(transaction, new FolderRow(folder_table,
imap_folder.get_path().basename, parent_id), cancellable);
assert(folder_id != Row.INVALID_ID);
yield folder_properties_table.create_async(transaction,
new ImapFolderPropertiesRow.from_imap_properties(folder_properties_table, folder_id,
@ -268,8 +292,48 @@ private class Geary.Sqlite.Account : Object {
// TODO Add per-version data massaging.
}
private void on_post_upgrade(int version){
private void on_post_upgrade(int version) {
// TODO Add per-version data massaging.
}
private void clear_duplicate_folders() throws SQLHeavy.Error {
int count = 0;
// Find all folders with duplicate names
SQLHeavy.Query dupe_name_query = db.db.prepare(
"SELECT id, name FROM FolderTable WHERE name IN "
+ "(SELECT name FROM FolderTable GROUP BY name HAVING (COUNT(name) > 1))");
SQLHeavy.QueryResult result = dupe_name_query.execute();
while (!result.finished) {
int64 id = result.fetch_int64(0);
// see if any folders have this folder as a parent OR if there are messages associated
// with this folder
SQLHeavy.Query child_query = db.db.prepare(
"SELECT id FROM FolderTable WHERE parent_id=?");
child_query.bind_int64(0, id);
SQLHeavy.QueryResult child_result = child_query.execute();
SQLHeavy.Query message_query = db.db.prepare(
"SELECT id FROM MessageLocationTable WHERE folder_id=?");
message_query.bind_int64(0, id);
SQLHeavy.QueryResult message_result = message_query.execute();
if (child_result.finished && message_result.finished) {
// no children, delete it
SQLHeavy.Query child_delete = db.db.prepare(
"DELETE FROM FolderTable WHERE id=?");
child_delete.bind_int64(0, id);
child_delete.execute();
count++;
}
result.next();
}
if (count > 0)
debug("Deleted %d duplicate folders", count);
}
}