Bug 477793 - Make sure preventive maintenance cannot act on roots, r=sdwilsh a=blocking191
authorMarco Bonardo <mbonardo@mozilla.com>
Wed, 11 Feb 2009 13:56:11 +0100
changeset 23241 9613d04bb884aa1b1175b1cce0bc318cc0275d69
parent 23240 c0ae109fa3030c5d9bc1abc59a0f046a3952e245
child 23242 32c6710ef316217abac2885e3c0713f0d7a7dd67
push id670
push usermak77@bonardo.net
push dateWed, 11 Feb 2009 12:58:21 +0000
reviewerssdwilsh, blocking191
bugs477793
milestone1.9.1b3pre
Bug 477793 - Make sure preventive maintenance cannot act on roots, r=sdwilsh a=blocking191
toolkit/components/places/src/PlacesDBUtils.jsm
toolkit/components/places/tests/unit/test_preventive_maintenance.js
--- 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);