Bug 477793 - Make sure preventive maintenance cannot act on roots, r=sdwilsh a=blocking191
--- a/toolkit/components/places/src/PlacesDBUtils.jsm
+++ b/toolkit/components/places/src/PlacesDBUtils.jsm
@@ -241,117 +241,135 @@ nsPlacesDBUtils.prototype = {
fixInvalidRoots.params["places_root"] = this._bms.placesRoot;
cleanupStatements.push(fixInvalidRoots);
*/
// MOZ_BOOKMARKS
// D.1 remove items without a valid place
// if fk IS NULL we fix them in D.7
let deleteNoPlaceItems = this._dbConn.createStatement(
- "DELETE FROM moz_bookmarks WHERE id IN (" +
+ "DELETE FROM moz_bookmarks WHERE id NOT IN ( " +
+ "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
+ ") AND id IN (" +
"SELECT b.id FROM moz_bookmarks b " +
"WHERE fk NOT NULL AND b.type = :bookmark_type " +
"AND NOT EXISTS (SELECT url FROM moz_places_temp WHERE id = b.fk LIMIT 1) " +
"AND NOT EXISTS (SELECT url FROM moz_places WHERE id = b.fk LIMIT 1) " +
")");
deleteNoPlaceItems.params["bookmark_type"] = this._bms.TYPE_BOOKMARK;
cleanupStatements.push(deleteNoPlaceItems);
// D.2 remove items that are not uri bookmarks from tag containers
let deleteBogusTagChildren = this._dbConn.createStatement(
- "DELETE FROM moz_bookmarks WHERE id IN (" +
+ "DELETE FROM moz_bookmarks WHERE id NOT IN ( " +
+ "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
+ ") AND id IN (" +
"SELECT b.id FROM moz_bookmarks b " +
"WHERE b.parent IN " +
"(SELECT id FROM moz_bookmarks WHERE parent = :tags_folder) " +
"AND b.type <> :bookmark_type " +
")");
deleteBogusTagChildren.params["tags_folder"] = this._bms.tagsFolder;
deleteBogusTagChildren.params["bookmark_type"] = this._bms.TYPE_BOOKMARK;
cleanupStatements.push(deleteBogusTagChildren);
// D.3 remove empty tags
let deleteEmptyTags = this._dbConn.createStatement(
- "DELETE FROM moz_bookmarks WHERE id IN (" +
+ "DELETE FROM moz_bookmarks WHERE id NOT IN ( " +
+ "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
+ ") AND id IN (" +
"SELECT b.id FROM moz_bookmarks b " +
"WHERE b.id IN " +
"(SELECT id FROM moz_bookmarks WHERE parent = :tags_folder) " +
"AND NOT EXISTS " +
"(SELECT id from moz_bookmarks WHERE parent = b.id LIMIT 1) " +
")");
deleteEmptyTags.params["tags_folder"] = this._bms.tagsFolder;
cleanupStatements.push(deleteEmptyTags);
// D.4 move orphan items to unsorted folder
let fixOrphanItems = this._dbConn.createStatement(
- "UPDATE moz_bookmarks SET parent = :unsorted_folder WHERE id IN (" +
+ "UPDATE moz_bookmarks SET parent = :unsorted_folder WHERE id NOT IN ( " +
+ "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
+ ") AND id IN (" +
"SELECT b.id FROM moz_bookmarks b " +
- "WHERE b.parent <> 0 " + // exclude root
+ "WHERE b.parent <> 0 " + // exclude Places root
"AND NOT EXISTS " +
"(SELECT id FROM moz_bookmarks WHERE id = b.parent LIMIT 1) " +
")");
fixOrphanItems.params["unsorted_folder"] = this._bms.unfiledBookmarksFolder;
cleanupStatements.push(fixOrphanItems);
// D.5 fix wrong keywords
let fixInvalidKeywords = this._dbConn.createStatement(
- "UPDATE moz_bookmarks SET keyword_id = NULL WHERE id IN ( " +
+ "UPDATE moz_bookmarks SET keyword_id = NULL WHERE id NOT IN ( " +
+ "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
+ ") AND id IN ( " +
"SELECT id FROM moz_bookmarks b " +
"WHERE keyword_id NOT NULL " +
"AND NOT EXISTS " +
"(SELECT id FROM moz_keywords WHERE id = b.keyword_id LIMIT 1) " +
")");
cleanupStatements.push(fixInvalidKeywords);
// D.6 fix wrong item types
// Folders, separators and dynamic containers should not have an fk.
// If they have a valid fk convert them to bookmarks. Later in D.9 we
// will move eventual children to unsorted bookmarks.
let fixBookmarksAsFolders = this._dbConn.createStatement(
- "UPDATE moz_bookmarks SET type = :bookmark_type WHERE id IN ( " +
+ "UPDATE moz_bookmarks SET type = :bookmark_type WHERE id NOT IN ( " +
+ "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
+ ") AND id IN ( " +
"SELECT id FROM moz_bookmarks b " +
"WHERE type IN (:folder_type, :separator_type, :dynamic_type) " +
"AND fk NOTNULL " +
")");
fixBookmarksAsFolders.params["bookmark_type"] = this._bms.TYPE_BOOKMARK;
fixBookmarksAsFolders.params["folder_type"] = this._bms.TYPE_FOLDER;
fixBookmarksAsFolders.params["separator_type"] = this._bms.TYPE_SEPARATOR;
fixBookmarksAsFolders.params["dynamic_type"] = this._bms.TYPE_DYNAMIC_CONTAINER;
cleanupStatements.push(fixBookmarksAsFolders);
// D.7 fix wrong item types
// Bookmarks should have an fk, if they don't have any, convert them to
// folders.
let fixFoldersAsBookmarks = this._dbConn.createStatement(
- "UPDATE moz_bookmarks SET type = :folder_type WHERE id IN ( " +
+ "UPDATE moz_bookmarks SET type = :folder_type WHERE id NOT IN ( " +
+ "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
+ ") AND id IN ( " +
"SELECT id FROM moz_bookmarks b " +
"WHERE type = :bookmark_type " +
"AND fk IS NULL " +
")");
fixFoldersAsBookmarks.params["bookmark_type"] = this._bms.TYPE_BOOKMARK;
fixFoldersAsBookmarks.params["folder_type"] = this._bms.TYPE_FOLDER;
cleanupStatements.push(fixFoldersAsBookmarks);
// D.8 fix wrong item types
// Dynamic containers should have a folder_type, if they don't have any
// convert them to folders.
let fixFoldersAsDynamic = this._dbConn.createStatement(
- "UPDATE moz_bookmarks SET type = :folder_type WHERE id IN ( " +
+ "UPDATE moz_bookmarks SET type = :folder_type WHERE id NOT IN ( " +
+ "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
+ ") AND id IN ( " +
"SELECT id FROM moz_bookmarks b " +
"WHERE type = :dynamic_type " +
"AND folder_type IS NULL " +
")");
fixFoldersAsDynamic.params["dynamic_type"] = this._bms.TYPE_DYNAMIC_CONTAINER;
fixFoldersAsDynamic.params["folder_type"] = this._bms.TYPE_FOLDER;
cleanupStatements.push(fixFoldersAsDynamic);
// D.9 fix wrong parents
// Items cannot have dynamic containers, separators or other bookmarks
// as parent, if they have bad parent move them to unsorted bookmarks.
let fixInvalidParents = this._dbConn.createStatement(
- "UPDATE moz_bookmarks SET parent = :unsorted_folder WHERE id IN ( " +
+ "UPDATE moz_bookmarks SET parent = :unsorted_folder WHERE id NOT IN ( " +
+ "SELECT folder_id FROM moz_bookmarks_roots " + // skip roots
+ ") AND id IN ( " +
"SELECT id FROM moz_bookmarks b " +
"WHERE EXISTS " +
"(SELECT id FROM moz_bookmarks WHERE id = b.parent " +
"AND type IN (:bookmark_type, :separator_type, :dynamic_type) " +
"LIMIT 1) " +
")");
fixInvalidParents.params["unsorted_folder"] = this._bms.unfiledBookmarksFolder;
fixInvalidParents.params["bookmark_type"] = this._bms.TYPE_BOOKMARK;
@@ -389,19 +407,20 @@ nsPlacesDBUtils.prototype = {
}
*/
// D.11 remove old livemarks status items
// Livemark status items are now static but some livemark has still old
// status items bookmarks inside it. We should remove them.
// Note: This does not need to query the temp table.
let removeLivemarkStaticItems = this._dbConn.createStatement(
- "DELETE FROM moz_bookmarks WHERE fk IN ( " +
+ "DELETE FROM moz_bookmarks WHERE type = :bookmark_type AND fk IN ( " +
"SELECT id FROM moz_places WHERE url = :lmloading OR url = :lmfailed " +
")");
+ removeLivemarkStaticItems.params["bookmark_type"] = this._bms.TYPE_BOOKMARK;
removeLivemarkStaticItems.params["lmloading"] = "about:livemark-loading";
removeLivemarkStaticItems.params["lmfailed"] = "about:livemark-failed";
cleanupStatements.push(removeLivemarkStaticItems);
// MOZ_FAVICONS
// E.1 remove orphan icons
let deleteOrphanIcons = this._dbConn.createStatement(
"DELETE FROM moz_favicons WHERE id IN (" +
--- a/toolkit/components/places/tests/unit/test_preventive_maintenance.js
+++ b/toolkit/components/places/tests/unit/test_preventive_maintenance.js
@@ -1098,16 +1098,22 @@ let observer = {
if (tests.length) {
current_test = tests.shift();
dump("\nExecuting test: " + current_test.name + "\n" + "*** " + current_test.desc + "\n");
current_test.setup();
PlacesDBUtils.maintenanceOnIdle();
}
else {
os.removeObserver(this, FINISHED_MAINTANANCE_NOTIFICATION_TOPIC);
+ // Sanity check: all roots should be intact
+ do_check_eq(bs.getFolderIdForItem(bs.placesRoot), 0);
+ do_check_eq(bs.getFolderIdForItem(bs.bookmarksMenuFolder), bs.placesRoot);
+ do_check_eq(bs.getFolderIdForItem(bs.tagsFolder), bs.placesRoot);
+ do_check_eq(bs.getFolderIdForItem(bs.unfiledBookmarksFolder), bs.placesRoot);
+ do_check_eq(bs.getFolderIdForItem(bs.toolbarFolder), bs.placesRoot);
do_test_finished();
}
}
}
}
os.addObserver(observer, FINISHED_MAINTANANCE_NOTIFICATION_TOPIC, false);