Bug 449640 - Modify the places backend to use the temporary tables &
authorMarco Bonardo <mak77@bonardo.net>, Shawn Wilsher <sdwilsh@shawnwilsher.com>
Fri, 17 Oct 2008 06:12:51 -0400
changeset 20569 ef5b27855c762859872a8d84bb24bd2d3272324f
parent 20568 4939cc030c3b7236aa5fe7c3a1856668e709910c
child 20570 49bf2417efdaaa0f990374e4029dab47ec14f416
push id2972
push usertmielczarek@mozilla.com
push dateFri, 17 Oct 2008 10:35:06 +0000
treeherdermozilla-central@f31b66fd4192 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs449640, 450705
milestone1.9.1b2pre
Bug 449640 - Modify the places backend to use the temporary tables & Bug 450705 - Optimize the query changes from the temp table rewrite This changeset merges patches from two bugs to actually use the temporary tables created for places. Bug 449640 patch by Shawn Wilsher <sdwilsh@shawnwilsher.com> r=dietrich, r=Mak77 Bug 450705 patch by Marco Bonardo <mak77@bonardo.net> r=sdwilsh, r=dietrich, r=Mardak
toolkit/components/places/src/nsAnnotationService.cpp
toolkit/components/places/src/nsFaviconService.cpp
toolkit/components/places/src/nsNavBookmarks.cpp
toolkit/components/places/src/nsNavHistory.cpp
toolkit/components/places/src/nsNavHistory.h
toolkit/components/places/src/nsNavHistoryAutoComplete.cpp
toolkit/components/places/src/nsNavHistoryExpire.cpp
toolkit/components/places/src/nsPlacesTriggers.h
toolkit/components/places/tests/mochitest/bug_411966/redirect.js
toolkit/components/places/tests/unit/test_history.js
--- a/toolkit/components/places/src/nsAnnotationService.cpp
+++ b/toolkit/components/places/src/nsAnnotationService.cpp
@@ -104,80 +104,94 @@ nsAnnotationService::Init()
     return NS_ERROR_FAILURE;
   mDBConn = history->GetStorageConnection();
 
   // annotation statements
 
   // mDBSetAnnotation
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "UPDATE moz_annos "
-      "SET mime_type = ?4, content = ?5, flags = ?6, expiration = ?7, type = ?8, lastModified = ?10 "
+      "SET mime_type = ?4, content = ?5, flags = ?6, expiration = ?7, "
+        "type = ?8, lastModified = ?10 "
       "WHERE id = ?1"),
     getter_AddRefs(mDBSetAnnotation));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBSetItemAnnotation
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "UPDATE moz_items_annos "
-      "SET mime_type = ?4, content = ?5, flags = ?6, expiration = ?7, type = ?8, lastModified = ?10 "
+      "SET mime_type = ?4, content = ?5, flags = ?6, expiration = ?7, "
+        "type = ?8, lastModified = ?10 "
       "WHERE id = ?1"),
     getter_AddRefs(mDBSetItemAnnotation));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetAnnotation
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT * "
       "FROM moz_annos "
       "WHERE place_id = ?1 AND anno_attribute_id = "
-      "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
+        "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
     getter_AddRefs(mDBGetAnnotation));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetItemAnnotation
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT * "
       "FROM moz_items_annos "
       "WHERE item_id = ?1 AND anno_attribute_id = "
-      "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
+        "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
     getter_AddRefs(mDBGetItemAnnotation));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetAnnotationNames
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT n.name "
-      "FROM moz_annos a LEFT JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
+      "FROM moz_annos a "
+      "JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
       "WHERE a.place_id = ?1"),
     getter_AddRefs(mDBGetAnnotationNames));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetItemAnnotationNames
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT n.name "
-      "FROM moz_items_annos a LEFT JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
+      "FROM moz_items_annos a "
+      "JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
       "WHERE a.item_id = ?1"),
     getter_AddRefs(mDBGetItemAnnotationNames));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetAnnotationFromURI
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // can only have one anno with a certain name for every place_id.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT a.id, a.place_id, ?2, a.mime_type, a.content, a.flags, "
         "a.expiration, a.type "
-      "FROM moz_places h JOIN moz_annos a ON h.id = a.place_id "
-      "WHERE h.url = ?1 AND a.anno_attribute_id = "
-      "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
+      "FROM ( "
+        "SELECT id FROM moz_places_temp "
+        "WHERE url = ?1 "
+        "UNION ALL "
+        "SELECT id FROM moz_places "
+        "WHERE url = ?1 "
+      ") AS h JOIN moz_annos a ON h.id = a.place_id "
+      "WHERE a.anno_attribute_id = "
+        "(SELECT id FROM moz_anno_attributes WHERE name = ?2) "
+      "LIMIT 1"),
     getter_AddRefs(mDBGetAnnotationFromURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetAnnotationFromItemId
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT a.id, a.item_id, ?2, a.mime_type, a.content, a.flags, "
         "a.expiration, a.type "
       "FROM moz_items_annos a "
       "WHERE a.item_id = ?1 AND a.anno_attribute_id = "
-      "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
+        "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
     getter_AddRefs(mDBGetAnnotationFromItemId));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetAnnotationNameID
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT id FROM moz_anno_attributes WHERE name = ?1"),
     getter_AddRefs(mDBGetAnnotationNameID));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -187,48 +201,50 @@ nsAnnotationService::Init()
       "INSERT INTO moz_anno_attributes (name) VALUES (?1)"),
     getter_AddRefs(mDBAddAnnotationName));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBAddAnnotation
   //   Note: kAnnoIndex_Name here is a name ID and not a string like the getters
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "INSERT INTO moz_annos "
-      "(place_id, anno_attribute_id, mime_type, content, flags, expiration, type, dateAdded) "
+        "(place_id, anno_attribute_id, mime_type, content, flags, expiration, "
+         "type, dateAdded) "
       "VALUES (?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"),
     getter_AddRefs(mDBAddAnnotation));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBAddItemAnnotation
   //   Note: kAnnoIndex_Name here is a name ID and not a string like the getters
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "INSERT INTO moz_items_annos "
-      "(item_id, anno_attribute_id, mime_type, content, flags, expiration, type, dateAdded) "
+        "(item_id, anno_attribute_id, mime_type, content, flags, expiration, "
+         "type, dateAdded) "
       "VALUES (?2, ?3, ?4, ?5, ?6, ?7, ?8, ?9)"),
     getter_AddRefs(mDBAddItemAnnotation));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBRemoveAnnotation
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "DELETE FROM moz_annos WHERE place_id = ?1 AND anno_attribute_id = "
-      "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
+        "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
     getter_AddRefs(mDBRemoveAnnotation));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBRemoveItemAnnotation
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "DELETE FROM moz_items_annos WHERE item_id = ?1 AND anno_attribute_id = "
-      "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
+        "(SELECT id FROM moz_anno_attributes WHERE name = ?2)"),
     getter_AddRefs(mDBRemoveItemAnnotation));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetItemsWithAnnotation
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT a.item_id FROM moz_anno_attributes n "
-    "INNER JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
+    "JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
     "WHERE n.name = ?1"),
     getter_AddRefs(mDBGetItemsWithAnnotation));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 
@@ -248,34 +264,36 @@ nsAnnotationService::InitTables(mozIStor
   PRBool exists;
   rv = aDBConn->TableExists(NS_LITERAL_CSTRING("moz_annos"), &exists);
   NS_ENSURE_SUCCESS(rv, rv);
   if (! exists) {
     rv = aDBConn->ExecuteSimpleSQL(CREATE_MOZ_ANNOS);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-        "CREATE UNIQUE INDEX moz_annos_placeattributeindex ON moz_annos (place_id, anno_attribute_id)"));
+        "CREATE UNIQUE INDEX moz_annos_placeattributeindex "
+        "ON moz_annos (place_id, anno_attribute_id)"));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = aDBConn->TableExists(NS_LITERAL_CSTRING("moz_anno_attributes"), &exists);
   NS_ENSURE_SUCCESS(rv, rv);
   if (! exists) {
     rv = aDBConn->ExecuteSimpleSQL(CREATE_MOZ_ANNO_ATTRIBUTES);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = aDBConn->TableExists(NS_LITERAL_CSTRING("moz_items_annos"), &exists);
   NS_ENSURE_SUCCESS(rv, rv);
   if (! exists) {
     rv = aDBConn->ExecuteSimpleSQL(CREATE_MOZ_ITEMS_ANNOS);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-        "CREATE UNIQUE INDEX moz_items_annos_itemattributeindex ON moz_items_annos (item_id, anno_attribute_id)"));
+        "CREATE UNIQUE INDEX moz_items_annos_itemattributeindex "
+          "ON moz_items_annos (item_id, anno_attribute_id)"));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 
 // nsAnnotationService::SetAnnotationStringInternal
@@ -1205,20 +1223,28 @@ nsAnnotationService::GetPagesWithAnnotat
 
 nsresult
 nsAnnotationService::GetPagesWithAnnotationCOMArray(
     const nsACString& aName, nsCOMArray<nsIURI>* aResults){
   // this probably isn't a common operation, so we don't have a precompiled
   // statement. Perhaps this should change.
   nsCOMPtr<mozIStorageStatement> statement;
   nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT h.url FROM moz_anno_attributes n "
-    "INNER JOIN moz_annos a ON n.id = a.anno_attribute_id "
-    "INNER JOIN moz_places h ON a.place_id = h.id "
-    "WHERE n.name = ?1"),
+      "SELECT h.url "
+      "FROM moz_places_temp h "
+      "JOIN moz_annos a ON h.id = a.place_id "
+      "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
+      "WHERE n.name = ?1 "
+      "UNION ALL "
+      "SELECT h.url "
+      "FROM moz_places h "
+      "JOIN moz_annos a ON h.id = a.place_id "
+      "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
+      "WHERE n.name = ?1 "
+        "AND h.id NOT IN (SELECT id FROM moz_places_temp)"),
     getter_AddRefs(statement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = statement->BindUTF8StringParameter(0, aName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool hasMore = PR_FALSE;
   while (NS_SUCCEEDED(rv = statement->ExecuteStep(&hasMore)) && hasMore) {
@@ -1623,20 +1649,22 @@ nsAnnotationService::CopyPageAnnotations
         sourceNames.RemoveElementAt(sourceIndex);
     }
   }
 
   // given (sourceID, destID, name) this will insert a new annotation on
   // source with the same values of the annotation on dest.
   nsCOMPtr<mozIStorageStatement> statement;
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "INSERT INTO moz_annos (place_id, anno_attribute_id, mime_type, content, flags, expiration) "
+      "INSERT INTO moz_annos "
+      "(place_id, anno_attribute_id, mime_type, content, flags, expiration) "
       "SELECT ?1, anno_attribute_id, mime_type, content, flags, expiration "
-      "FROM moz_annos WHERE place_id = ?2 AND anno_attribute_id = "
-      "(SELECT id FROM moz_anno_attributes WHERE name = ?3)"),
+      "FROM moz_annos "
+      "WHERE place_id = ?2 AND anno_attribute_id = "
+        "(SELECT id FROM moz_anno_attributes WHERE name = ?3)"),
     getter_AddRefs(statement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Get the IDs of the pages in quesion.  PERFORMANCE: This is the second time
   // we do this for each page, since GetPageAnnotationNamesTArray does it when
   // it gets the names. If this function requires optimization, we should only
   // do this once and get the names ourselves using the IDs.
   PRInt64 sourceID, destID;
--- a/toolkit/components/places/src/nsFaviconService.cpp
+++ b/toolkit/components/places/src/nsFaviconService.cpp
@@ -149,20 +149,29 @@ nsFaviconService::Init()
   mDBConn = historyService->GetStorageConnection();
   NS_ENSURE_TRUE(mDBConn, NS_ERROR_FAILURE);
 
   nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT id, length(data), expiration FROM moz_favicons WHERE url = ?1"),
     getter_AddRefs(mDBGetIconInfo));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  // We can avoid checking for duplicates in the unified table since an uri
+  // can only have one favicon associated. LIMIT 1 will ensure that we get
+  // only one result.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT f.id, f.url, length(f.data), f.expiration "
-      "FROM moz_places h JOIN moz_favicons f ON h.favicon_id = f.id "
-      "WHERE h.url = ?1"),
+      "FROM ( "
+        "SELECT * FROM moz_places_temp "
+        "WHERE url = ?1 "
+        "UNION ALL "
+        "SELECT * FROM moz_places "
+        "WHERE url = ?1 "
+      ") AS h JOIN moz_favicons f ON h.favicon_id = f.id "
+      "LIMIT 1"),
     getter_AddRefs(mDBGetURL));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT f.data, f.mime_type FROM moz_favicons f WHERE url = ?1"),
     getter_AddRefs(mDBGetData));
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -174,17 +183,17 @@ nsFaviconService::Init()
 
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "UPDATE moz_favicons SET data = ?2, mime_type = ?3, expiration = ?4 "
       "WHERE id = ?1"),
     getter_AddRefs(mDBUpdateIcon));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "UPDATE moz_places SET favicon_id = ?2 WHERE id = ?1"),
+      "UPDATE moz_places_view SET favicon_id = ?2 WHERE id = ?1"),
     getter_AddRefs(mDBSetPageFavicon));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // failed favicon cache
   if (! mFailedFavicons.Init(256))
     return NS_ERROR_OUT_OF_MEMORY;
 
   return NS_OK;
--- a/toolkit/components/places/src/nsNavBookmarks.cpp
+++ b/toolkit/components/places/src/nsNavBookmarks.cpp
@@ -108,18 +108,19 @@ nsNavBookmarks::Init()
   nsNavHistory *history = History();
   NS_ENSURE_TRUE(history, NS_ERROR_UNEXPECTED);
   mozIStorageConnection *dbConn = DBConn();
   mozStorageTransaction transaction(dbConn, PR_FALSE);
   nsresult rv;
 
   {
     nsCOMPtr<mozIStorageStatement> statement;
-    rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("SELECT id FROM moz_bookmarks WHERE type = ?1 AND parent IS NULL"),
-                                 getter_AddRefs(statement));
+    rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+        "SELECT id FROM moz_bookmarks WHERE type = ?1 AND parent IS NULL"),
+      getter_AddRefs(statement));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = statement->BindInt32Parameter(0, TYPE_FOLDER);
     NS_ENSURE_SUCCESS(rv, rv);
 
     PRBool results;
     rv = statement->ExecuteStep(&results);
     NS_ENSURE_SUCCESS(rv, rv);
     if (results) {
@@ -127,161 +128,244 @@ nsNavBookmarks::Init()
     }
   }
 
   nsCAutoString buffer;
 
   nsCOMPtr<nsIStringBundleService> bundleService =
     do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = bundleService->CreateBundle(
-      "chrome://places/locale/places.properties",
-      getter_AddRefs(mBundle));
+  rv = bundleService->CreateBundle("chrome://places/locale/places.properties",
+                                   getter_AddRefs(mBundle));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBFindURIBookmarks
   // NOTE: Do not modify the ORDER BY segment of the query, as certain
   // features depend on it. See bug 398914 for an example.
   rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT a.id "
-      "FROM moz_bookmarks a, moz_places h "
-      "WHERE h.url = ?1 AND a.fk = h.id and a.type = ?2 "
-      "ORDER BY MAX(COALESCE(a.lastModified, 0), a.dateAdded) DESC, a.id DESC"),
+      "SELECT b.id "
+      "FROM moz_bookmarks b "
+      "JOIN ( "
+        "SELECT id FROM moz_places_temp "
+        "WHERE url = ?1 "
+        "UNION ALL "
+        "SELECT id FROM moz_places "
+        "WHERE url = ?1 "
+        "AND +id NOT IN (SELECT id FROM moz_places_temp) "
+      ") AS h ON b.fk = h.id "
+      "WHERE b.type = ?2 "
+      "ORDER BY MAX(IFNULL(b.lastModified, 0), b.dateAdded) DESC, b.id DESC"),
     getter_AddRefs(mDBFindURIBookmarks));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Construct a result where the first columns exactly match those returned by
   // mDBGetURLPageInfo, and additionally contains columns for position,
   // item_child, and folder_child from moz_bookmarks.
   // Results are kGetInfoIndex_*
 
   // mDBGetChildren: select all children of a given folder, sorted by position
   // This is a LEFT OUTER JOIN with moz_places since folders does not have
   // a reference into that table.
   rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT h.id, h.url, COALESCE(b.title, h.title), "
-      "h.rev_host, h.visit_count, "
-      SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
-      ", f.url, null, b.id, "
-      "b.dateAdded, b.lastModified, "
-      "b.position, b.type, b.fk "
-      "FROM moz_bookmarks b "
-      "LEFT OUTER JOIN moz_places h ON b.fk = h.id "
-      "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
-      "WHERE b.parent = ?1 "
-      "ORDER BY b.position"),
+      "SELECT * FROM ( "
+        "SELECT h.id, h.url, COALESCE(b.title, h.title), "
+        "h.rev_host, h.visit_count, "
+          SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
+          ", f.url, null, b.id, b.dateAdded, b.lastModified, "
+          "b.position, b.type, b.fk "
+        "FROM moz_bookmarks b "
+        "JOIN moz_places_temp h ON b.fk = h.id "
+        "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+        "WHERE b.parent = ?1 "
+        "UNION ALL "
+        "SELECT h.id, h.url, COALESCE(b.title, h.title), "
+        "h.rev_host, h.visit_count, "
+          SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
+          ", f.url, null, b.id, b.dateAdded, b.lastModified, "
+          "b.position, b.type, b.fk "
+        "FROM moz_bookmarks b "
+        "LEFT JOIN moz_places h ON b.fk = h.id "
+        "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+        "WHERE b.parent = ?1 "
+        "AND (b.fk ISNULL OR b.fk NOT IN (select id FROM moz_places_temp)) "
+      ") "
+      "ORDER BY 12 ASC"), /* position */
     getter_AddRefs(mDBGetChildren));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBFolderCount: count all of the children of a given folder
-  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("SELECT COUNT(*) FROM moz_bookmarks WHERE parent = ?1"),
-                               getter_AddRefs(mDBFolderCount));
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT COUNT(*) FROM moz_bookmarks WHERE parent = ?1"),
+    getter_AddRefs(mDBFolderCount));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("SELECT position FROM moz_bookmarks WHERE id = ?1"),
-                               getter_AddRefs(mDBGetItemIndex));
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT position FROM moz_bookmarks WHERE id = ?1"),
+    getter_AddRefs(mDBGetItemIndex));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("SELECT id, fk, type FROM moz_bookmarks WHERE parent = ?1 AND position = ?2"),
-                               getter_AddRefs(mDBGetChildAt));
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT id, fk, type FROM moz_bookmarks WHERE parent = ?1 AND position = ?2"),
+    getter_AddRefs(mDBGetChildAt));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // get bookmark/folder/separator properties 
+  // get bookmark/folder/separator properties
   rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT b.id, (SELECT url from moz_places WHERE id = b.fk), b.title, b.position, b.fk, b.parent, b.type, b.folder_type, b.dateAdded, b.lastModified "
+      "SELECT b.id, "
+        "IFNULL( "
+          "(SELECT url FROM moz_places_temp "
+          "WHERE id = (SELECT fk FROM moz_bookmarks WHERE id = ?1)) "
+          ", "
+          "(SELECT url FROM moz_places "
+          "WHERE id = (SELECT fk FROM moz_bookmarks WHERE id = ?1)) "
+        "), b.title, b.position, b.fk, b.parent, b.type, b.folder_type, "
+        "b.dateAdded, b.lastModified "
       "FROM moz_bookmarks b "
       "WHERE b.id = ?1"),
     getter_AddRefs(mDBGetItemProperties));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT item_id FROM moz_items_annos "
       "WHERE content = ?1 "
       "LIMIT 1"),
     getter_AddRefs(mDBGetItemIdForGUID));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetRedirectDestinations
   // input = page ID, time threshold; output = unique ID input has redirected to
   rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT dest_v.place_id "
-      "FROM moz_historyvisits source_v "
-      "LEFT JOIN moz_historyvisits dest_v ON dest_v.from_visit = source_v.id "
+      "SELECT DISTINCT dest_v.place_id "
+      "FROM moz_historyvisits_temp source_v "
+      "JOIN moz_historyvisits_temp dest_v ON dest_v.from_visit = source_v.id "
+      "WHERE source_v.place_id = ?1 "
+        "AND source_v.visit_date >= ?2 "
+        "AND dest_v.visit_type IN (") +
+        nsPrintfCString("%d,%d",
+                        nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                        nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
+        NS_LITERAL_CSTRING(") "
+      "UNION "
+      "SELECT DISTINCT dest_v.place_id "
+      "FROM moz_historyvisits_temp source_v "
+      "JOIN moz_historyvisits dest_v ON dest_v.from_visit = source_v.id "
       "WHERE source_v.place_id = ?1 "
-      "AND source_v.visit_date >= ?2 "
-      "AND (dest_v.visit_type = 5 OR dest_v.visit_type = 6) "
-      "GROUP BY dest_v.place_id"),
+        "AND source_v.visit_date >= ?2 "
+        "AND dest_v.visit_type IN (") +
+        nsPrintfCString("%d,%d",
+                        nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                        nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
+        NS_LITERAL_CSTRING(") "
+      "UNION "
+      "SELECT DISTINCT dest_v.place_id "
+      "FROM moz_historyvisits source_v "
+      "JOIN moz_historyvisits_temp dest_v ON dest_v.from_visit = source_v.id "
+      "WHERE source_v.place_id = ?1 "
+        "AND source_v.visit_date >= ?2 "
+        "AND dest_v.visit_type IN (") +
+        nsPrintfCString("%d,%d",
+                        nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                        nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
+        NS_LITERAL_CSTRING(") "
+      "UNION "      
+      "SELECT DISTINCT dest_v.place_id "
+      "FROM moz_historyvisits source_v "
+      "JOIN moz_historyvisits dest_v ON dest_v.from_visit = source_v.id "
+      "WHERE source_v.place_id = ?1 "
+        "AND source_v.visit_date >= ?2 "
+        "AND dest_v.visit_type IN (") +
+        nsPrintfCString("%d,%d",
+                        nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                        nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
+        NS_LITERAL_CSTRING(") "),
     getter_AddRefs(mDBGetRedirectDestinations));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBInsertBookmark
-  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_bookmarks "
-                               "(fk, type, parent, position, title, dateAdded) "
-                               "VALUES (?1, ?2, ?3, ?4, ?5, ?6)"),
-                               getter_AddRefs(mDBInsertBookmark));
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+      "INSERT INTO moz_bookmarks "
+        "(fk, type, parent, position, title, dateAdded) "
+      "VALUES (?1, ?2, ?3, ?4, ?5, ?6)"),
+    getter_AddRefs(mDBInsertBookmark));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBIsBookmarkedInDatabase
   // Just select position since it's just an int32 and may be faster.
   // We don't actually care about the data, just whether there is any.
-  rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING(
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT position FROM moz_bookmarks WHERE fk = ?1 AND type = ?2"),
     getter_AddRefs(mDBIsBookmarkedInDatabase));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetLastBookmarkID
-  rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING(
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT id "
       "FROM moz_bookmarks "
       "ORDER BY ROWID DESC "
       "LIMIT 1"),
     getter_AddRefs(mDBGetLastBookmarkID));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBSetItemDateAdded
-  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("UPDATE moz_bookmarks SET dateAdded = ?1 WHERE id = ?2"),
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_bookmarks SET dateAdded = ?1 WHERE id = ?2"),
     getter_AddRefs(mDBSetItemDateAdded));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBSetItemLastModified
-  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("UPDATE moz_bookmarks SET lastModified = ?1 WHERE id = ?2"),
-                               getter_AddRefs(mDBSetItemLastModified));
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_bookmarks SET lastModified = ?1 WHERE id = ?2"),
+    getter_AddRefs(mDBSetItemLastModified));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBSetItemIndex
-  rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING("UPDATE moz_bookmarks SET position = ?2 WHERE id = ?1"),
-                               getter_AddRefs(mDBSetItemIndex));
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_bookmarks SET position = ?2 WHERE id = ?1"),
+    getter_AddRefs(mDBSetItemIndex));
   NS_ENSURE_SUCCESS(rv, rv);
 
   FillBookmarksHash();
 
   // must be last: This may cause bookmarks to be imported, which will exercise
   // most of the bookmark system
 
   // get keyword text for bookmark id
   rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT k.keyword FROM moz_bookmarks b "
       "JOIN moz_keywords k ON k.id = b.keyword_id "
       "WHERE b.id = ?1"),
     getter_AddRefs(mDBGetKeywordForBookmark));
   NS_ENSURE_SUCCESS(rv, rv);
   // get keyword text for URI (must be a bookmarked URI)
   rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT k.keyword " 
-      "FROM moz_places p "
-      "JOIN moz_bookmarks b ON b.fk = p.id "
-      "JOIN moz_keywords k ON k.id = b.keyword_id "
-      "WHERE p.url = ?1"),
+      "SELECT k.keyword "
+      "FROM ( "
+        "SELECT id FROM moz_places_temp "
+        "WHERE url = ?1 "
+        "UNION ALL "
+        "SELECT id FROM moz_places "
+        "WHERE +id NOT IN (SELECT id FROM moz_places_temp) "
+          "AND url = ?1 "
+      ") AS h "
+      "JOIN moz_bookmarks b ON b.fk = h.id "
+      "JOIN moz_keywords k ON k.id = b.keyword_id"),
     getter_AddRefs(mDBGetKeywordForURI));
   NS_ENSURE_SUCCESS(rv, rv);
   // get URI for keyword
   rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT p.url FROM moz_keywords k "
+      "SELECT url FROM moz_keywords k "
       "JOIN moz_bookmarks b ON b.keyword_id = k.id "
-      "JOIN moz_places p ON b.fk = p.id "
-      "WHERE k.keyword = ?1"),
+      "JOIN moz_places_temp h ON b.fk = h.id "
+      "WHERE k.keyword = ?1 "
+      "UNION ALL "
+      "SELECT url FROM moz_keywords k "
+      "JOIN moz_bookmarks b ON b.keyword_id = k.id "
+      "JOIN moz_places h ON b.fk = h.id "
+      "WHERE k.keyword = ?1 "
+        "AND h.id NOT IN (SELECT id FROM moz_places_temp)"),
     getter_AddRefs(mDBGetURIForKeyword));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // generate a new GUID base for this session
   nsCOMPtr<nsIUUIDGenerator> uuidgen = do_GetService("@mozilla.org/uuid-generator;1", &rv);
   NS_ENSURE_SUCCESS(rv, rv);
   nsID GUID;
   rv = uuidgen->GenerateUUIDInPlace(&GUID);
@@ -293,18 +377,19 @@ nsNavBookmarks::Init()
   rv = InitRoots();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Temporary migration code for bug 396300
   nsCOMPtr<mozIStorageStatement> moveUnfiledBookmarks;
-  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("UPDATE moz_bookmarks SET parent = ?1 WHERE type = ?2 AND parent=?3"),
-                               getter_AddRefs(moveUnfiledBookmarks));
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_bookmarks SET parent = ?1 WHERE type = ?2 AND parent=?3"),
+    getter_AddRefs(moveUnfiledBookmarks));
   rv = moveUnfiledBookmarks->BindInt64Parameter(0, mUnfiledRoot);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = moveUnfiledBookmarks->BindInt32Parameter(1, TYPE_BOOKMARK);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = moveUnfiledBookmarks->BindInt64Parameter(2, mRoot);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = moveUnfiledBookmarks->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
@@ -405,18 +490,19 @@ nsNavBookmarks::InitTables(mozIStorageCo
 //
 //    This should be called as the last part of the init process so that
 //    all of the statements are set up and the service is ready to use.
 
 nsresult
 nsNavBookmarks::InitRoots()
 {
   nsCOMPtr<mozIStorageStatement> getRootStatement;
-  nsresult rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING("SELECT folder_id FROM moz_bookmarks_roots WHERE root_name = ?1"),
-                                 getter_AddRefs(getRootStatement));
+  nsresult rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT folder_id FROM moz_bookmarks_roots WHERE root_name = ?1"),
+    getter_AddRefs(getRootStatement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool createdPlacesRoot = PR_FALSE;
   rv = CreateRoot(getRootStatement, NS_LITERAL_CSTRING("places"), &mRoot, 0, &createdPlacesRoot);
   NS_ENSURE_SUCCESS(rv, rv);
 
   getRootStatement->Reset();
   rv = CreateRoot(getRootStatement, NS_LITERAL_CSTRING("menu"), &mBookmarksRoot, mRoot, nsnull);
@@ -433,18 +519,19 @@ nsNavBookmarks::InitRoots()
     nsAnnotationService* annosvc = nsAnnotationService::GetAnnotationService();
     NS_ENSURE_TRUE(annosvc, NS_ERROR_OUT_OF_MEMORY);
 
     nsTArray<PRInt64> folders;
     annosvc->GetItemsWithAnnotationTArray(BOOKMARKS_TOOLBAR_FOLDER_ANNO,
                                           &folders);
     if (folders.Length() > 0) {
       nsCOMPtr<mozIStorageStatement> moveItems;
-      rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING("UPDATE moz_bookmarks SET parent = ?1 WHERE parent=?2"),
-                                     getter_AddRefs(moveItems));
+      rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING(
+          "UPDATE moz_bookmarks SET parent = ?1 WHERE parent=?2"),
+        getter_AddRefs(moveItems));
       rv = moveItems->BindInt64Parameter(0, mToolbarFolder);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = moveItems->BindInt64Parameter(1, folders[0]);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = moveItems->Execute();
       NS_ENSURE_SUCCESS(rv, rv);
       rv = RemoveFolder(folders[0]);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -555,18 +642,19 @@ nsNavBookmarks::CreateRoot(mozIStorageSt
     *aWasCreated = PR_TRUE;
 
   // create folder with no name or attributes
   nsCOMPtr<mozIStorageStatement> insertStatement;
   rv = CreateFolder(aParentID, EmptyCString(), nsINavBookmarksService::DEFAULT_INDEX, aID);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // save root ID
-  rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_bookmarks_roots (root_name, folder_id) VALUES (?1, ?2)"),
-                                 getter_AddRefs(insertStatement));
+  rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING(
+      "INSERT INTO moz_bookmarks_roots (root_name, folder_id) VALUES (?1, ?2)"),
+    getter_AddRefs(insertStatement));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = insertStatement->BindUTF8StringParameter(0, name);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = insertStatement->BindInt64Parameter(1, *aID);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = insertStatement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -611,22 +699,58 @@ nsNavBookmarks::FillBookmarksHash()
   //    bookmarked -> url (h1)         url (h2)
   //                    |                 ^
   //                    .                 |
   //                 visit (v1) -> destination visit (v2)
   // This should catch most redirects, which are only one level. More levels of
   // redirection will be handled separately.
   rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT v1.place_id, v2.place_id "
-      "FROM moz_bookmarks b "
-      "LEFT JOIN moz_historyvisits v1 on b.fk = v1.place_id "
-      "LEFT JOIN moz_historyvisits v2 on v2.from_visit = v1.id "
-      "WHERE b.fk IS NOT NULL AND b.type = ?1 "
-      "AND v2.visit_type = 5 OR v2.visit_type = 6 " // perm. or temp. RDRs
-      "GROUP BY v2.place_id"),
+        "FROM moz_bookmarks b "
+        "LEFT JOIN moz_historyvisits_temp v1 on b.fk = v1.place_id "
+        "LEFT JOIN moz_historyvisits v2 on v2.from_visit = v1.id "
+        "WHERE b.fk IS NOT NULL AND b.type = ?1 "
+        "AND v2.visit_type IN (") +
+        nsPrintfCString("%d,%d",
+                        nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                        nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
+        NS_LITERAL_CSTRING(") GROUP BY v2.place_id "
+      "UNION "
+      "SELECT v1.place_id, v2.place_id "
+        "FROM moz_bookmarks b "
+        "LEFT JOIN moz_historyvisits v1 on b.fk = v1.place_id "
+        "LEFT JOIN moz_historyvisits_temp v2 on v2.from_visit = v1.id "
+        "WHERE b.fk IS NOT NULL AND b.type = ?1 "
+        "AND v2.visit_type IN (") +
+        nsPrintfCString("%d,%d",
+                        nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                        nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
+        NS_LITERAL_CSTRING(") GROUP BY v2.place_id "
+      "UNION "
+      "SELECT v1.place_id, v2.place_id "
+        "FROM moz_bookmarks b "
+        "LEFT JOIN moz_historyvisits v1 on b.fk = v1.place_id "
+        "LEFT JOIN moz_historyvisits v2 on v2.from_visit = v1.id "
+        "WHERE b.fk IS NOT NULL AND b.type = ?1 "
+        "AND v2.visit_type IN (") +
+        nsPrintfCString("%d,%d",
+                        nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                        nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
+        NS_LITERAL_CSTRING(") GROUP BY v2.place_id "
+      "UNION "
+        "SELECT v1.place_id, v2.place_id "
+        "FROM moz_bookmarks b "
+        "LEFT JOIN moz_historyvisits_temp v1 on b.fk = v1.place_id "
+        "LEFT JOIN moz_historyvisits_temp v2 on v2.from_visit = v1.id "
+        "WHERE b.fk IS NOT NULL AND b.type = ?1 "
+        "AND v2.visit_type IN (") +
+        nsPrintfCString("%d,%d",
+                        nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                        nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
+        NS_LITERAL_CSTRING(") GROUP BY v2.place_id "),
     getter_AddRefs(statement));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindInt64Parameter(0, TYPE_BOOKMARK);
   NS_ENSURE_SUCCESS(rv, rv);
   while (NS_SUCCEEDED(statement->ExecuteStep(&hasMore)) && hasMore) {
     PRInt64 fromId, toId;
     statement->GetInt64(0, &fromId);
     statement->GetInt64(1, &toId);
@@ -1171,23 +1295,29 @@ nsNavBookmarks::CreateContainerWithID(PR
   } else {
     index = *aIndex;
     rv = AdjustIndices(aParent, index, PR_INT32_MAX, 1);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<mozIStorageStatement> statement;
   if (aItemId == -1) {
-    rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_bookmarks (title, type, parent, position, folder_type, dateAdded) VALUES (?1, ?2, ?3, ?4, ?5, ?6)"),
-                                 getter_AddRefs(statement));
+    rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+        "INSERT INTO moz_bookmarks "
+          "(title, type, parent, position, folder_type, dateAdded) "
+        "VALUES (?1, ?2, ?3, ?4, ?5, ?6)"),
+      getter_AddRefs(statement));
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
-    rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_bookmarks (id, title, type, parent, position, folder_type, dateAdded) VALUES (?7, ?1, ?2, ?3, ?4, ?5, ?6)"),
-                                 getter_AddRefs(statement));
+    rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+        "INSERT INTO moz_bookmarks "
+          "(id, title, type, parent, position, folder_type, dateAdded) "
+        "VALUES (?7, ?1, ?2, ?3, ?4, ?5, ?6)"),
+      getter_AddRefs(statement));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = statement->BindInt64Parameter(6, aItemId);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = statement->BindUTF8StringParameter(0, aName);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1255,19 +1385,20 @@ nsNavBookmarks::InsertSeparator(PRInt64 
     index = FolderCount(aParent);
   } else {
     index = aIndex;
     rv = AdjustIndices(aParent, index, PR_INT32_MAX, 1);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<mozIStorageStatement> statement;
-  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("INSERT INTO moz_bookmarks "
-                                          "(type, parent, position, dateAdded) VALUES (?1, ?2, ?3, ?4)"),
-                               getter_AddRefs(statement));
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+      "INSERT INTO moz_bookmarks "
+        "(type, parent, position, dateAdded) VALUES (?1, ?2, ?3, ?4)"),
+    getter_AddRefs(statement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = statement->BindInt64Parameter(0, TYPE_SEPARATOR);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindInt64Parameter(1, aParent);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindInt32Parameter(2, index);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -2236,18 +2367,19 @@ nsNavBookmarks::ChangeBookmarkURI(PRInt6
 
   PRInt64 placeId;
   nsresult rv = History()->GetUrlIdFor(aNewURI, &placeId, PR_TRUE);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!placeId)
     return NS_ERROR_INVALID_ARG;
 
   nsCOMPtr<mozIStorageStatement> statement;
-  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING("UPDATE moz_bookmarks SET fk = ?1 WHERE id = ?2"),
-                               getter_AddRefs(statement));
+  rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_bookmarks SET fk = ?1 WHERE id = ?2"),
+    getter_AddRefs(statement));
   statement->BindInt64Parameter(0, placeId);
   statement->BindInt64Parameter(1, aBookmarkId);
 
   rv = statement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = SetItemDateInternal(mDBSetItemLastModified, aBookmarkId, PR_Now());
   NS_ENSURE_SUCCESS(rv, rv);
@@ -2420,17 +2552,17 @@ nsNavBookmarks::SetKeywordForBookmark(PR
   nsresult rv;
   PRBool results;
   PRInt64 keywordId = 0;
 
   if (!kwd.IsEmpty()) {
     //  Attempt to find pre-existing keyword record
     nsCOMPtr<mozIStorageStatement> getKeywordStmnt;
     rv = DBConn()->CreateStatement(NS_LITERAL_CSTRING(
-         "SELECT id from moz_keywords WHERE keyword = ?1"),
+        "SELECT id from moz_keywords WHERE keyword = ?1"),
       getter_AddRefs(getKeywordStmnt));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = getKeywordStmnt->BindStringParameter(0, kwd);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = getKeywordStmnt->ExecuteStep(&results);
     NS_ENSURE_SUCCESS(rv, rv);
 
--- a/toolkit/components/places/src/nsNavHistory.cpp
+++ b/toolkit/components/places/src/nsNavHistory.cpp
@@ -428,16 +428,18 @@ nsNavHistory::Init()
 #endif
 
   // extract the last session ID so we know where to pick up. There is no index
   // over sessions so the naive statement "SELECT MAX(session) FROM
   // moz_historyvisits" won't have good performance. Instead we select the
   // session of the last visited page because we do have indices over dates.
   // We still do MAX(session) in case there are duplicate sessions for the same
   // date, but there will generally be very few (1) of these.
+  // This is long before we use our temporary tables, so we do not have to join
+  // on moz_historyvisits_temp to get the right result here.
   {
     nsCOMPtr<mozIStorageStatement> selectSession;
     rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
         "SELECT MAX(session) FROM moz_historyvisits "
         "WHERE visit_date = "
         "(SELECT MAX(visit_date) from moz_historyvisits)"),
       getter_AddRefs(selectSession));
     NS_ENSURE_SUCCESS(rv, rv);
@@ -639,17 +641,17 @@ nsNavHistory::InitDBFile(PRBool aForceIn
 
   return NS_OK;
 }
 
 // nsNavHistory::InitDB
 //
 
 
-#define PLACES_SCHEMA_VERSION 7
+#define PLACES_SCHEMA_VERSION 8
 
 nsresult
 nsNavHistory::InitDB(PRInt16 *aMadeChanges)
 {
   nsresult rv;
   PRBool tableExists;
   *aMadeChanges = DB_MIGRATION_NONE;
 
@@ -731,17 +733,23 @@ nsNavHistory::InitDB(PRInt16 *aMadeChang
       }
 
       // Migrate historyvisits and bookmarks up to V7
       if (DBSchemaVersion < 7) {
         rv = MigrateV7Up(mDBConn);
         NS_ENSURE_SUCCESS(rv, rv);
       }
 
-      // XXX Upgrades >V7 must add migration code here.
+      // Migrate historyvisits up to V8
+      if (DBSchemaVersion < 8) {
+        rv = MigrateV8Up(mDBConn);
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+
+      // XXX Upgrades >V8 must add migration code here.
 
     } else {
       // Downgrading
 
       // XXX Need to prompt user or otherwise notify of 
       // potential dataloss when downgrading.
 
       // XXX Downgrades from >V6 must add migration code here.
@@ -849,22 +857,16 @@ nsNavHistory::InitDB(PRInt16 *aMadeChang
     // finding bookmark redirects using the referring page. 
     rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
         "CREATE INDEX moz_historyvisits_fromindex ON moz_historyvisits (from_visit)"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
         "CREATE INDEX moz_historyvisits_dateindex ON moz_historyvisits (visit_date)"));
     NS_ENSURE_SUCCESS(rv, rv);
-
-    // Create our triggers for this table
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_VISIT_COUNT_INSERT_TRIGGER);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_VISIT_COUNT_DELETE_TRIGGER);
-    NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // moz_inputhistory
   rv = mDBConn->TableExists(NS_LITERAL_CSTRING("moz_inputhistory"), &tableExists);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!tableExists) {
     rv = mDBConn->ExecuteSimpleSQL(CREATE_MOZ_INPUTHISTORY);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1065,178 +1067,306 @@ nsNavHistory::InitFunctions()
 //    Called after InitDB, this creates our stored statements
 
 nsresult
 nsNavHistory::InitStatements()
 {
   nsresult rv;
 
   // mDBGetURLPageInfo
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // have unique urls.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count "
-      "FROM moz_places h "
-      "WHERE h.url = ?1"),
+    "SELECT id, url, title, rev_host, visit_count "
+    "FROM moz_places_temp "
+    "WHERE url = ?1 "
+    "UNION ALL "
+    "SELECT id, url, title, rev_host, visit_count "
+    "FROM moz_places "
+    "WHERE url = ?1 "
+    "LIMIT 1"),
     getter_AddRefs(mDBGetURLPageInfo));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetIdPageInfo
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // have unique place ids.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count "
-      "FROM moz_places h WHERE h.id = ?1"),
+      "SELECT id, url, title, rev_host, visit_count "
+      "FROM moz_places_temp "
+      "WHERE id = ?1 "
+      "UNION ALL "
+      "SELECT id, url, title, rev_host, visit_count "
+      "FROM moz_places "
+      "WHERE id = ?1 "
+      "LIMIT 1"),
     getter_AddRefs(mDBGetIdPageInfo));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBRecentVisitOfURL
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // expect visits in temp table being the most recent.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT v.id, v.session "
-      "FROM moz_places h JOIN moz_historyvisits v ON h.id = v.place_id "
-      "WHERE h.url = ?1 "
-      "ORDER BY v.visit_date DESC "
+      "SELECT * FROM ( "
+        "SELECT v.id, v.session "
+        "FROM moz_historyvisits_temp v "
+        "WHERE v.place_id = IFNULL((SELECT id FROM moz_places_temp WHERE url = ?1), "
+                                  "(SELECT id FROM moz_places WHERE url = ?1)) "
+        "ORDER BY v.visit_date DESC LIMIT 1 "
+      ") "
+      "UNION ALL "
+      "SELECT * FROM ( "
+        "SELECT v.id, v.session "
+        "FROM moz_historyvisits v "
+        "WHERE v.place_id = IFNULL((SELECT id FROM moz_places_temp WHERE url = ?1), "
+                                  "(SELECT id FROM moz_places WHERE url = ?1)) "
+        "ORDER BY v.visit_date DESC LIMIT 1 "
+      ") "
       "LIMIT 1"),
     getter_AddRefs(mDBRecentVisitOfURL));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBRecentVisitOfPlace
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // expect visits in temp table being the most recent.  
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT id "
-      "FROM moz_historyvisits "
+      "SELECT id FROM moz_historyvisits_temp "
       "WHERE place_id = ?1 "
-      "AND visit_date = ?2 "
-      "AND session = ?3 "
+        "AND visit_date = ?2 "
+        "AND session = ?3 "
+      "UNION ALL "
+      "SELECT id FROM moz_historyvisits "
+      "WHERE place_id = ?1 "
+        "AND visit_date = ?2 "
+        "AND session = ?3 "
       "LIMIT 1"),
     getter_AddRefs(mDBRecentVisitOfPlace));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBInsertVisit
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "INSERT INTO moz_historyvisits "
-      "(from_visit, place_id, visit_date, visit_type, session) "
+      "INSERT INTO moz_historyvisits_view "
+        "(from_visit, place_id, visit_date, visit_type, session) "
       "VALUES (?1, ?2, ?3, ?4, ?5)"),
     getter_AddRefs(mDBInsertVisit));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetPageVisitStats (see InternalAdd)
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // have unique place ids.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT id, visit_count, typed, hidden "
+      "FROM moz_places_temp "
+      "WHERE url = ?1 "
+      "UNION ALL "
+      "SELECT id, visit_count, typed, hidden "
       "FROM moz_places "
-      "WHERE url = ?1"),
+      "WHERE url = ?1 "
+      "LIMIT 1"),
     getter_AddRefs(mDBGetPageVisitStats));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBIsPageVisited
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // only need to know if a visit exists.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT h.id FROM moz_places h WHERE h.url = ?1 " 
-      "AND EXISTS "
-      "(SELECT id FROM moz_historyvisits WHERE place_id = h.id LIMIT 1)"),
+      "SELECT h.id "
+      "FROM moz_places_temp h "
+      "WHERE url = ?1 " 
+        "AND ( "
+          "EXISTS(SELECT id FROM moz_historyvisits_temp WHERE place_id = h.id LIMIT 1) "
+          "OR EXISTS(SELECT id FROM moz_historyvisits WHERE place_id = h.id LIMIT 1) "
+        ") "
+      "UNION ALL "
+      "SELECT h.id "
+      "FROM moz_places h "
+      "WHERE url = ?1 "
+      "AND ( "
+        "EXISTS(SELECT id FROM moz_historyvisits_temp WHERE place_id = h.id LIMIT 1) "
+        "OR EXISTS(SELECT id FROM moz_historyvisits WHERE place_id = h.id LIMIT 1) "
+      ") "
+      "LIMIT 1"), 
     getter_AddRefs(mDBIsPageVisited));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBUpdatePageVisitStats (see InternalAdd)
   // we don't need to update visit_count since it's maintained
   // in sync by triggers, and we must NEVER touch it
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "UPDATE moz_places "
+      "UPDATE moz_places_view "
       "SET hidden = ?2, typed = ?3 "
       "WHERE id = ?1"),
     getter_AddRefs(mDBUpdatePageVisitStats));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBAddNewPage (see InternalAddNewPage)
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "INSERT OR REPLACE INTO moz_places "
-      "(url, title, rev_host, hidden, typed, frecency) "
+      "INSERT OR REPLACE INTO moz_places_view "
+        "(url, title, rev_host, hidden, typed, frecency) "
       "VALUES (?1, ?2, ?3, ?4, ?5, ?6)"),
     getter_AddRefs(mDBAddNewPage));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBVisitToURLResult, should match kGetInfoIndex_* (see GetQueryResults)
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // have unique visit ids.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
-        SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
-        ", f.url, null, null "
-      "FROM moz_places h "
-      "JOIN moz_historyvisits v ON h.id = v.place_id "
-      "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
-      "WHERE v.id = ?1"),
+          SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
+          ", f.url, null, null "
+        "FROM moz_places_temp h "
+        "LEFT JOIN moz_historyvisits_temp v_t ON h.id = v_t.place_id "
+        "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
+        "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+        "WHERE v.id = ?1 OR v_t.id = ?1 "
+      "UNION ALL "
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+          SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
+          ", f.url, null, null "
+        "FROM moz_places h "
+        "LEFT JOIN moz_historyvisits_temp v_t ON h.id = v_t.place_id "
+        "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
+        "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+        "WHERE v.id = ?1 OR v_t.id = ?1 "
+      "LIMIT 1"),
     getter_AddRefs(mDBVisitToURLResult));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBVisitToVisitResult, should match kGetInfoIndex_* (see GetQueryResults)
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // have unique visit ids.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
-             "v.visit_date, f.url, v.session, null "
-      "FROM moz_places h "
-      "JOIN moz_historyvisits v ON h.id = v.place_id "
-      "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
-      "WHERE v.id = ?1"),
+          "v.visit_date, f.url, v.session, null "
+        "FROM moz_places_temp h "
+        "LEFT JOIN moz_historyvisits_temp v_t ON h.id = v_t.place_id "
+        "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
+        "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+        "WHERE v.id = ?1 OR v_t.id = ?1 "
+      "UNION ALL "
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+          "v.visit_date, f.url, v.session, null "
+        "FROM moz_places h "
+        "LEFT JOIN moz_historyvisits_temp v_t ON h.id = v_t.place_id "
+        "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
+        "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+        "WHERE v.id = ?1 OR v_t.id = ?1 "
+      "LIMIT 1"),
     getter_AddRefs(mDBVisitToVisitResult));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBUrlToURLResult, should match kGetInfoIndex_*
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // have unique urls.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
         SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
         ", f.url, null, null "
-      "FROM moz_places h "
+      "FROM moz_places_temp h "
       "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
-      "WHERE h.url = ?1"),
+      "WHERE h.url = ?1 "
+      "UNION ALL "
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+        SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
+        ", f.url, null, null "
+      "FROM moz_places_temp h "
+      "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
+      "WHERE h.url = ?1 "
+      "LIMIT 1"),
     getter_AddRefs(mDBUrlToUrlResult));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBBookmarkToUrlResult, should match kGetInfoIndex_*
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // have unique place ids.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT b.fk, h.url, COALESCE(b.title, h.title), "
         "h.rev_host, h.visit_count, "
         SQL_STR_FRAGMENT_MAX_VISIT_DATE( "b.fk" )
         ", f.url, null, b.id, b.dateAdded, b.lastModified "
       "FROM moz_bookmarks b "
+      "JOIN moz_places_temp h ON b.fk = h.id "
+      "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
+      "WHERE b.id = ?1 "
+      "UNION ALL "
+      "SELECT b.fk, h.url, COALESCE(b.title, h.title), "
+        "h.rev_host, h.visit_count, "
+        SQL_STR_FRAGMENT_MAX_VISIT_DATE( "b.fk" )
+        ", f.url, null, b.id, b.dateAdded, b.lastModified "
+      "FROM moz_bookmarks b "
       "JOIN moz_places h ON b.fk = h.id "
       "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
-      "WHERE b.id = ?1"),
+      "WHERE b.id = ?1 "
+      "LIMIT 1"),
     getter_AddRefs(mDBBookmarkToUrlResult));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetTags
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
       "SELECT GROUP_CONCAT(t.title, ' ') "
-      "FROM moz_places h "
-      "JOIN moz_bookmarks b ON b.type = ") +
-        nsPrintfCString("%d", nsINavBookmarksService::TYPE_BOOKMARK) +
-        NS_LITERAL_CSTRING(" AND b.fk = h.id "
-      "JOIN moz_bookmarks t ON t.parent = ?1 AND t.id = b.parent "
-      "WHERE h.url = ?2"),
+      "FROM moz_bookmarks b "
+      "JOIN moz_bookmarks t ON t.id = b.parent "
+      "WHERE b.fk = IFNULL((SELECT id FROM moz_places_temp WHERE url = ?2), "
+                          "(SELECT id FROM moz_places WHERE url = ?2)) "
+        "AND b.type = ") +
+          nsPrintfCString("%d", nsINavBookmarksService::TYPE_BOOKMARK) +
+        NS_LITERAL_CSTRING(" AND t.parent = ?1 "),
     getter_AddRefs(mDBGetTags));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mFoldersWithAnnotationQuery
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT annos.item_id, annos.content FROM moz_anno_attributes attrs " 
-    "JOIN moz_items_annos annos ON attrs.id = annos.anno_attribute_id "
-    "WHERE attrs.name = ?1"), 
+    "SELECT a.item_id, a.content "
+    "FROM moz_anno_attributes n "
+    "JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
+    "WHERE n.name = ?1"), 
     getter_AddRefs(mFoldersWithAnnotationQuery));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBVisitsForFrecency
   // NOTE: we are not limiting to visits with "visit_type NOT IN (0,4,7)"
   // because if we do that, mDBVisitsForFrecency would return no visits
   // for places with only embed (or undefined) visits.  That would
   // cause use to estimate a frecency based on what information we do have,
   // see CalculateFrecencyInternal(). That would result in a non-zero frecency
   // for a place with only embedded visits, instead of a frecency of 0. If we
   // have a temporary or permanent redirect, calculate the frecency as if it
   // was the original page visited.
+
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT IFNULL(r.visit_date, v.visit_date) date, IFNULL(r.visit_type, v.visit_type) "
-    "FROM moz_historyvisits v "
-    "LEFT OUTER JOIN moz_historyvisits r "
-      "ON r.id = v.from_visit AND v.visit_type IN ") +
-      nsPrintfCString("(%d,%d) ", TRANSITION_REDIRECT_PERMANENT,
-      TRANSITION_REDIRECT_TEMPORARY) + NS_LITERAL_CSTRING(
-    "WHERE v.place_id = ?1 ORDER BY date DESC LIMIT ") +
-     nsPrintfCString("%d", mNumVisitsForFrecency),
+      "SELECT COALESCE(r_t.visit_date, r.visit_date, v.visit_date) date, "
+        "COALESCE(r_t.visit_type, r.visit_type, v.visit_type) "
+      "FROM ( "
+        "SELECT visit_date, visit_type, from_visit FROM moz_historyvisits_temp "
+        "WHERE place_id = ?1 "
+        "UNION ALL "
+        "SELECT visit_date, visit_type, from_visit FROM moz_historyvisits "
+        "WHERE id NOT IN (SELECT id FROM moz_historyvisits_temp) "
+        "AND place_id = ?1 "
+      ") AS v "
+      "LEFT JOIN moz_historyvisits r ON r.id = v.from_visit "
+        "AND v.visit_type IN ") +
+          nsPrintfCString("(%d,%d) ", TRANSITION_REDIRECT_PERMANENT,
+            TRANSITION_REDIRECT_TEMPORARY) + NS_LITERAL_CSTRING(
+      "LEFT JOIN moz_historyvisits_temp r_t ON r_t.id = v.from_visit "
+        "AND v.visit_type IN ") +
+          nsPrintfCString("(%d,%d) ", TRANSITION_REDIRECT_PERMANENT,
+            TRANSITION_REDIRECT_TEMPORARY) + NS_LITERAL_CSTRING(
+      "ORDER BY date DESC LIMIT ") +
+        nsPrintfCString("%d", mNumVisitsForFrecency),
     getter_AddRefs(mDBVisitsForFrecency));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // find places with invalid frecencies (frecency < 0)
   // invalid frecencies can happen in these scenarios:
   // 1) we've done "clear private data"
   // 2) we've expired or deleted visits
   // 3) we've migrated from an older version, before global frecency
@@ -1248,62 +1378,91 @@ nsNavHistory::InitStatements()
   // place: queries.)
   //
   // Note, we are not limiting ourselves to places with visits
   // because we may not have any if the place is a bookmark and
   // we expired or deleted all the visits. 
   // We get two sets of places that are 1) most visited and 2) random so that
   // we don't get stuck recalculating frecencies that end up being -1 every
   // time
+  // Since we don't need real random results and ORDER BY RANDOM() is slow
+  // we will jump at a random rowid in the table and we will get random results
+  // only from moz_places since temp will be synched there sometimes.  
   // Notice that frecency is invalidated as frecency = -visit_count
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT * FROM "
-      "(SELECT id, visit_count, hidden, typed, frecency, url "
-      "FROM moz_places WHERE frecency < 0 "
-      "ORDER BY frecency ASC LIMIT ROUND(?1 / 2)) "
-    "UNION "
-    "SELECT * FROM "
-      "(SELECT id, visit_count, hidden, typed, frecency, url "
-      "FROM moz_places WHERE frecency < 0 "
-      "ORDER BY RANDOM() LIMIT ROUND(?1 / 2))"),
+      "SELECT * FROM ( "
+        "SELECT id, visit_count, hidden, typed, frecency, url "
+        "FROM ( "
+          "SELECT * FROM moz_places_temp "
+          "WHERE frecency < 0 "
+          "UNION ALL "
+          "SELECT * FROM ( "
+            "SELECT * FROM moz_places "
+            "WHERE +id NOT IN (SELECT id FROM moz_places_temp) "
+            "AND frecency < 0 "
+            "ORDER BY frecency ASC LIMIT ROUND(?1 / 2) "
+          ") "
+        ") ORDER BY frecency ASC LIMIT ROUND(?1 / 2)) "
+      "UNION "
+      "SELECT * FROM ( "
+        "SELECT id, visit_count, hidden, typed, frecency, url "
+        "FROM moz_places "
+        "WHERE frecency < 0 "
+        "AND ROWID >= ABS(RANDOM() % (SELECT MAX(ROWID) FROM moz_places)) "
+        "LIMIT ROUND(?1 / 2))"),
     getter_AddRefs(mDBInvalidFrecencies));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // This query finds random old places to update frecency because frequently
-  // visited places will have their frecencies updated when visited
+  // visited places will have their frecencies updated when visited.
+  // We can limit the selection to moz_places since results in temp tables
+  // have been most likely visited recently.
+  // Since we don't need real random results and ORDER BY RANDOM() is slow
+  // we will jump at a random rowid in the table.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT id, visit_count, hidden, typed, frecency, url "
      "FROM moz_places "
-     "ORDER BY RANDOM() LIMIT ?1"),
+     "WHERE ROWID >= ABS(RANDOM() % (SELECT MAX(ROWID) FROM moz_places)) "
+     "LIMIT ?1"),
     getter_AddRefs(mDBOldFrecencies));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBUpdateFrecencyAndHidden
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "UPDATE moz_places SET frecency = ?2, hidden = ?3 WHERE id = ?1"),
+      "UPDATE moz_places_view SET frecency = ?2, hidden = ?3 WHERE id = ?1"),
     getter_AddRefs(mDBUpdateFrecencyAndHidden));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // mDBGetPlaceVisitStats
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // have unique place ids.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT typed, hidden, frecency FROM moz_places WHERE id = ?1"),
+      "SELECT typed, hidden, frecency "
+      "FROM moz_places_temp WHERE id = ?1 "
+      "UNION ALL "
+      "SELECT typed, hidden, frecency "
+      "FROM moz_places WHERE id = ?1 "
+      "LIMIT 1"),
     getter_AddRefs(mDBGetPlaceVisitStats));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT b.parent FROM moz_places h JOIN moz_bookmarks b "
-      " on b.fk = h.id WHERE b.type = 1 and h.id = ?1"),
+      "SELECT b.parent FROM moz_bookmarks b "
+      "WHERE b.type = 1 AND b.fk = ?1"),
     getter_AddRefs(mDBGetBookmarkParentsForPlace));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // when calculating frecency, we want the visit count to be 
   // all the visits.
-  rv = mDBConn->CreateStatement(
-    NS_LITERAL_CSTRING("SELECT COUNT(*) FROM moz_historyvisits " 
-      "WHERE place_id = ?1"),
+  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT "
+        "(SELECT COUNT(*) FROM moz_historyvisits WHERE place_id = ?1) + "
+        "(SELECT COUNT(*) FROM moz_historyvisits_temp WHERE place_id = ?1 "
+            "AND id NOT IN (SELECT id FROM moz_historyvisits))"),
     getter_AddRefs(mDBFullVisitCount));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 // nsNavHistory::ForceMigrateBookmarksDB
 //
@@ -1312,23 +1471,27 @@ nsNavHistory::InitStatements()
 //
 //    NOTE: This may cause data-loss if downgrading!
 //    Only use this for migration if you're sure that bookmarks.html
 //    and the target version support all bookmarks fields.
 nsresult
 nsNavHistory::ForceMigrateBookmarksDB(mozIStorageConnection* aDBConn) 
 {
   // drop bookmarks tables
-  nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE IF EXISTS moz_bookmarks"));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE IF EXISTS moz_bookmarks_folders"));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE IF EXISTS moz_bookmarks_roots"));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE IF EXISTS moz_keywords"));
+  nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP TABLE IF EXISTS moz_bookmarks"));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP TABLE IF EXISTS moz_bookmarks_folders"));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP TABLE IF EXISTS moz_bookmarks_roots"));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP TABLE IF EXISTS moz_keywords"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // initialize bookmarks tables
   rv = nsNavBookmarks::InitTables(aDBConn);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // set pref indicating bookmarks.html should be imported.
   nsCOMPtr<nsIPrefBranch> prefs(do_GetService("@mozilla.org/preferences-service;1"));
@@ -1340,27 +1503,29 @@ nsNavHistory::ForceMigrateBookmarksDB(mo
 
 // nsNavHistory::MigrateV3Up
 nsresult
 nsNavHistory::MigrateV3Up(mozIStorageConnection* aDBConn) 
 {
   // if type col is already there, then a partial update occurred.
   // return, making no changes, and allowing db version to be updated.
   nsCOMPtr<mozIStorageStatement> statement;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING("SELECT type from moz_annos"),
-                                         getter_AddRefs(statement));
+  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT type from moz_annos"),
+    getter_AddRefs(statement));
   if (NS_SUCCEEDED(rv))
     return NS_OK;
 
   // add type column to moz_annos
   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "ALTER TABLE moz_annos ADD type INTEGER DEFAULT 0"));
+      "ALTER TABLE moz_annos ADD type INTEGER DEFAULT 0"));
   if (NS_FAILED(rv)) {
     // if the alteration failed, force-migrate
-    rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("DROP TABLE IF EXISTS moz_annos"));
+    rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP TABLE IF EXISTS moz_annos"));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = nsAnnotationService::InitTables(mDBConn);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
@@ -1369,71 +1534,71 @@ nsresult
 nsNavHistory::MigrateV6Up(mozIStorageConnection* aDBConn) 
 {
   mozStorageTransaction transaction(aDBConn, PR_FALSE);
 
   // if dateAdded & lastModified cols are already there, then a partial update occurred,
   // and so we should not attempt to add these cols.
   nsCOMPtr<mozIStorageStatement> statement;
   nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT a.dateAdded, a.lastModified FROM moz_annos a"), 
+      "SELECT a.dateAdded, a.lastModified FROM moz_annos a"), 
     getter_AddRefs(statement));
   if (NS_FAILED(rv)) {
     // add dateAdded and lastModified columns to moz_annos
     rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "ALTER TABLE moz_annos ADD dateAdded INTEGER DEFAULT 0"));
+        "ALTER TABLE moz_annos ADD dateAdded INTEGER DEFAULT 0"));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "ALTER TABLE moz_annos ADD lastModified INTEGER DEFAULT 0"));
+        "ALTER TABLE moz_annos ADD lastModified INTEGER DEFAULT 0"));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // if dateAdded & lastModified cols are already there, then a partial update occurred,
   // and so we should not attempt to add these cols.  see bug #408443 for details.
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT b.dateAdded, b.lastModified FROM moz_items_annos b"), 
+      "SELECT b.dateAdded, b.lastModified FROM moz_items_annos b"), 
     getter_AddRefs(statement));
   if (NS_FAILED(rv)) {
     // add dateAdded and lastModified columns to moz_items_annos
     rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "ALTER TABLE moz_items_annos ADD dateAdded INTEGER DEFAULT 0"));
+        "ALTER TABLE moz_items_annos ADD dateAdded INTEGER DEFAULT 0"));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "ALTER TABLE moz_items_annos ADD lastModified INTEGER DEFAULT 0"));
+        "ALTER TABLE moz_items_annos ADD lastModified INTEGER DEFAULT 0"));
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // we used to create an indexes on moz_favicons.url and
   // moz_anno_attributes.name, but those indexes are not needed
   // because those columns are UNIQUE, so remove them.
   // see bug #386303 for more details
-  rv = aDBConn->ExecuteSimpleSQL(
-    NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_favicons_url"));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = aDBConn->ExecuteSimpleSQL(
-    NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_anno_attributes_nameindex"));
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP INDEX IF EXISTS moz_favicons_url"));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP INDEX IF EXISTS moz_anno_attributes_nameindex"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return transaction.Commit();
 }
 
 // nsNavHistory::MigrateV7Up
 nsresult
 nsNavHistory::MigrateV7Up(mozIStorageConnection* aDBConn) 
 {
   mozStorageTransaction transaction(aDBConn, PR_FALSE);
 
   // Create a statement to test for trigger creation
   nsCOMPtr<mozIStorageStatement> triggerDetection;
   nsresult rv = aDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT name "
-    "FROM sqlite_master "
-    "WHERE type = 'trigger' "
-    "AND name = ?"
-  ), getter_AddRefs(triggerDetection));
+      "SELECT name "
+      "FROM sqlite_master "
+      "WHERE type = 'trigger' "
+      "AND name = ?"),
+    getter_AddRefs(triggerDetection));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Check for existence
   PRBool triggerExists;
   rv = triggerDetection->BindUTF8StringParameter(
     0, NS_LITERAL_CSTRING("moz_historyvisits_afterinsert_v1_trigger")
   );
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1444,28 +1609,29 @@ nsNavHistory::MigrateV7Up(mozIStorageCon
 
   // We need to create two triggers on moz_historyvists to maintain the
   // accuracy of moz_places.visit_count.  For this to work, we must ensure that
   // all moz_places.visit_count values are correct.
   // See bug 416313 for details.
   if (!triggerExists) {
     // First, we do a one-time reset of all the moz_places.visit_count values.
     rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "UPDATE moz_places SET visit_count = "
-        "(SELECT count(*) FROM moz_historyvisits "
-         "WHERE place_id = moz_places.id "
-         "AND visit_type NOT IN (0, 4, 7))") /* invalid, EMBED, DOWNLOAD */
-    );
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Now we create our two triggers
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_VISIT_COUNT_INSERT_TRIGGER);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_VISIT_COUNT_DELETE_TRIGGER);
-    NS_ENSURE_SUCCESS(rv, rv);
+        "UPDATE moz_places SET visit_count = "
+          "(SELECT count(*) FROM moz_historyvisits "
+           "WHERE place_id = moz_places.id "
+            "AND visit_type NOT IN ") +
+              nsPrintfCString("(0,%d,%d) ",
+                              nsINavHistoryService::TRANSITION_EMBED,
+                              nsINavHistoryService::TRANSITION_DOWNLOAD) +
+          NS_LITERAL_CSTRING(")"));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // We used to create two triggers here, but we no longer need that with
+    // schema version eight and greater.  We've removed their creation here as
+    // a result.
   }
 
   // Check for existence
   rv = triggerDetection->BindUTF8StringParameter(
     0, NS_LITERAL_CSTRING("moz_bookmarks_beforedelete_v1_trigger")
   );
   NS_ENSURE_SUCCESS(rv, rv);
   rv = triggerDetection->ExecuteStep(&triggerExists);
@@ -1473,36 +1639,51 @@ nsNavHistory::MigrateV7Up(mozIStorageCon
   rv = triggerDetection->Reset();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We need to create one trigger on moz_bookmarks to remove unused keywords.
   // See bug 421180 for details.
   if (!triggerExists) {
     // First, remove any existing dangling keywords
     rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "DELETE FROM moz_keywords "
-      "WHERE id IN ("
-        "SELECT k.id "
-        "FROM moz_keywords k "
-        "LEFT OUTER JOIN moz_bookmarks b "
-        "ON b.keyword_id = k.id "
-        "WHERE b.id IS NULL"
-      ")")
-    );
+        "DELETE FROM moz_keywords "
+        "WHERE id IN ("
+          "SELECT k.id "
+          "FROM moz_keywords k "
+          "LEFT OUTER JOIN moz_bookmarks b "
+          "ON b.keyword_id = k.id "
+          "WHERE b.id IS NULL"
+        ")"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Now we create our trigger
     rv = aDBConn->ExecuteSimpleSQL(CREATE_KEYWORD_VALIDITY_TRIGGER);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return transaction.Commit();
 }
 
 nsresult
+nsNavHistory::MigrateV8Up(mozIStorageConnection *aDBConn)
+{
+  mozStorageTransaction transaction(aDBConn, PR_FALSE);
+
+  nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP TRIGGER moz_historyvisits_afterinsert_v1_trigger"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP TRIGGER moz_historyvisits_afterdelete_v1_trigger"));
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  return transaction.Commit();
+}
+
+nsresult
 nsNavHistory::EnsureCurrentSchema(mozIStorageConnection* aDBConn, PRBool* aDidMigrate)
 {
   // We need an index on lastModified to catch quickly last modified bookmark
   // title for tag container's children. This will be useful for sync too.
   PRBool lastModIndexExists = PR_FALSE;
   nsresult rv = aDBConn->IndexExists(
     NS_LITERAL_CSTRING("moz_bookmarks_itemlastmodifiedindex"),
     &lastModIndexExists);
@@ -1541,35 +1722,36 @@ nsNavHistory::EnsureCurrentSchema(mozISt
 
     rv = pageindexTransaction.Commit();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // for existing profiles, we may not have a frecency column
   nsCOMPtr<mozIStorageStatement> statement;
   rv = aDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT frecency FROM moz_places"), getter_AddRefs(statement));
+      "SELECT frecency FROM moz_places"),
+    getter_AddRefs(statement));
 
   if (NS_FAILED(rv)) {
     *aDidMigrate = PR_TRUE;
     // wrap in a transaction for safety and performance
     mozStorageTransaction frecencyTransaction(aDBConn, PR_FALSE);
 
     // add frecency column to moz_places, default to -1
     // so that all the frecencies are invalid and we'll
     // recalculate them on idle.
     rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "ALTER TABLE moz_places ADD frecency INTEGER DEFAULT -1 NOT NULL"));
+        "ALTER TABLE moz_places ADD frecency INTEGER DEFAULT -1 NOT NULL"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // create index for the frecency column
     // XXX multi column index with typed, and visit_count?
     rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "CREATE INDEX IF NOT EXISTS "
-      "moz_places_frecencyindex ON moz_places (frecency)"));
+        "CREATE INDEX IF NOT EXISTS moz_places_frecencyindex "
+          "ON moz_places (frecency)"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // XXX todo
     // forcibly call the "on idle" timer here to do a little work
     // but the rest will happen on idle.
 
     // for place: items and unvisited livemark items, we need to set
     // the frecency to 0 so that they don't show up in url bar autocomplete
@@ -1585,130 +1767,136 @@ nsNavHistory::EnsureCurrentSchema(mozISt
 
 nsresult
 nsNavHistory::CleanUpOnQuit()
 {
   // bug #371800 - remove moz_places.user_title
   // test for moz_places.user_title
   nsCOMPtr<mozIStorageStatement> statement2;
   nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT user_title FROM moz_places"), getter_AddRefs(statement2));
+      "SELECT user_title FROM moz_places"),
+    getter_AddRefs(statement2));
   if (NS_SUCCEEDED(rv)) {
     mozStorageTransaction transaction(mDBConn, PR_FALSE);
     // 1. Indexes are moved along with the renamed table. Since we're dropping
     // that table, we're also dropping its indexes, and later re-creating them
     // for the new table.
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_places_urlindex"));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_places_titleindex"));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_places_faviconindex"));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_places_hostindex"));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_places_visitcount"));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_places_frecencyindex"));
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP INDEX IF EXISTS moz_places_urlindex"));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP INDEX IF EXISTS moz_places_titleindex"));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP INDEX IF EXISTS moz_places_faviconindex"));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP INDEX IF EXISTS moz_places_hostindex"));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP INDEX IF EXISTS moz_places_visitcount"));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP INDEX IF EXISTS moz_places_frecencyindex"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // 2. remove any duplicate URIs
     rv = RemoveDuplicateURIs();
     NS_ENSURE_SUCCESS(rv, rv);
 
     // 3. rename moz_places to moz_places_backup
-    rv = mDBConn->ExecuteSimpleSQL(
-      NS_LITERAL_CSTRING("ALTER TABLE moz_places RENAME TO moz_places_backup"));
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "ALTER TABLE moz_places RENAME TO moz_places_backup"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // 4. create moz_places w/o user_title
-    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING("CREATE TABLE moz_places ("
-        "id INTEGER PRIMARY KEY, "
-        "url LONGVARCHAR, "
-        "title LONGVARCHAR, "
-        "rev_host LONGVARCHAR, "
-        "visit_count INTEGER DEFAULT 0, "
-        "hidden INTEGER DEFAULT 0 NOT NULL, "
-        "typed INTEGER DEFAULT 0 NOT NULL, "
-        "favicon_id INTEGER, "
-        "frecency INTEGER DEFAULT -1 NOT NULL)"));
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "CREATE TABLE moz_places ("
+          "id INTEGER PRIMARY KEY, "
+          "url LONGVARCHAR, "
+          "title LONGVARCHAR, "
+          "rev_host LONGVARCHAR, "
+          "visit_count INTEGER DEFAULT 0, "
+          "hidden INTEGER DEFAULT 0 NOT NULL, "
+          "typed INTEGER DEFAULT 0 NOT NULL, "
+          "favicon_id INTEGER, "
+          "frecency INTEGER DEFAULT -1 NOT NULL)"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // 5. recreate the indexes
     // NOTE: tests showed that it's faster to create the indexes prior to filling
     // the table than it is to add them afterwards.
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("CREATE UNIQUE INDEX moz_places_url_uniqueindex ON moz_places (url)"));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("CREATE INDEX moz_places_faviconindex ON moz_places (favicon_id)"));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("CREATE INDEX moz_places_hostindex ON moz_places (rev_host)"));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("CREATE INDEX moz_places_visitcount ON moz_places (visit_count)"));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("CREATE INDEX moz_places_frecencyindex ON moz_places (frecency)"));
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "CREATE UNIQUE INDEX moz_places_url_uniqueindex ON moz_places (url)"));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "CREATE INDEX moz_places_faviconindex ON moz_places (favicon_id)"));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "CREATE INDEX moz_places_hostindex ON moz_places (rev_host)"));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "CREATE INDEX moz_places_visitcount ON moz_places (visit_count)"));
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "CREATE INDEX moz_places_frecencyindex ON moz_places (frecency)"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // 6. copy all data into moz_places
     rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "INSERT INTO moz_places "
-      "SELECT id, url, title, rev_host, visit_count, hidden, typed, favicon_id, frecency "
-      "FROM moz_places_backup"));
+        "INSERT INTO moz_places "
+        "SELECT id, url, title, rev_host, visit_count, hidden, typed, "
+          "favicon_id, frecency "
+        "FROM moz_places_backup"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // 7. drop moz_places_backup
     rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "DROP TABLE moz_places_backup"));
+        "DROP TABLE moz_places_backup"));
     NS_ENSURE_SUCCESS(rv, rv);
     transaction.Commit();
   }
 
   // bug #381795 - remove unused indexes
   mozStorageTransaction idxTransaction(mDBConn, PR_FALSE);
-  rv = mDBConn->ExecuteSimpleSQL(
-    NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_places_titleindex"));
-  rv = mDBConn->ExecuteSimpleSQL(
-    NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_annos_item_idindex"));
+  rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP INDEX IF EXISTS moz_places_titleindex"));
+  rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP INDEX IF EXISTS moz_annos_item_idindex"));
   idxTransaction.Commit();
 
   // Do a one-time re-creation of the moz_annos indexes (bug 415201)
   PRBool oldIndexExists = PR_FALSE;
-  rv = mDBConn->IndexExists(NS_LITERAL_CSTRING("moz_annos_attributesindex"), &oldIndexExists);
+  rv = mDBConn->IndexExists(NS_LITERAL_CSTRING("moz_annos_attributesindex"),
+                            &oldIndexExists);
   NS_ENSURE_SUCCESS(rv, rv);
   if (oldIndexExists) {
     // wrap in a transaction for safety and performance
     mozStorageTransaction annoIndexTransaction(mDBConn, PR_FALSE);
 
     // drop old uri annos index
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("DROP INDEX moz_annos_attributesindex"));
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP INDEX moz_annos_attributesindex"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // create new uri annos index
-    rv = mDBConn->ExecuteSimpleSQL(
-      NS_LITERAL_CSTRING("CREATE UNIQUE INDEX moz_annos_placeattributeindex ON moz_annos (place_id, anno_attribute_id)"));
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "CREATE UNIQUE INDEX moz_annos_placeattributeindex "
+          "ON moz_annos (place_id, anno_attribute_id)"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // drop old item annos index
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("DROP INDEX IF EXISTS moz_items_annos_attributesindex"));
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP INDEX IF EXISTS moz_items_annos_attributesindex"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     // create new item annos index
-    rv = mDBConn->ExecuteSimpleSQL(
-      NS_LITERAL_CSTRING("CREATE UNIQUE INDEX moz_items_annos_itemattributeindex ON moz_items_annos (item_id, anno_attribute_id)"));
+    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "CREATE UNIQUE INDEX moz_items_annos_itemattributeindex "
+        "ON moz_items_annos (item_id, anno_attribute_id)"));
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = annoIndexTransaction.Commit();
     NS_ENSURE_SUCCESS(rv, rv);
   }
   return NS_OK;
 }
 
@@ -1884,16 +2072,17 @@ nsNavHistory::InternalAddVisit(PRInt64 a
 
     PRBool hasResult;
     rv = mDBRecentVisitOfPlace->ExecuteStep(&hasResult);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ASSERTION(hasResult, "hasResult is false but the call succeeded?");
 
     *visitID = mDBRecentVisitOfPlace->AsInt64(0);
   }
+
   return NS_OK;
 }
 
 
 // nsNavHistory::FindLastVisit
 //
 //    This finds the most recent visit to the given URL. If found, it will put
 //    that visit's ID and session into the respective out parameters and return
@@ -2415,43 +2604,52 @@ nsNavHistory::DomainNameFromURI(nsIURI *
 // nsNavHistory::GetHasHistoryEntries
 
 NS_IMETHODIMP
 nsNavHistory::GetHasHistoryEntries(PRBool* aHasEntries)
 {
   NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
 
   nsCOMPtr<mozIStorageStatement> dbSelectStatement;
-  nsresult rv = mDBConn->CreateStatement(
-      NS_LITERAL_CSTRING("SELECT id FROM moz_historyvisits LIMIT 1"),
-      getter_AddRefs(dbSelectStatement));
+  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT 1 "
+      "WHERE EXISTS (SELECT id FROM moz_historyvisits_temp LIMIT 1) "
+        "OR EXISTS (SELECT id FROM moz_historyvisits LIMIT 1)"),
+    getter_AddRefs(dbSelectStatement));
   NS_ENSURE_SUCCESS(rv, rv);
   return dbSelectStatement->ExecuteStep(aHasEntries);
 }
 
 nsresult
 nsNavHistory::FixInvalidFrecenciesForExcludedPlaces()
 {
   // for every moz_place that has an invalid frecency (< 0) and
   // is an unvisited child of a livemark feed, or begins with "place:",
   // set frecency to 0 so that it is excluded from url bar autocomplete.
   nsCOMPtr<mozIStorageStatement> dbUpdateStatement;
   nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "UPDATE moz_places "
-    "SET frecency = 0 WHERE id IN ("
-      "SELECT h.id FROM moz_places h "
-      "LEFT OUTER JOIN moz_bookmarks b ON h.id = b.fk "
-      "WHERE frecency < 0 AND "
-        // place is an unvisited child of a livemark feed
-        "(b.parent IN ("
-            "SELECT annos.item_id FROM moz_anno_attributes attrs "
-            "JOIN moz_items_annos annos ON attrs.id = annos.anno_attribute_id "
-            "WHERE attrs.name = ?1) "
-          "AND visit_count = 0) "
-        "OR SUBSTR(h.url,0,6) = 'place:')"),
+      "UPDATE moz_places_view "
+      "SET frecency = 0 WHERE id IN ("
+        "SELECT h.id FROM moz_places h "
+        "WHERE h.url >= 'place:' AND h.url < 'place;' "
+        "UNION "
+        "SELECT h.id FROM moz_places_temp h "
+        "WHERE  h.url >= 'place:' AND h.url < 'place;' "
+        "UNION "
+        // Unvisited child of a livemark        
+        "SELECT b.fk FROM moz_bookmarks b "
+        "JOIN moz_items_annos a ON a.item_id = b.id "
+        "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
+        "WHERE n.name = ?1 "
+        "AND fk IN( "
+          "SELECT id FROM moz_places WHERE visit_count = 0 AND frecency < 0 "
+          "UNION ALL "
+          "SELECT id FROM moz_places_temp WHERE visit_count = 0 AND frecency < 0 "
+        ") "
+      ")"),
     getter_AddRefs(dbUpdateStatement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = dbUpdateStatement->BindUTF8StringParameter(0, NS_LITERAL_CSTRING(LMANNO_FEEDURI));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = dbUpdateStatement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
@@ -3053,29 +3251,170 @@ PlacesSQLQueryBuilder::Select()
 }
 
 nsresult
 PlacesSQLQueryBuilder::SelectAsURI()
 {
   switch (mQueryType)
   {
     case nsINavHistoryQueryOptions::QUERY_TYPE_HISTORY:
-      mQueryString = NS_LITERAL_CSTRING(
-        "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
-          "MAX(visit_date), f.url, null, null "
-        "FROM moz_places h "
-             "LEFT OUTER JOIN moz_historyvisits v ON h.id = v.place_id "
-             "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id ");
-
-      if (!mIncludeHidden)
-        mQueryString += NS_LITERAL_CSTRING(
-          " WHERE h.hidden <> 1 AND v.visit_type NOT IN (0,4)"
-            " {ADDITIONAL_CONDITIONS} ");
-
-      mGroupBy = NS_LITERAL_CSTRING(" GROUP BY h.id");
+      if (!mIncludeHidden) {
+        mQueryString = NS_LITERAL_CSTRING(
+          "SELECT id, url, title, rev_host, visit_count, MAX(visit_date), "
+            "favicon_url, session, empty "
+          "FROM ( "
+            "SELECT id, url, title, rev_host, visit_count, visit_date, "
+              "favicon_url, session, empty "
+            "FROM ("
+              "SELECT h.id AS id, h.url AS url, h.title AS title, "
+                "h.rev_host AS rev_host, h.visit_count AS visit_count, "
+                "MAX(v.visit_date) AS visit_date, f.url AS favicon_url, "
+                "v.session AS session, null AS empty "
+              "FROM moz_places h "
+              "JOIN moz_historyvisits v ON h.id = v.place_id "
+              "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+              "WHERE h.hidden <> 1 AND v.visit_type NOT IN ") +
+                nsPrintfCString("(0,%d,%d) ",
+                                nsINavHistoryService::TRANSITION_EMBED,
+                                nsINavHistoryService::TRANSITION_DOWNLOAD) +
+                NS_LITERAL_CSTRING("AND h.visit_count > 0 "
+                "{ADDITIONAL_CONDITIONS} "
+              "GROUP BY h.id "
+            ") "
+            "UNION ALL "
+            "SELECT id, url, title, rev_host, visit_count, visit_date, "
+              "favicon_url, session, empty "
+            "FROM ( "
+              "SELECT h.id AS id, h.url AS url, h.title AS title, "
+                "h.rev_host AS rev_host, h.visit_count AS visit_count, "
+                "MAX(v.visit_date) AS visit_date, f.url AS favicon_url, "
+                "v.session AS session, null AS empty "
+              "FROM moz_places_temp h "
+              "JOIN moz_historyvisits v ON h.id = v.place_id "
+              "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+              "WHERE h.hidden <> 1 AND v.visit_type NOT IN ") +
+                nsPrintfCString("(0,%d,%d) ",
+                                nsINavHistoryService::TRANSITION_EMBED,
+                                nsINavHistoryService::TRANSITION_DOWNLOAD) +
+                NS_LITERAL_CSTRING("AND h.visit_count > 0 "
+                "AND h.id NOT IN (SELECT id FROM moz_places_temp) "
+                "{ADDITIONAL_CONDITIONS} "
+              "GROUP BY h.id "
+            ") "
+            "UNION ALL "
+            "SELECT id, url, title, rev_host, visit_count, visit_date, "
+              "favicon_url, session, empty "
+            "FROM ( "
+              "SELECT h.id AS id, h.url AS url, h.title AS title, "
+                "h.rev_host AS rev_host, h.visit_count AS visit_count, "
+                "MAX(v.visit_date) AS visit_date, f.url AS favicon_url, "
+                "v.session AS session, null AS empty "
+              "FROM moz_places h "
+              "JOIN moz_historyvisits_temp v ON h.id = v.place_id "
+              "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+              "WHERE h.hidden <> 1 AND v.visit_type NOT IN ") +
+                nsPrintfCString("(0,%d,%d) ",
+                                nsINavHistoryService::TRANSITION_EMBED,
+                                nsINavHistoryService::TRANSITION_DOWNLOAD) +
+                NS_LITERAL_CSTRING("AND h.visit_count > 0 "
+                "AND h.id NOT IN (SELECT id FROM moz_places_temp) "
+                "{ADDITIONAL_CONDITIONS} "
+              "GROUP BY h.id "
+            ") "
+            "UNION ALL "
+            "SELECT id, url, title, rev_host, visit_count, visit_date, "
+              "favicon_url, session, empty "
+            "FROM ( "
+              "SELECT h.id AS id, h.url AS url, h.title AS title, "
+                "h.rev_host AS rev_host, h.visit_count AS visit_count, "
+                "MAX(v.visit_date) AS visit_date, f.url AS favicon_url, "
+                "v.session AS session, null AS empty "
+              "FROM moz_places_temp h "
+              "JOIN moz_historyvisits_temp v ON h.id = v.place_id "
+              "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+              "WHERE h.hidden <> 1 AND v.visit_type NOT IN ") +
+                nsPrintfCString("(0,%d,%d) ",
+                                nsINavHistoryService::TRANSITION_EMBED,
+                                nsINavHistoryService::TRANSITION_DOWNLOAD) +
+                NS_LITERAL_CSTRING("AND h.visit_count > 0 "
+                "{ADDITIONAL_CONDITIONS} "
+              "GROUP BY h.id "
+            ") "
+          ") "
+          "GROUP BY id ");
+      }
+      else {
+        mQueryString = NS_LITERAL_CSTRING(
+          "SELECT id, url, title, rev_host, visit_count, MAX(visit_date), "
+            "favicon_url, session, empty "
+          "FROM ( "
+            "SELECT id, url, title, rev_host, visit_count, visit_date, "
+              "favicon_url, session, empty "
+            "FROM ("
+              "SELECT h.id AS id, h.url AS url, h.title AS title, "
+                "h.rev_host AS rev_host, h.visit_count AS visit_count, "
+                "MAX(v.visit_date) AS visit_date, f.url AS favicon_url, "
+                "v.session AS session, null AS empty "
+              "FROM moz_places h "
+              "JOIN moz_historyvisits v ON h.id = v.place_id "
+              "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+              // no-op since {ADDITIONAL_CONDITIONS} will start with AND
+              "WHERE 1=1 "
+                "{ADDITIONAL_CONDITIONS} "
+              "GROUP BY h.id "
+            ") "
+            "UNION ALL "
+            "SELECT id, url, title, rev_host, visit_count, visit_date, "
+              "favicon_url, session, empty "
+            "FROM ( "
+              "SELECT h.id AS id, h.url AS url, h.title AS title, "
+                "h.rev_host AS rev_host, h.visit_count AS visit_count, "
+                "MAX(v.visit_date) AS visit_date, f.url AS favicon_url, "
+                "v.session AS session, null AS empty "
+              "FROM moz_places_temp h "
+              "JOIN moz_historyvisits v ON h.id = v.place_id "
+              "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+              "WHERE h.id NOT IN (SELECT id FROM moz_places_temp) "
+                "{ADDITIONAL_CONDITIONS} "
+              "GROUP BY h.id "
+            ") "
+            "UNION ALL "
+            "SELECT id, url, title, rev_host, visit_count, visit_date, "
+              "favicon_url, session, empty "
+            "FROM ( "
+              "SELECT h.id AS id, h.url AS url, h.title AS title, "
+                "h.rev_host AS rev_host, h.visit_count AS visit_count, "
+                "MAX(v.visit_date) AS visit_date, f.url AS favicon_url, "
+                "v.session AS session, null AS empty "
+              "FROM moz_places h "
+              "JOIN moz_historyvisits_temp v ON h.id = v.place_id "
+              "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+              "WHERE h.id NOT IN (SELECT id FROM moz_places_temp) "
+                "{ADDITIONAL_CONDITIONS} "
+              "GROUP BY h.id "
+            ") "
+            "UNION ALL "
+            "SELECT id, url, title, rev_host, visit_count, visit_date, "
+              "favicon_url, session, empty "
+            "FROM ( "
+              "SELECT h.id AS id, h.url AS url, h.title AS title, "
+                "h.rev_host AS rev_host, h.visit_count AS visit_count, "
+                "MAX(v.visit_date) AS visit_date, f.url AS favicon_url, "
+                "v.session AS session, null AS empty "
+              "FROM moz_places_temp h "
+              "JOIN moz_historyvisits_temp v ON h.id = v.place_id "
+              "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+              // no-op since {ADDITIONAL_CONDITIONS} will start with AND
+              "WHERE 1=1 "
+                "{ADDITIONAL_CONDITIONS} "
+              "GROUP BY h.id "
+            ") "
+          ") "
+          "GROUP BY id ");    
+      }
       break;
 
     case nsINavHistoryQueryOptions::QUERY_TYPE_BOOKMARKS:
       // Don't initialize on var creation, that would give an error on compile
       // because we are in the same scope of the switch clause and the var could
       // not be initialized. Do an assignment rather than an initialization.
       nsNavHistory* history;
       history = nsNavHistory::GetHistoryService();
@@ -3089,63 +3428,177 @@ PlacesSQLQueryBuilder::SelectAsURI()
         mSkipOrderBy = PR_TRUE;
 
         mQueryString = NS_LITERAL_CSTRING(
           "SELECT b2.fk, h.url, COALESCE(b2.title, h.title), h.rev_host, "
             "h.visit_count, "
             SQL_STR_FRAGMENT_MAX_VISIT_DATE( "b2.fk" )
             ", f.url, null, b2.id, b2.dateAdded, b2.lastModified "
           "FROM moz_bookmarks b2 "
-            "JOIN moz_places h ON b2.fk = h.id AND b2.type = 1 "
-            "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
-            "WHERE b2.id IN ("
-              "SELECT b1.id FROM moz_bookmarks b1 "
-              "WHERE b1.fk IN "
-                "(SELECT b.fk FROM moz_bookmarks b WHERE b.type = 1 {ADDITIONAL_CONDITIONS}) "
-              "AND NOT EXISTS "
-                "(SELECT id FROM moz_bookmarks WHERE id = b1.parent AND parent = ") +
+          "JOIN moz_places_temp h ON b2.fk = h.id AND b2.type = 1 "
+          "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
+          "WHERE b2.id IN ( "
+            "SELECT b1.id FROM moz_bookmarks b1 "
+            "WHERE b1.fk IN "
+              "(SELECT b.fk FROM moz_bookmarks b WHERE b.type = 1 {ADDITIONAL_CONDITIONS}) "
+            "AND NOT EXISTS ( "
+              "SELECT id FROM moz_bookmarks WHERE id = b1.parent AND parent = ") +
                 nsPrintfCString("%lld", history->GetTagsFolder()) +
-              NS_LITERAL_CSTRING(")) ORDER BY b2.fk DESC, b2.lastModified DESC");
+              NS_LITERAL_CSTRING(") "
+          ") "
+          "UNION ALL "
+          "SELECT b2.fk, h.url, COALESCE(b2.title, h.title), h.rev_host, "
+            "h.visit_count, "
+            SQL_STR_FRAGMENT_MAX_VISIT_DATE( "b2.fk" )
+            ", f.url, null, b2.id, b2.dateAdded, b2.lastModified "
+          "FROM moz_bookmarks b2 "
+          "JOIN moz_places h ON b2.fk = h.id AND b2.type = 1 "
+          "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
+          "WHERE b2.id IN ( "
+            "SELECT b1.id FROM moz_bookmarks b1 "
+            "WHERE h.id NOT IN (SELECT id FROM moz_places_temp) "
+            "AND b1.fk IN "
+              "(SELECT b.fk FROM moz_bookmarks b WHERE b.type = 1 {ADDITIONAL_CONDITIONS}) "
+            "AND NOT EXISTS ( "
+              "SELECT id FROM moz_bookmarks WHERE id = b1.parent AND parent = ") +
+                nsPrintfCString("%lld", history->GetTagsFolder()) +
+              NS_LITERAL_CSTRING(") "
+          ") "          
+          "ORDER BY b2.fk DESC, b2.lastModified DESC");
       }
       else {
         mQueryString = NS_LITERAL_CSTRING(
           "SELECT b.fk, h.url, COALESCE(b.title, h.title), h.rev_host, "
             "h.visit_count,"
             SQL_STR_FRAGMENT_MAX_VISIT_DATE( "b.fk" )
             ", f.url, null, b.id, b.dateAdded, b.lastModified "
           "FROM moz_bookmarks b "
-          "JOIN moz_places h ON b.fk = h.id AND b.type = 1 "
+          "JOIN moz_places_temp h ON b.fk = h.id AND b.type = 1 "
           "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
           "WHERE NOT EXISTS "
-            "(SELECT id FROM moz_bookmarks WHERE id = b.parent AND parent = ") +
-            nsPrintfCString("%lld", history->GetTagsFolder()) +
-            NS_LITERAL_CSTRING(") {ADDITIONAL_CONDITIONS}");
+            "(SELECT id FROM moz_bookmarks "
+              "WHERE id = b.parent AND parent = ") +
+                nsPrintfCString("%lld", history->GetTagsFolder()) +
+            NS_LITERAL_CSTRING(") "
+            "{ADDITIONAL_CONDITIONS}"
+          "UNION ALL "
+          "SELECT b.fk, h.url, COALESCE(b.title, h.title), h.rev_host, "
+            "h.visit_count,"
+            SQL_STR_FRAGMENT_MAX_VISIT_DATE( "b.fk" )
+            ", f.url, null, b.id, b.dateAdded, b.lastModified "
+          "FROM moz_bookmarks b "
+          "JOIN moz_places h ON b.fk = h.id AND b.type = 1 "
+          "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
+          "WHERE h.id NOT IN (SELECT id FROM moz_places_temp) "
+            "AND NOT EXISTS "
+              "(SELECT id FROM moz_bookmarks "
+                "WHERE id = b.parent AND parent = ") +
+                  nsPrintfCString("%lld", history->GetTagsFolder()) +
+              NS_LITERAL_CSTRING(") "
+            "{ADDITIONAL_CONDITIONS}");
       }
       break;
 
     default:
       return NS_ERROR_NOT_IMPLEMENTED;
   }
   return NS_OK;
 }
 
 nsresult
 PlacesSQLQueryBuilder::SelectAsVisit()
 {
-  mQueryString = NS_LITERAL_CSTRING(
-    "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
-      "v.visit_date, f.url, v.session, null "
-    "FROM moz_places h "
-         "LEFT OUTER JOIN moz_historyvisits v ON h.id = v.place_id "
-         "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id ");
-
-  if (!mIncludeHidden)
-    mQueryString += NS_LITERAL_CSTRING(
-      " WHERE h.hidden <> 1 AND v.visit_type NOT IN (0,4)"
-        " {ADDITIONAL_CONDITIONS} ");
+  if (!mIncludeHidden) {
+    mQueryString = NS_LITERAL_CSTRING(
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+        "v.visit_date, f.url, v.session, null "
+      "FROM moz_places h "
+      "JOIN moz_historyvisits v ON h.id = v.place_id "
+      "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+      "WHERE h.visit_count > 0 "
+        "AND h.hidden <> 1 AND v.visit_type NOT IN ") +
+          nsPrintfCString("(0,%d,%d) ",
+                          nsINavHistoryService::TRANSITION_EMBED,
+                          nsINavHistoryService::TRANSITION_DOWNLOAD) +
+        NS_LITERAL_CSTRING("AND h.id NOT IN (SELECT id FROM moz_places_temp) "
+        "{ADDITIONAL_CONDITIONS} "
+      "UNION ALL "
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+        "v.visit_date, f.url, v.session, null "
+      "FROM moz_places_temp h "
+      "JOIN moz_historyvisits v ON h.id = v.place_id "
+      "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+      "WHERE h.visit_count > 0 "
+        "AND h.hidden <> 1 AND v.visit_type NOT IN ") +
+          nsPrintfCString("(0,%d,%d) ",
+                          nsINavHistoryService::TRANSITION_EMBED,
+                          nsINavHistoryService::TRANSITION_DOWNLOAD) +
+        NS_LITERAL_CSTRING("{ADDITIONAL_CONDITIONS} "
+      "UNION ALL "
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+        "v.visit_date, f.url, v.session, null "
+      "FROM moz_places h "
+      "JOIN moz_historyvisits_temp v ON h.id = v.place_id "
+      "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+      "WHERE h.visit_count > 0 "
+        "AND h.id NOT IN (SELECT id FROM moz_places_temp) "
+        "AND h.hidden <> 1 AND v.visit_type NOT IN ") +
+          nsPrintfCString("(0,%d,%d) ", 
+                          nsINavHistoryService::TRANSITION_EMBED,
+                          nsINavHistoryService::TRANSITION_DOWNLOAD) +
+        NS_LITERAL_CSTRING("{ADDITIONAL_CONDITIONS} "
+      "UNION ALL "
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+        "v.visit_date, f.url, v.session, null "
+      "FROM moz_places_temp h "
+      "JOIN moz_historyvisits_temp v ON h.id = v.place_id "
+      "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+      "WHERE h.visit_count > 0 "
+        "AND h.hidden <> 1 AND v.visit_type NOT IN ") +
+          nsPrintfCString("(0,%d,%d) ",
+                          nsINavHistoryService::TRANSITION_EMBED,
+                          nsINavHistoryService::TRANSITION_DOWNLOAD) +
+        NS_LITERAL_CSTRING("{ADDITIONAL_CONDITIONS} ");
+  }
+  else {
+    mQueryString = NS_LITERAL_CSTRING(
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+        "v.visit_date, f.url, v.session, null "
+      "FROM moz_places h "
+      "JOIN moz_historyvisits v ON h.id = v.place_id "
+      "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+      "WHERE h.id NOT IN (SELECT id FROM moz_places_temp) "
+        "{ADDITIONAL_CONDITIONS} "
+      "UNION ALL "
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+        "v.visit_date, f.url, v.session, null "
+      "FROM moz_places_temp h "
+      "JOIN moz_historyvisits v ON h.id = v.place_id "
+      "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+      // no-op since {ADDITIONAL_CONDITIONS} will start with AND
+      "WHERE 1=1 "
+        "{ADDITIONAL_CONDITIONS} "
+      "UNION ALL "
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+        "v.visit_date, f.url, v.session, null "
+      "FROM moz_places h "
+      "JOIN moz_historyvisits_temp v ON h.id = v.place_id "
+      "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+      "WHERE h.id NOT IN (SELECT id FROM moz_places_temp) "
+        "{ADDITIONAL_CONDITIONS} "
+      "UNION ALL "
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+        "v.visit_date, f.url, v.session, null "
+      "FROM moz_places_temp h "
+      "JOIN moz_historyvisits_temp v ON h.id = v.place_id "
+      "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
+      // no-op since {ADDITIONAL_CONDITIONS} will start with AND
+      "WHERE 1=1 "
+      "{ADDITIONAL_CONDITIONS} ");
+  }
 
   return NS_OK;
 }
 
 nsresult
 PlacesSQLQueryBuilder::SelectAsDay()
 {
   mSkipOrderBy = PR_TRUE;
@@ -3202,58 +3655,83 @@ PlacesSQLQueryBuilder::SelectAsDay()
 
     mAddParams.Put(dateParam, dateName);
 
     PRInt32 fromDayAgo = -i;
     PRInt32 toDayAgo = -i + 1;
 
     nsPrintfCString dayRange(1024,
       "SELECT * "
-      "FROM (SELECT %d dayOrder, "
-                  "'%d' dayRange, "
-                  "%s dayTitle, " // This will be bound
-                  "%llu beginTime, "
-                  "%llu endTime "
-      "FROM  moz_historyvisits "
-      "WHERE visit_date >= %llu AND visit_date < %llu "
-      "  AND visit_type NOT IN (0,4) "
+      "FROM ( "
+        "SELECT %d dayOrder, "
+               "'%d' dayRange, "
+               "%s dayTitle, " // This will be bound
+               "%llu beginTime, "
+               "%llu endTime "
+        "WHERE EXISTS ( "
+          "SELECT id FROM moz_historyvisits_temp "
+          "WHERE visit_date >= %llu "
+            "AND visit_date < %llu "
+            "AND visit_type NOT IN (0, 4) "
+          "LIMIT 1 "
+        ") "
+        "OR EXISTS ( "
+          "SELECT * FROM moz_historyvisits "
+          "WHERE visit_date >= %llu "
+            "AND visit_date < %llu "
+            "AND visit_type NOT IN (0, 4) "
+          "LIMIT 1 "
+        ") "
       "LIMIT 1) TUNION%d UNION ", 
       i, i, dateParam.get(), 
       midnight.Get(fromDayAgo),
       midnight.Get(toDayAgo), 
       midnight.Get(fromDayAgo),
       midnight.Get(toDayAgo),
+      midnight.Get(fromDayAgo),
+      midnight.Get(toDayAgo),
       i);
 
     mQueryString.Append( dayRange );
   }
 
   dateParam = nsPrintfCString(":dayTitle%d", MAX_HISTORY_DAYS+1);
   history->GetAgeInDaysString(MAX_HISTORY_DAYS, 
     NS_LITERAL_STRING("finduri-AgeInDays-isgreater").get(), dateName);
 
   mAddParams.Put(dateParam, dateName);
 
   mQueryString.Append(nsPrintfCString(1024,
     "SELECT * "
-    "FROM (SELECT %d dayOrder, "
-                 "'%d+' dayRange, "
-                 "%s dayTitle, " // This will be bound
-                 "1 beginTime, "
-                 "%llu endTime "
-          "FROM  moz_historyvisits "
-          "WHERE visit_date < %llu "
-          "  AND visit_type NOT IN (0,4) "
-          "LIMIT 1) TUNIONLAST "
+    "FROM ("
+      "SELECT %d dayOrder, "
+            "'%d+' dayRange, "
+            "%s dayTitle, " // This will be bound
+            "1 beginTime, "
+            "%llu endTime "
+      "WHERE EXISTS ( "
+        "SELECT id FROM moz_historyvisits_temp "
+        "WHERE visit_date < %llu "
+          "AND visit_type NOT IN (0, 4) "
+        "LIMIT 1 "
+      ") "
+      "OR EXISTS ( "
+        "SELECT id FROM moz_historyvisits "
+        "WHERE visit_date < %llu "
+          "AND visit_type NOT IN (0, 4) "
+        "LIMIT 1 "
+      ") "
+      "LIMIT 1) TUNIONLAST "
     ") TOUTER " // TOUTER END
     "ORDER BY dayOrder ASC",
     MAX_HISTORY_DAYS+1,
     MAX_HISTORY_DAYS+1,
     dateParam.get(),
     midnight.Get(-MAX_HISTORY_DAYS),
+    midnight.Get(-MAX_HISTORY_DAYS),
     midnight.Get(-MAX_HISTORY_DAYS)
     ));
 
   return NS_OK;
 }
 
 nsresult
 PlacesSQLQueryBuilder::SelectAsSite()
@@ -3263,69 +3741,133 @@ PlacesSQLQueryBuilder::SelectAsSite()
   nsNavHistory* history = nsNavHistory::GetHistoryService();
   NS_ENSURE_STATE(history);
 
   history->GetStringFromName(NS_LITERAL_STRING("localhost").get(), localFiles);
   mAddParams.Put(NS_LITERAL_CSTRING(":localhost"), localFiles);
 
   // We want just sites, but from whole database.
   if (mConditions.IsEmpty()) {
-
     mQueryString = nsPrintfCString(2048,
       "SELECT DISTINCT null, "
              "'place:type=%ld&sort=%ld&domain=&domainIsHost=true', "
              ":localhost, :localhost, null, null, null, null, null "
-      "WHERE EXISTS(SELECT '*' "
-                   "FROM moz_places "
-                   "WHERE hidden <> 1 AND rev_host = '.' "
-                     "AND visit_count > 0 "
-                     "AND url BETWEEN 'file://' AND 'file:/~') "
+      "WHERE EXISTS ( "
+        "SELECT id FROM moz_places_temp "
+        "WHERE hidden <> 1 "
+          "AND rev_host = '.' "
+          "AND visit_count > 0 "
+          "AND url BETWEEN 'file://' AND 'file:/~' "
+        "UNION ALL "
+        "SELECT id FROM moz_places "
+        "WHERE id NOT IN (SELECT id FROM moz_places_temp) "
+          "AND hidden <> 1 "
+          "AND rev_host = '.' "
+          "AND visit_count > 0 "
+          "AND url BETWEEN 'file://' AND 'file:/~' "
+      ") "
       "UNION ALL "
       "SELECT DISTINCT null, "
              "'place:type=%ld&sort=%ld&domain='||host||'&domainIsHost=true', "
              "host, host, null, null, null, null, null "
-      "FROM (SELECT get_unreversed_host(rev_host) host "
-            "FROM (SELECT DISTINCT rev_host "
-                  "FROM moz_places "
-                  "WHERE hidden <> 1 AND rev_host <> '.' "
-                    "AND visit_count > 0 ) inner0 "
-            "ORDER BY 1 ASC) inner1",
+      "FROM ( "
+        "SELECT get_unreversed_host(rev_host) host "
+        "FROM ( "
+          "SELECT DISTINCT rev_host FROM moz_places_temp "
+          "WHERE hidden <> 1 "
+            "AND rev_host <> '.' "
+            "AND visit_count > 0 "
+          "UNION ALL "
+          "SELECT DISTINCT rev_host FROM moz_places "
+          "WHERE id NOT IN (SELECT id FROM moz_places_temp) "
+            "AND hidden <> 1 "
+            "AND rev_host <> '.' "
+            "AND visit_count > 0 "
+        ") "
+      "ORDER BY 1 ASC)",
       nsINavHistoryQueryOptions::RESULTS_AS_URI,
       nsINavHistoryQueryOptions::SORT_BY_TITLE_ASCENDING,
       nsINavHistoryQueryOptions::RESULTS_AS_URI,
       nsINavHistoryQueryOptions::SORT_BY_TITLE_ASCENDING);
   // Now we need to use the filters - we need them all
   } else {
 
     mQueryString = nsPrintfCString(4096,
       "SELECT DISTINCT null, "
              "'place:type=%ld&sort=%ld&domain=&domainIsHost=true"
                "&beginTime='||:begin_time||'&endTime='||:end_time, "
              ":localhost, :localhost, null, null, null, null, null "
-      "WHERE EXISTS(SELECT '*' "
-                   "FROM moz_places h  "
-                        "JOIN moz_historyvisits v ON h.id = v.place_id "
-                   "WHERE h.hidden <> 1 AND h.rev_host = '.' "
-                     "AND h.visit_count > 0 "
-                     "AND h.url BETWEEN 'file://' AND 'file:/~' "
-                     "AND v.visit_type NOT IN (0,4) {ADDITIONAL_CONDITIONS} ) "
+      "WHERE EXISTS( "
+        "SELECT h.id "
+        "FROM moz_places h "
+        "JOIN moz_historyvisits v ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 AND h.rev_host = '.' "
+          "AND h.visit_count > 0 "
+          "AND h.url BETWEEN 'file://' AND 'file:/~' "
+          "{ADDITIONAL_CONDITIONS} "
+        "UNION "
+        "SELECT h.id "
+        "FROM moz_places_temp h "
+        "JOIN moz_historyvisits v ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 AND h.rev_host = '.' "
+          "AND h.visit_count > 0 "
+          "AND h.url BETWEEN 'file://' AND 'file:/~' "
+          "{ADDITIONAL_CONDITIONS} "
+        "UNION "
+        "SELECT h.id "
+        "FROM moz_places h "
+        "JOIN moz_historyvisits_temp v ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 AND h.rev_host = '.' "
+          "AND h.visit_count > 0 "
+          "AND h.url BETWEEN 'file://' AND 'file:/~' "
+          "{ADDITIONAL_CONDITIONS} "
+        "UNION "
+        "SELECT h.id "
+        "FROM moz_places_temp h "
+        "JOIN moz_historyvisits_temp v ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 AND h.rev_host = '.' "
+          "AND h.visit_count > 0 "
+          "AND h.url BETWEEN 'file://' AND 'file:/~' "
+          "{ADDITIONAL_CONDITIONS} "        
+      ") "
       "UNION ALL "
       "SELECT DISTINCT null, "
              "'place:type=%ld&sort=%ld&domain='||host||'&domainIsHost=true"
                "&beginTime='||:begin_time||'&endTime='||:end_time, "
              "host, host, null, null, null, null, null "
-      "FROM (SELECT get_unreversed_host(rev_host) host "
-            "FROM (SELECT DISTINCT rev_host "
-                  "FROM moz_places h "
-                       "JOIN moz_historyvisits v ON h.id = v.place_id "
-                  "WHERE h.hidden <> 1 AND h.rev_host <> '.' "
-                    "AND h.visit_count > 0 "
-                    "AND v.visit_type NOT IN (0,4) "
-                    "{ADDITIONAL_CONDITIONS} ) inner0 "
-            "ORDER BY 1 ASC) inner1",
+      "FROM ( "
+        "SELECT DISTINCT get_unreversed_host(rev_host) AS host "
+        "FROM moz_places h "
+        "JOIN moz_historyvisits v ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 AND h.rev_host <> '.' "
+          "AND h.visit_count > 0 "
+          "{ADDITIONAL_CONDITIONS} "
+        "UNION "
+        "SELECT DISTINCT get_unreversed_host(rev_host) AS host "
+        "FROM moz_places_temp h "
+        "JOIN moz_historyvisits v ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 AND h.rev_host <> '.' "
+          "AND h.visit_count > 0 "
+          "{ADDITIONAL_CONDITIONS} "
+        "UNION "
+        "SELECT DISTINCT get_unreversed_host(rev_host) AS host "
+        "FROM moz_places h "
+        "JOIN moz_historyvisits_temp v ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 AND h.rev_host <> '.' "
+          "AND h.visit_count > 0 "
+          "{ADDITIONAL_CONDITIONS} "
+        "UNION "
+        "SELECT DISTINCT get_unreversed_host(rev_host) AS host "
+        "FROM moz_places_temp h "
+        "JOIN moz_historyvisits_temp v ON v.place_id = h.id "        
+        "WHERE h.hidden <> 1 AND h.rev_host <> '.' "
+          "AND h.visit_count > 0 "
+          "{ADDITIONAL_CONDITIONS} "        
+        "ORDER BY 1 ASC "
+      ")",
       nsINavHistoryQueryOptions::RESULTS_AS_URI,
       nsINavHistoryQueryOptions::SORT_BY_TITLE_ASCENDING,
       nsINavHistoryQueryOptions::RESULTS_AS_URI,
       nsINavHistoryQueryOptions::SORT_BY_TITLE_ASCENDING);
   }
 
   return NS_OK;
 }
@@ -3502,50 +4044,86 @@ nsNavHistory::ConstructQueryString(
     return NS_ERROR_INVALID_ARG;
   }
 
   // for the very special query for the history menu 
   // we generate a super-optimized SQL query
   if (IsHistoryMenuQuery(aQueries, aOptions, 
         nsINavHistoryQueryOptions::SORT_BY_DATE_DESCENDING)) {
 
+    nsCString sqlFragment = NS_LITERAL_CSTRING(
+      "SELECT * FROM ( "
+        "SELECT DISTINCT place_id "
+        "FROM moz_historyvisits "
+        "WHERE visit_type NOT IN (0,4) "
+          "AND NOT EXISTS (SELECT id FROM moz_places h WHERE h.id = place_id AND hidden = 1) "
+          "AND NOT EXISTS (SELECT id FROM moz_places_temp h WHERE h.id = place_id AND hidden = 1) "
+        "ORDER by visit_date DESC LIMIT ") +
+        nsPrintfCString("%d ", aOptions->MaxResults()) +
+      NS_LITERAL_CSTRING(") "
+      "UNION ALL "
+      "SELECT * FROM ( "
+        "SELECT DISTINCT place_id "
+        "FROM moz_historyvisits_temp "
+        "WHERE visit_type NOT IN (0,4) "
+        "AND NOT EXISTS (SELECT id FROM moz_places h WHERE h.id = place_id AND hidden = 1) "
+        "AND NOT EXISTS (SELECT id FROM moz_places_temp h WHERE h.id = place_id AND hidden = 1) "
+        "ORDER by visit_date DESC LIMIT ") +
+        nsPrintfCString("%d ", aOptions->MaxResults()) +
+      NS_LITERAL_CSTRING(")");
+
     queryString = NS_LITERAL_CSTRING(
       "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
-        SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
-        ", f.url, null, null "
-      "FROM moz_places h "
-      "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
-      "WHERE h.id IN ( "
-        "SELECT DISTINCT p.id "
-        "FROM moz_places p "
-        "JOIN moz_historyvisits v ON v.place_id = p.id "
-        "WHERE p.hidden <> 1 AND v.visit_type NOT IN (0,4) "
-        "ORDER BY v.visit_date DESC "
+          SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
+          ", f.url, null, null "
+        "FROM moz_places_temp h "
+        "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
+        "WHERE h.id IN ( ") + sqlFragment + NS_LITERAL_CSTRING(") "
+      "UNION "
+      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+          SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
+          ", f.url, null, null "
+        "FROM moz_places h "
+        "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
+        "WHERE h.id IN ( ") + sqlFragment + NS_LITERAL_CSTRING(") "
+        "ORDER BY 6 DESC " // last visit date
         "LIMIT ");
     queryString.AppendInt(aOptions->MaxResults());
-    queryString += NS_LITERAL_CSTRING(") ORDER BY 6 DESC"); // v.visit_date
     return NS_OK;
   }
 
   // for the most visited menu query
   // we generate a super-optimized SQL query
   if (IsHistoryMenuQuery(aQueries, aOptions, 
         nsINavHistoryQueryOptions::SORT_BY_VISITCOUNT_DESCENDING)) {
     queryString = NS_LITERAL_CSTRING(
-      "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
-        SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
-        ", f.url, null, null "
-      "FROM moz_places h "
-      "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
-      "WHERE h.id IN ("
-        "SELECT p.id FROM moz_places p "
-        "WHERE p.hidden <> 1 AND visit_count > 0 "
-        "ORDER BY p.visit_count DESC LIMIT ");
+      "SELECT * FROM ( "
+        "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+          SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
+          ", f.url, null, null "
+        "FROM moz_places_temp h "
+        "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
+        "WHERE h.hidden <> 1 AND visit_count > 0 "
+        "ORDER BY h.visit_count DESC LIMIT ") +
+        nsPrintfCString("%d ", aOptions->MaxResults()) +
+      NS_LITERAL_CSTRING(") "
+      "UNION "
+      "SELECT * FROM ( "
+        "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
+          SQL_STR_FRAGMENT_MAX_VISIT_DATE( "h.id" )
+          ", f.url, null, null "
+        "FROM moz_places h "
+        "LEFT OUTER JOIN moz_favicons f ON h.favicon_id = f.id "
+        "WHERE h.hidden <> 1 AND visit_count > 0 "
+        "ORDER BY h.visit_count DESC LIMIT ") +
+        nsPrintfCString("%d ", aOptions->MaxResults()) +
+      NS_LITERAL_CSTRING(") "
+      "ORDER BY 5 DESC LIMIT "); // visit_count
     queryString.AppendInt(aOptions->MaxResults());
-    queryString += NS_LITERAL_CSTRING(") ORDER BY h.visit_count DESC");
+
     return NS_OK;
   }  
 
   nsCAutoString conditions;
 
   PRInt32 i;
   for (i = 0; i < aQueries.Count(); i ++) {
     nsCString queryClause;
@@ -3620,17 +4198,17 @@ nsNavHistory::GetQueryResults(nsNavHisto
   nsCString queryString;
   PRBool paramsPresent = PR_FALSE;
   nsNavHistory::StringHash addParams;
   addParams.Init(MAX_HISTORY_DAYS+1);
   nsresult rv = ConstructQueryString(aQueries, aOptions, queryString, 
                                      paramsPresent, addParams);
   NS_ENSURE_SUCCESS(rv,rv);
 
-#ifdef DEBUG_thunder
+#ifdef DEBUG_FRECENCY
   printf("Constructed the query: %s\n", PromiseFlatCString(queryString).get());
 #endif
 
   // Put this in a transaction. Even though we are only reading, this will
   // speed up the grouped queries to the annotation service for titles and
   // full text searching.
   mozStorageTransaction transaction(mDBConn, PR_FALSE);
 
@@ -3772,23 +4350,48 @@ nsNavHistory::AddPageWithDetails(nsIURI 
 //    the statement.
 
 NS_IMETHODIMP
 nsNavHistory::GetLastPageVisited(nsACString & aLastPageVisited)
 {
   NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
 
   nsCOMPtr<mozIStorageStatement> statement;
+  // We are not checking for duplicated ids into the unified table
+  // for perf reasons, LIMIT 1 will discard duplicates faster since we
+  // expect newest visits being in temp table.
   nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT h.url "
-      "FROM moz_places h LEFT OUTER JOIN moz_historyvisits v ON h.id = v.place_id "
-      "WHERE v.visit_date IN "
-      "(SELECT MAX(visit_date) "
-       "FROM moz_historyvisits v2 LEFT JOIN moz_places h2 ON v2.place_id = h2.id "
-        "WHERE h2.hidden != 1)"),
+      "SELECT * FROM ( "
+        "SELECT url, visit_date FROM moz_historyvisits_temp v "
+        "JOIN moz_places_temp h ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 "
+        "ORDER BY visit_date DESC LIMIT 1 "
+      ") "
+      "UNION ALL "
+      "SELECT * FROM ( "
+        "SELECT url, visit_date FROM moz_historyvisits_temp v "
+        "JOIN moz_places h ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 "
+        "ORDER BY visit_date DESC LIMIT 1 "
+      ") "
+      "UNION ALL "
+      "SELECT * FROM ( "
+        "SELECT url, visit_date FROM moz_historyvisits v "
+        "JOIN moz_places h ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 "
+        "ORDER BY visit_date DESC LIMIT 1 "
+      ") "
+      "UNION ALL "
+      "SELECT * FROM ( "
+        "SELECT url, visit_date FROM moz_historyvisits v "
+        "JOIN moz_places_temp h ON v.place_id = h.id "
+        "WHERE h.hidden <> 1 "
+        "ORDER BY visit_date DESC LIMIT 1 "
+      ") "
+      "ORDER BY 2 DESC LIMIT 1"), /* visit date */
     getter_AddRefs(statement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool hasMatch = PR_FALSE;
   if (NS_SUCCEEDED(statement->ExecuteStep(&hasMatch)) && hasMatch) {
     return statement->GetUTF8String(0, aLastPageVisited);
   }
   aLastPageVisited.Truncate(0);
@@ -3836,48 +4439,68 @@ nsNavHistory::RemovePagesInternal(const 
 
   // if a moz_place is annotated or was a bookmark,
   // we won't delete it, but we will delete the moz_visits
   // so we need to reset the frecency.  Note, we set frecency to
   // -visit_count, as we use that value in our "on idle" query
   // to figure out which places to recalculate frecency first.
   // Pay attention to not set frecency = 0 if visit_count = 0
   nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "UPDATE moz_places "
+      "UPDATE moz_places_view "
       "SET frecency = -MAX(visit_count, 1) "
-      "WHERE id IN(") +
-        aPlaceIdsQueryString +
-        NS_LITERAL_CSTRING(") AND ("
-          "EXISTS (SELECT b.id FROM moz_bookmarks b WHERE b.fk = moz_places.id) "
-          "OR EXISTS "
-            "(SELECT a.id FROM moz_annos a WHERE a.place_id = moz_places.id))"));
+      "WHERE id IN ( "
+        "SELECT h.id " 
+        "FROM moz_places_temp h "
+        "WHERE h.id IN ( ") + aPlaceIdsQueryString + NS_LITERAL_CSTRING(") "
+          "AND ( "
+            "EXISTS (SELECT b.id FROM moz_bookmarks b WHERE b.fk =h.id) "
+            "OR EXISTS (SELECT a.id FROM moz_annos a WHERE a.place_id = h.id) "
+          ") "
+        "UNION ALL "
+        "SELECT h.id " 
+        "FROM moz_places h "
+        "WHERE h.id IN ( ") + aPlaceIdsQueryString + NS_LITERAL_CSTRING(") "
+          "AND h.id NOT IN (SELECT id FROM moz_places_temp) "
+          "AND ( "
+            "EXISTS (SELECT b.id FROM moz_bookmarks b WHERE b.fk =h.id) "
+            "OR EXISTS (SELECT a.id FROM moz_annos a WHERE a.place_id = h.id) "
+          ") "        
+      ")"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // delete all visits
   rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "DELETE FROM moz_historyvisits WHERE place_id IN (") +
+      "DELETE FROM moz_historyvisits_view WHERE place_id IN (") +
         aPlaceIdsQueryString +
         NS_LITERAL_CSTRING(")"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // now that visits have been removed, run annotation expiration.
   // this will remove all expire-able annotations for these URIs.
   (void)mExpire.OnDeleteURI();
 
   // if the entry is not bookmarked and is not a place: uri
   // then we can remove it from moz_places.
   // Note that we do NOT delete favicons. Any unreferenced favicons will be
   // deleted next time the browser is shut down.
   rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "DELETE FROM moz_places WHERE id IN ("
-        "SELECT h.id FROM moz_places h WHERE h.id IN (") +
-        aPlaceIdsQueryString +
-        NS_LITERAL_CSTRING(") AND "
-        "NOT EXISTS (SELECT b.id FROM moz_bookmarks b WHERE b.fk = h.id LIMIT 1) "
-        "AND SUBSTR(h.url,0,6) <> 'place:')"));
+      "DELETE FROM moz_places_view WHERE id IN ("
+        "SELECT h.id FROM moz_places_temp h "
+        "WHERE h.id IN ( ") + aPlaceIdsQueryString + NS_LITERAL_CSTRING(") "
+          "AND SUBSTR(h.url, 0, 6) <> 'place:' "
+          "AND NOT EXISTS "
+            "(SELECT b.id FROM moz_bookmarks b WHERE b.fk = h.id LIMIT 1) "
+        "UNION ALL "
+        "SELECT h.id FROM moz_places h "
+        "WHERE h.id NOT IN (SELECT id FROM moz_places_temp) "
+          "AND h.id IN ( ") + aPlaceIdsQueryString + NS_LITERAL_CSTRING(") "
+          "AND SUBSTR(h.url, 0, 6) <> 'place:' "
+          "AND NOT EXISTS "
+            "(SELECT b.id FROM moz_bookmarks b WHERE b.fk = h.id LIMIT 1) "
+    ")"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // placeId could have a livemark item, so setting the frecency to -1
   // would cause it to show up in the url bar autocomplete
   // call FixInvalidFrecenciesForExcludedPlaces() to handle that scenario
   // XXX this might be dog slow, further degrading delete perf.
   rv = FixInvalidFrecenciesForExcludedPlaces();
   NS_ENSURE_SUCCESS(rv, rv);
@@ -3991,26 +4614,31 @@ nsNavHistory::RemovePagesFromHost(const 
   NS_ASSERTION(revHostDot[revHostDot.Length() - 1] == '.', "Invalid rev. host");
   nsAutoString revHostSlash(revHostDot);
   revHostSlash.Truncate(revHostSlash.Length() - 1);
   revHostSlash.Append(NS_LITERAL_STRING("/"));
 
   // build condition string based on host selection type
   nsCAutoString conditionString;
   if (aEntireDomain)
-    conditionString.AssignLiteral("h.rev_host >= ?1 AND h.rev_host < ?2 ");
+    conditionString.AssignLiteral("rev_host >= ?1 AND rev_host < ?2 ");
   else
-    conditionString.AssignLiteral("h.rev_host = ?1 ");
+    conditionString.AssignLiteral("rev_host = ?1 ");
 
   nsCOMPtr<mozIStorageStatement> statement;
 
   // create statement depending on delete type
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT h.id FROM moz_places h WHERE ") +
-      conditionString, getter_AddRefs(statement));
+      "SELECT id FROM moz_places_temp "
+      "WHERE ") + conditionString + NS_LITERAL_CSTRING(
+      "UNION ALL "
+      "SELECT id FROM moz_places "
+      "WHERE id NOT IN (SELECT id FROM moz_places_temp) "
+        "AND ") + conditionString,
+    getter_AddRefs(statement));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindStringParameter(0, revHostDot);
   NS_ENSURE_SUCCESS(rv, rv);
   if (aEntireDomain) {
     rv = statement->BindStringParameter(1, revHostSlash);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
@@ -4051,19 +4679,31 @@ nsNavHistory::RemovePagesByTimeframe(PRT
   nsresult rv;
   // build a list of place ids to delete
   nsCString deletePlaceIdsQueryString;
 
   // we only need to know if a place has a visit into the given timeframe
   // this query is faster than actually selecting in moz_historyvisits
   nsCOMPtr<mozIStorageStatement> selectByTime;
   rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT h.id FROM moz_places_temp h WHERE "
+        "EXISTS "
+          "(SELECT id FROM moz_historyvisits v WHERE v.place_id = h.id "
+            "AND v.visit_date >= ?1 AND v.visit_date <= ?2 LIMIT 1)"
+        "OR EXISTS "
+          "(SELECT id FROM moz_historyvisits_temp v WHERE v.place_id = h.id "
+            "AND v.visit_date >= ?1 AND v.visit_date <= ?2 LIMIT 1) "
+      "UNION "
       "SELECT h.id FROM moz_places h WHERE "
-      "EXISTS (SELECT id FROM moz_historyvisits v WHERE v.place_id = h.id "
-      " AND v.visit_date >= ?1 AND v.visit_date <= ?2 LIMIT 1)"),
+        "EXISTS "
+          "(SELECT id FROM moz_historyvisits v WHERE v.place_id = h.id "
+            "AND v.visit_date >= ?1 AND v.visit_date <= ?2 LIMIT 1)"
+        "OR EXISTS "
+          "(SELECT id FROM moz_historyvisits_temp v WHERE v.place_id = h.id "
+            "AND v.visit_date >= ?1 AND v.visit_date <= ?2 LIMIT 1)"),
     getter_AddRefs(selectByTime));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = selectByTime->BindInt64Parameter(0, aBeginTime);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = selectByTime->BindInt64Parameter(1, aEndTime);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRBool hasMore = PR_FALSE;
@@ -5084,18 +5724,18 @@ nsNavHistory::QueryToSelectClause(nsNavH
   if (hasIt) {
     clause.Condition("");
     if (aQuery->AnnotationIsNot())
       clause.Str("NOT");
     clause.Str(
       "EXISTS "
         "(SELECT h.id "
          "FROM moz_annos anno "
-              "JOIN moz_anno_attributes annoname "
-                "ON anno.anno_attribute_id = annoname.id "
+         "JOIN moz_anno_attributes annoname "
+           "ON anno.anno_attribute_id = annoname.id "
          "WHERE anno.place_id = h.id "
            "AND annoname.name = ").Param(":anno").Str(")");
     // annotation-based queries don't get the common conditions, so you get
     // all URLs with that annotation
   }
 
   // parent parameter is used in tag contents queries.
   // Only one folder should be defined for them.
@@ -5967,19 +6607,19 @@ nsNavHistory::SetPageTitleInternal(nsIUR
   // be. For example, going to any web page will always cause a title to be set,
   // even though it will often be unchanged since the last visit. In these
   // cases, we can avoid DB writing and (most significantly) observer overhead.
   if ((aTitle.IsVoid() && title.IsVoid()) || aTitle == title)
     return NS_OK;
 
   nsCOMPtr<mozIStorageStatement> dbModStatement;
   title = aTitle;
-  rv = mDBConn->CreateStatement(
-      NS_LITERAL_CSTRING("UPDATE moz_places SET title = ?1 WHERE url = ?2"),
-      getter_AddRefs(dbModStatement));
+  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_places_view SET title = ?1 WHERE url = ?2"),
+    getter_AddRefs(dbModStatement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // title
   if (aTitle.IsVoid())
     dbModStatement->BindNullParameter(0);
   else
     dbModStatement->BindStringParameter(0, StringHead(aTitle, HISTORY_TITLE_LENGTH_MAX));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -6037,67 +6677,68 @@ nsNavHistory::RemoveDuplicateURIs()
 {
   // this must be in a transaction because we do related queries
   mozStorageTransaction transaction(mDBConn, PR_FALSE);
 
   // this query chooses an id for every duplicate uris
   // this id will be retained while duplicates will be discarded
   // total_visit_count is the sum of all duplicate uris visit_count
   nsCOMPtr<mozIStorageStatement> selectStatement;
-  nsresult rv = mDBConn->CreateStatement(
-      NS_LITERAL_CSTRING("SELECT "
-        "(SELECT h.id FROM moz_places h WHERE h.url=url ORDER BY h.visit_count DESC LIMIT 1), "
+  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT "
+        "(SELECT h.id FROM moz_places_view h WHERE h.url = url "
+         "ORDER BY h.visit_count DESC LIMIT 1), "
         "url, SUM(visit_count) "
-        "FROM moz_places "
-        "GROUP BY url HAVING( COUNT(url) > 1)"),
-      getter_AddRefs(selectStatement));
+      "FROM moz_places_view "
+      "GROUP BY url HAVING( COUNT(url) > 1)"),
+    getter_AddRefs(selectStatement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // this query remaps history visits to the retained place_id
   nsCOMPtr<mozIStorageStatement> updateStatement;
-  rv = mDBConn->CreateStatement(
-      NS_LITERAL_CSTRING(
-        "UPDATE moz_historyvisits "
-        "SET place_id = ?1 "
-        "WHERE place_id IN (SELECT id FROM moz_places WHERE id <> ?1 AND url = ?2)"),
-      getter_AddRefs(updateStatement));
+  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_historyvisits_view "
+      "SET place_id = ?1 "
+      "WHERE place_id IN "
+        "(SELECT id FROM moz_places_view WHERE id <> ?1 AND url = ?2)"),
+    getter_AddRefs(updateStatement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // this query remaps bookmarks to the retained place_id
   nsCOMPtr<mozIStorageStatement> bookmarkStatement;
-  rv = mDBConn->CreateStatement(
-      NS_LITERAL_CSTRING(
-        "UPDATE moz_bookmarks "
-        "SET fk = ?1 "
-        "WHERE fk IN (SELECT id FROM moz_places WHERE id <> ?1 AND url = ?2)"),
-      getter_AddRefs(bookmarkStatement));
+  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_bookmarks "
+      "SET fk = ?1 "
+      "WHERE fk IN "
+        "(SELECT id FROM moz_places_view WHERE id <> ?1 AND url = ?2)"),
+    getter_AddRefs(bookmarkStatement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // this query remaps annotations to the retained place_id
   nsCOMPtr<mozIStorageStatement> annoStatement;
-  rv = mDBConn->CreateStatement(
-      NS_LITERAL_CSTRING(
-        "UPDATE moz_annos "
-        "SET place_id = ?1 "
-        "WHERE place_id IN (SELECT id FROM moz_places WHERE id <> ?1 AND url = ?2)"),
-      getter_AddRefs(annoStatement));
+  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_annos "
+      "SET place_id = ?1 "
+      "WHERE place_id IN "
+        "(SELECT id FROM moz_places_view WHERE id <> ?1 AND url = ?2)"),
+    getter_AddRefs(annoStatement));
   NS_ENSURE_SUCCESS(rv, rv);
   
   // this query deletes all duplicate uris except the choosen id
   nsCOMPtr<mozIStorageStatement> deleteStatement;
-  rv = mDBConn->CreateStatement(
-      NS_LITERAL_CSTRING("DELETE FROM moz_places WHERE url = ?1 AND id <> ?2"),
-      getter_AddRefs(deleteStatement));
+  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "DELETE FROM moz_places_view WHERE url = ?1 AND id <> ?2"),
+    getter_AddRefs(deleteStatement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // this query updates visit_count to the sum of all visits
   nsCOMPtr<mozIStorageStatement> countStatement;
-  rv = mDBConn->CreateStatement(
-      NS_LITERAL_CSTRING("UPDATE moz_places SET visit_count = ?1 WHERE id = ?2"),
-      getter_AddRefs(countStatement));
+  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_places_view SET visit_count = ?1 WHERE id = ?2"),
+    getter_AddRefs(countStatement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // for each duplicate uri we update historyvisit and visit_count
   PRBool hasMore;
   while (NS_SUCCEEDED(selectStatement->ExecuteStep(&hasMore)) && hasMore) {
     PRUint64 id = selectStatement->AsInt64(0);
     nsCAutoString url;
     rv = selectStatement->GetUTF8String(1, url);
--- a/toolkit/components/places/src/nsNavHistory.h
+++ b/toolkit/components/places/src/nsNavHistory.h
@@ -99,20 +99,25 @@
 #define QUERYUPDATE_SIMPLE 1
 #define QUERYUPDATE_COMPLEX 2
 #define QUERYUPDATE_COMPLEX_WITH_BOOKMARKS 3
 #define QUERYUPDATE_HOST 4
 
 // this is a work-around for a problem with the optimizer of sqlite
 // A sub-select on MAX(visit_date) is slower than this query with our indexes
 // see Bug #392399 for more details
-#define SQL_STR_FRAGMENT_MAX_VISIT_DATE( place_relation ) \
-  "(SELECT visit_date FROM moz_historyvisits WHERE place_id = " place_relation \
+#define SQL_STR_FRAGMENT_MAX_VISIT_DATE_BASE( __place_relation, __table_name ) \
+  "(SELECT visit_date FROM " __table_name \
+  " WHERE place_id = " __place_relation \
   " AND visit_type NOT IN (0,4,7) ORDER BY visit_date DESC LIMIT 1)"
 
+#define SQL_STR_FRAGMENT_MAX_VISIT_DATE( __place_relation ) \
+  "IFNULL( " SQL_STR_FRAGMENT_MAX_VISIT_DATE_BASE( __place_relation, "moz_historyvisits_temp") \
+          ", " SQL_STR_FRAGMENT_MAX_VISIT_DATE_BASE( __place_relation, "moz_historyvisits") ")"
+
 struct AutoCompleteIntermediateResult;
 class AutoCompleteResultComparator;
 class mozIAnnotationService;
 class nsNavHistory;
 class nsNavBookmarks;
 class QueryKeyValuePair;
 class nsIEffectiveTLDService;
 class nsIIDNService;
@@ -466,16 +471,17 @@ protected:
   nsresult InitTempTables();
   nsresult InitViews();
   nsresult InitFunctions();
   nsresult InitStatements();
   nsresult ForceMigrateBookmarksDB(mozIStorageConnection *aDBConn);
   nsresult MigrateV3Up(mozIStorageConnection *aDBConn);
   nsresult MigrateV6Up(mozIStorageConnection *aDBConn);
   nsresult MigrateV7Up(mozIStorageConnection *aDBConn);
+  nsresult MigrateV8Up(mozIStorageConnection *aDBConn);
   nsresult EnsureCurrentSchema(mozIStorageConnection* aDBConn, PRBool *aMadeChanges);
   nsresult CleanUpOnQuit();
 
   nsresult RemovePagesInternal(const nsCString& aPlaceIdsQueryString);
 
   nsresult AddURIInternal(nsIURI* aURI, PRTime aTime, PRBool aRedirect,
                           PRBool aToplevel, nsIURI* aReferrer);
 
--- a/toolkit/components/places/src/nsNavHistoryAutoComplete.cpp
+++ b/toolkit/components/places/src/nsNavHistoryAutoComplete.cpp
@@ -87,31 +87,40 @@
   "SELECT " column " " \
   "FROM moz_bookmarks b " \
   "JOIN moz_bookmarks t ON t.id = b.parent AND t.parent " comparison " ?1 " \
   "WHERE b.type = ") + nsPrintfCString("%d", \
     nsINavBookmarksService::TYPE_BOOKMARK) + \
     NS_LITERAL_CSTRING(" AND b.fk = h.id") + \
   (getMostRecent ? NS_LITERAL_CSTRING(" " \
     "ORDER BY b.lastModified DESC LIMIT 1") : EmptyCString()) + \
-  NS_LITERAL_CSTRING(") " name)
+  NS_LITERAL_CSTRING(") AS " name)
 
 // Get three named columns from the bookmarks and tags table
 #define BOOK_TAG_SQL (\
   SQL_STR_FRAGMENT_GET_BOOK_TAG("parent", "b.parent", "!=", PR_TRUE) + \
   SQL_STR_FRAGMENT_GET_BOOK_TAG("bookmark", "b.title", "!=", PR_TRUE) + \
   SQL_STR_FRAGMENT_GET_BOOK_TAG("tags", "GROUP_CONCAT(t.title, ',')", "=", PR_FALSE))
 
 // This separator is used as an RTL-friendly way to split the title and tags.
 // It can also be used by an nsIAutoCompleteResult consumer to re-split the
 // "comment" back into the title and tag.
 // Use a Unichar array to avoid problems with 2-byte char strings: " \u2013 "
 const PRUnichar kTitleTagsSeparatorChars[] = { ' ', 0x2013, ' ', 0 };
 #define TITLE_TAGS_SEPARATOR nsAutoString(kTitleTagsSeparatorChars)
 
+// This fragment is used to get best favicon for a rev_host
+#define BEST_FAVICON_FOR_REVHOST( __table_name ) \
+  "(SELECT f.url FROM " __table_name " " \
+   "JOIN moz_favicons f ON f.id = favicon_id " \
+   "WHERE rev_host = IFNULL( " \
+     "(SELECT rev_host FROM moz_places_temp WHERE id = b.fk), " \
+     "(SELECT rev_host FROM moz_places WHERE id = b.fk)) " \
+   "ORDER BY frecency DESC LIMIT 1) "
+
 ////////////////////////////////////////////////////////////////////////////////
 //// nsNavHistoryAutoComplete Helper Functions
 
 /**
  * Returns true if the string starts with javascript:
  */
 inline PRBool
 StartsWithJS(const nsAString &aString)
@@ -258,91 +267,133 @@ nsNavHistory::InitAutoComplete()
 //
 //    The auto complete queries we use depend on options, so we have them in
 //    a separate function so it can be re-created when the option changes.
 
 nsresult
 nsNavHistory::CreateAutoCompleteQueries()
 {
   // Define common pieces of various queries
-  nsCString sqlHead = NS_LITERAL_CSTRING(
-    "SELECT h.url, h.title, f.url") + BOOK_TAG_SQL + NS_LITERAL_CSTRING(", "
-      "h.visit_count "
-    "FROM moz_places h "
-    "LEFT OUTER JOIN moz_favicons f ON f.id = h.favicon_id "
-    "WHERE h.frecency <> 0 ");
-  // NOTE:
-  // after migration or clear all private data, we might end up with
-  // a lot of places with frecency < 0 (until idle)
-  //
   // XXX bug 412736
   // in the case of a frecency tie, break it with h.typed and h.visit_count
   // which is better than nothing.  but this is slow, so not doing it yet.
-  nsCString sqlTail = NS_LITERAL_CSTRING(
-    "ORDER BY h.frecency DESC LIMIT ?2 OFFSET ?3");
+
+  // Try to reduce size of compound table since with partitioning this became
+  // slower. Limiting moz_places with OFFSET+LIMIT will mostly help speed
+  // of first chunks, that are usually most wanted.
+  // Can do this only if there aren't additional conditions on final resultset.
+
+  // Note: h.frecency is selected because we need it for ordering, but will
+  // not be read later and we don't have an associated kAutoCompleteIndex_
 
-  nsresult rv = mDBConn->CreateStatement(sqlHead + (mAutoCompleteOnlyTyped ?
-      NS_LITERAL_CSTRING("AND h.typed = 1 ") : EmptyCString()) + sqlTail,
-    getter_AddRefs(mDBAutoCompleteQuery));
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCString sqlBase = NS_LITERAL_CSTRING(
+    "SELECT h.url, h.title, f.url") + BOOK_TAG_SQL + NS_LITERAL_CSTRING(", "
+      "h.visit_count, h.frecency "
+    "FROM moz_places_temp h "
+    "LEFT OUTER JOIN moz_favicons f ON f.id = h.favicon_id "
+    "WHERE h.frecency <> 0 "
+    "{ADDITIONAL_CONDITIONS} "
+    "UNION ALL "
+    "SELECT * FROM ( "
+      "SELECT h.url, h.title, f.url") + BOOK_TAG_SQL + NS_LITERAL_CSTRING(", "
+        "h.visit_count, h.frecency "
+      "FROM moz_places h "
+      "LEFT OUTER JOIN moz_favicons f ON f.id = h.favicon_id "
+      "WHERE h.id NOT IN (SELECT id FROM moz_places_temp) "
+      "AND h.frecency <> 0 "
+      "{ADDITIONAL_CONDITIONS} "
+      "ORDER BY h.frecency DESC LIMIT (?2 + ?3) "
+    ") "
+    "ORDER BY 8 DESC LIMIT ?2 OFFSET ?3"); // ORDER BY frecency
 
-  rv = mDBConn->CreateStatement(sqlHead +
-      NS_LITERAL_CSTRING("AND h.visit_count > 0 ") + sqlTail,
-    getter_AddRefs(mDBAutoCompleteHistoryQuery));
+  nsCString AutoCompleteQuery = sqlBase;
+  AutoCompleteQuery.ReplaceSubstring("{ADDITIONAL_CONDITIONS}",
+                                     (mAutoCompleteOnlyTyped ?
+                                        "AND h.typed = 1" : ""));
+  nsresult rv = mDBConn->CreateStatement(AutoCompleteQuery,
+                                getter_AddRefs(mDBAutoCompleteQuery));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = mDBConn->CreateStatement(sqlHead +
-      NS_LITERAL_CSTRING("AND bookmark IS NOT NULL ") + sqlTail,
-    getter_AddRefs(mDBAutoCompleteStarQuery));
+  nsCString AutoCompleteHistoryQuery = sqlBase;
+  AutoCompleteHistoryQuery.ReplaceSubstring("{ADDITIONAL_CONDITIONS}",
+                                            "AND h.visit_count > 0");
+  rv = mDBConn->CreateStatement(AutoCompleteHistoryQuery,
+                                getter_AddRefs(mDBAutoCompleteHistoryQuery));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = mDBConn->CreateStatement(sqlHead +
-      NS_LITERAL_CSTRING("AND tags IS NOT NULL ") + sqlTail,
-    getter_AddRefs(mDBAutoCompleteTagsQuery));
+  nsCString AutoCompleteStarQuery = sqlBase;
+  AutoCompleteStarQuery.ReplaceSubstring("{ADDITIONAL_CONDITIONS}",
+                                         "AND bookmark IS NOT NULL");
+  rv = mDBConn->CreateStatement(AutoCompleteStarQuery,
+                                getter_AddRefs(mDBAutoCompleteStarQuery));
   NS_ENSURE_SUCCESS(rv, rv);
 
+  nsCString AutoCompleteTagsQuery = sqlBase;
+  AutoCompleteTagsQuery.ReplaceSubstring("{ADDITIONAL_CONDITIONS}",
+                                         "AND tags IS NOT NULL");
+  rv = mDBConn->CreateStatement(AutoCompleteTagsQuery,
+                                getter_AddRefs(mDBAutoCompleteTagsQuery));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // In this query we are taking BOOK_TAG_SQL only for h.id because it
+  // uses data from moz_bookmarks table and we sync tables on bookmark insert.
+  // So, most likely, h.id will always be populated when we have any bookmark.
+  // We still need to join on moz_places_temp for other data (eg. title).
   nsCString sql = NS_LITERAL_CSTRING(
-    "SELECT h.url, h.title, f.url") + BOOK_TAG_SQL + NS_LITERAL_CSTRING(", "
-      "h.visit_count, "
-      "ROUND(MAX(((i.input = ?2) + (SUBSTR(i.input, 1, LENGTH(?2)) = ?2)) * "
-                "i.use_count), 1) rank "
-    "FROM moz_inputhistory i "
-    "JOIN moz_places h ON h.id = i.place_id "
-    "LEFT OUTER JOIN moz_favicons f ON f.id = h.favicon_id "
-    "GROUP BY i.place_id HAVING rank > 0 "
-    "ORDER BY rank DESC, h.frecency DESC");
+    "SELECT IFNULL(h_t.url, h.url), IFNULL(h_t.title, h.title), f.url ") +
+      BOOK_TAG_SQL + NS_LITERAL_CSTRING(", "
+      "IFNULL(h_t.visit_count, h.visit_count), rank "
+    "FROM ( "
+      "SELECT ROUND(MAX(((i.input = ?2) + (SUBSTR(i.input, 1, LENGTH(?2)) = ?2)) * "
+        "i.use_count), 1) AS rank, place_id "
+      "FROM moz_inputhistory i "
+      "GROUP BY i.place_id HAVING rank > 0 "
+      ") AS i "
+    "LEFT JOIN moz_places h ON h.id = i.place_id "
+    "LEFT JOIN moz_places_temp h_t ON h_t.id = i.place_id "
+    "LEFT JOIN moz_favicons f ON f.id = IFNULL(h_t.favicon_id, h.favicon_id) "
+    "WHERE IFNULL(h_t.url, h.url) NOTNULL "
+    "ORDER BY rank DESC, IFNULL(h_t.frecency, h.frecency) DESC");
   rv = mDBConn->CreateStatement(sql, getter_AddRefs(mDBAdaptiveQuery));
   NS_ENSURE_SUCCESS(rv, rv);
 
   sql = NS_LITERAL_CSTRING(
-    "SELECT REPLACE(s.url, '%s', ?2) search_url, h.title, IFNULL(f.url, "
-      "(SELECT f.url "
-       "FROM moz_places r "
-       "JOIN moz_favicons f ON f.id = r.favicon_id "
-       "WHERE r.rev_host = s.rev_host "
-       "ORDER BY r.frecency DESC LIMIT 1)), "
-      "b.parent, b.title, NULL, h.visit_count "
+    "SELECT IFNULL( "
+        "(SELECT REPLACE(url, '%s', ?2) FROM moz_places_temp WHERE id = b.fk), "
+        "(SELECT REPLACE(url, '%s', ?2) FROM moz_places WHERE id = b.fk) "
+      ") AS search_url, IFNULL(h_t.title, h.title), "
+      "COALESCE(f.url, "
+        BEST_FAVICON_FOR_REVHOST("moz_places_temp") ", "
+        BEST_FAVICON_FOR_REVHOST("moz_places")
+      "), "
+      "b.parent, b.title, NULL, IFNULL(h_t.visit_count, h.visit_count) "
     "FROM moz_keywords k "
     "JOIN moz_bookmarks b ON b.keyword_id = k.id "
-    "JOIN moz_places s ON s.id = b.fk "
-    "LEFT OUTER JOIN moz_places h ON h.url = search_url "
-    "LEFT OUTER JOIN moz_favicons f ON f.id = h.favicon_id "
+    "LEFT JOIN moz_places AS h ON h.url = search_url "
+    "LEFT JOIN moz_places_temp AS h_t ON h_t.url = search_url "
+    "LEFT JOIN moz_favicons f ON f.id = IFNULL(h_t.favicon_id, h.favicon_id) "
     "WHERE LOWER(k.keyword) = LOWER(?1) "
-    "ORDER BY h.frecency DESC");
+    "ORDER BY IFNULL(h_t.frecency, h.frecency) DESC");
   rv = mDBConn->CreateStatement(sql, getter_AddRefs(mDBKeywordQuery));
   NS_ENSURE_SUCCESS(rv, rv);
 
   sql = NS_LITERAL_CSTRING(
     // Leverage the PRIMARY KEY (place_id, input) to insert/update entries
     "INSERT OR REPLACE INTO moz_inputhistory "
-    // use_count will asymptotically approach the max of 10
-    "SELECT h.id, IFNULL(i.input, ?1), IFNULL(i.use_count, 0) * .9 + 1 "
-    "FROM moz_places h "
-    "LEFT OUTER JOIN moz_inputhistory i ON i.place_id = h.id AND i.input = ?1 "
-    "WHERE h.url = ?2");
+      // use_count will asymptotically approach the max of 10    
+      "SELECT h.id, IFNULL(i.input, ?1), IFNULL(i.use_count, 0) * .9 + 1 "
+      "FROM moz_places_temp h "
+      "LEFT JOIN moz_inputhistory i ON i.place_id = h.id AND i.input = ?1 "
+      "WHERE url = ?2 "
+      "UNION ALL "
+      "SELECT h.id, IFNULL(i.input, ?1), IFNULL(i.use_count, 0) * .9 + 1 "
+      "FROM moz_places h "
+      "LEFT JOIN moz_inputhistory i ON i.place_id = h.id AND i.input = ?1 "
+      "WHERE url = ?2 "
+        "AND h.id NOT IN (SELECT id FROM moz_places_temp)");
   rv = mDBConn->CreateStatement(sql, getter_AddRefs(mDBFeedbackIncrease));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 // nsNavHistory::StartAutoCompleteTimer
 
@@ -532,33 +583,40 @@ nsNavHistory::StartSearch(const nsAStrin
       DoneSearching(PR_TRUE);
 
       return NS_OK;
     } else {
       // We either have a previous in-progress search or a finished search that
       // has more than 0 results. We can continue from where the previous
       // search left off, but first we want to create an optimized query that
       // only searches through the urls that were previously found
+
+      // We have to do the bindings for both tables, so we build a temporary
+      // string
+      nsCString bindings;
+      for (PRUint32 i = 0; i < prevMatchCount; i++) {
+        if (i)
+          bindings += NS_LITERAL_CSTRING(",");
+
+        // +2 to skip over the ?1 for the tag root parameter
+        bindings += nsPrintfCString("?%d", i + 2);
+      }
+
       nsCString sql = NS_LITERAL_CSTRING(
         "SELECT h.url, h.title, f.url") + BOOK_TAG_SQL + NS_LITERAL_CSTRING(", "
           "h.visit_count "
-        "FROM moz_places h "
+        "FROM ( "
+          "SELECT * FROM moz_places_temp "
+          "WHERE url IN (") + bindings + NS_LITERAL_CSTRING(") "
+          "UNION ALL "
+          "SELECT * FROM moz_places "
+          "WHERE id NOT IN (SELECT id FROM moz_places_temp) "
+          "AND url IN (") + bindings + NS_LITERAL_CSTRING(") "
+        ") AS h "
         "LEFT OUTER JOIN moz_favicons f ON f.id = h.favicon_id "
-        "WHERE h.url IN (");
-
-      // Put in bind spots for the urls
-      for (PRUint32 i = 0; i < prevMatchCount; i++) {
-        if (i)
-          sql += NS_LITERAL_CSTRING(",");
-
-        // +2 to skip over the ?1 for the tag root parameter
-        sql += nsPrintfCString("?%d", i + 2);
-      }
-
-      sql += NS_LITERAL_CSTRING(") "
         "ORDER BY h.frecency DESC");
 
       rv = mDBConn->CreateStatement(sql, getter_AddRefs(mDBPreviousQuery));
       NS_ENSURE_SUCCESS(rv, rv);
 
       // Collect the previous result's URLs that we want to process
       nsStringArray urls;
       (void)mCurrentResultURLs.EnumerateRead(HashedURLsToArray, &urls);
--- a/toolkit/components/places/src/nsNavHistoryExpire.cpp
+++ b/toolkit/components/places/src/nsNavHistoryExpire.cpp
@@ -247,30 +247,39 @@ nsNavHistoryExpire::ClearHistory()
 
   mozStorageTransaction transaction(connection, PR_FALSE);
 
   // reset frecency for all items that will _not_ be deleted
   // Note, we set frecency to -visit_count since we use that value in our
   // idle query to figure out which places to recalcuate frecency first.
   // We must do this before deleting visits
   nsresult rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "UPDATE moz_places SET frecency = -MAX(visit_count, 1) "
+    "UPDATE moz_places_view SET frecency = -MAX(visit_count, 1) "
     "WHERE id IN("
-      "SELECT h.id FROM moz_places h WHERE "
+      "SELECT h.id FROM moz_places_temp h "
+      "WHERE "
         "EXISTS (SELECT id FROM moz_bookmarks WHERE fk = h.id) "
         "OR EXISTS "
-        "(SELECT id FROM moz_annos WHERE place_id = h.id AND expiration = ") +
-      nsPrintfCString("%d", nsIAnnotationService::EXPIRE_NEVER) +
-      NS_LITERAL_CSTRING(")"));
-  if (NS_FAILED(rv))
-    NS_WARNING("failed to recent frecency");
+          "(SELECT id FROM moz_annos WHERE place_id = h.id AND expiration = ") +
+          nsPrintfCString("%d", nsIAnnotationService::EXPIRE_NEVER) +
+          NS_LITERAL_CSTRING(") "
+      "UNION ALL "
+      "SELECT h.id FROM moz_places h "
+      "WHERE "
+        "EXISTS (SELECT id FROM moz_bookmarks WHERE fk = h.id) "
+        "OR EXISTS "
+          "(SELECT id FROM moz_annos WHERE place_id = h.id AND expiration = ") +
+          nsPrintfCString("%d", nsIAnnotationService::EXPIRE_NEVER) +
+          NS_LITERAL_CSTRING(") "
+    ")"));
+  NS_ENSURE_SUCCESS(rv, rv);
 
   // expire visits, then let the paranoid functions do the cleanup for us
   rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "DELETE FROM moz_historyvisits"));
+      "DELETE FROM moz_historyvisits_view"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = ExpireHistoryParanoid(connection, -1);
   if (NS_FAILED(rv))
     NS_WARNING("ExpireHistoryParanoid failed.");
 
   rv = ExpireFaviconsParanoid(connection);
   if (NS_FAILED(rv))
@@ -466,21 +475,48 @@ nsNavHistoryExpireRecord::nsNavHistoryEx
 nsresult
 nsNavHistoryExpire::FindVisits(PRTime aExpireThreshold, PRUint32 aNumToExpire,
                                mozIStorageConnection* aConnection,
                                nsTArray<nsNavHistoryExpireRecord>& aRecords)
 {
   // Select a limited number of visits older than a time
   nsCOMPtr<mozIStorageStatement> selectStatement;
   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT v.id, v.place_id, v.visit_date, h.url, h.favicon_id, h.hidden, "
-        "(SELECT fk FROM moz_bookmarks WHERE fk = h.id) "
-      "FROM moz_places h JOIN moz_historyvisits v ON h.id = v.place_id "
-      "WHERE v.visit_date < ?1 "
-      "ORDER BY v.visit_date ASC LIMIT ?2"),
+      "SELECT * FROM ( "
+        "SELECT v.id, v.place_id, v.visit_date, h.url, h.favicon_id, h.hidden, "
+          "(SELECT fk FROM moz_bookmarks WHERE fk = h.id) "
+        "FROM moz_places h "
+        "JOIN moz_historyvisits AS v ON h.id = v.place_id "
+        "WHERE visit_date < ?1 "      
+        "ORDER BY v.visit_date ASC LIMIT ?2 "
+      ") UNION ALL "
+        "SELECT * FROM ( "
+        "SELECT v.id, v.place_id, v.visit_date, h.url, h.favicon_id, h.hidden, "
+          "(SELECT fk FROM moz_bookmarks WHERE fk = h.id)"
+        "FROM moz_places_temp h "
+        "JOIN moz_historyvisits AS v ON h.id = v.place_id "
+        "WHERE visit_date < ?1 "
+        "ORDER BY v.visit_date ASC LIMIT ?2 "
+      ") UNION ALL "
+      "SELECT * FROM ( "
+        "SELECT v.id, v.place_id, v.visit_date, h.url, h.favicon_id, h.hidden, "
+          "(SELECT fk FROM moz_bookmarks WHERE fk = h.id) "
+        "FROM moz_places h "
+        "JOIN moz_historyvisits_temp AS v ON h.id = v.place_id "
+        "WHERE visit_date < ?1 "
+        "ORDER BY v.visit_date ASC LIMIT ?2 "
+      ") UNION ALL "
+      "SELECT * FROM ( "
+        "SELECT v.id, v.place_id, v.visit_date, h.url, h.favicon_id, h.hidden, "
+          "(SELECT fk FROM moz_bookmarks WHERE fk = h.id) "
+        "FROM moz_places_temp h "
+        "JOIN moz_historyvisits_temp AS v ON h.id = v.place_id "
+        "WHERE visit_date < ?1 "
+        "ORDER BY v.visit_date ASC LIMIT ?2 "
+      ") GROUP BY 1 ORDER BY 3 ASC LIMIT ?2"),
     getter_AddRefs(selectStatement));
     NS_ENSURE_SUCCESS(rv, rv);
 
   // browser.history_expire_days || match all visits
   PRTime expireMaxTime = aExpireThreshold ? aExpireThreshold : LL_MAXINT;
   rv = selectStatement->BindInt64Parameter(0, expireMaxTime);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -496,17 +532,21 @@ nsNavHistoryExpire::FindVisits(PRTime aE
   }
 
   // If we have found less than aNumToExpire over-max-age records, and we are
   // over the unique urls cap, select records older than the min-age cap .
   if (aRecords.Length() < aNumToExpire) {
     // check the number of visited unique urls in the db.
     nsCOMPtr<mozIStorageStatement> countStatement;
     rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
-        "SELECT count(*) FROM moz_places WHERE visit_count > 0"),
+        "SELECT "
+          "(SELECT count(*) FROM moz_places_temp WHERE visit_count > 0) + "
+          "(SELECT count(*) FROM moz_places WHERE visit_count > 0) - "
+          "(SELECT count(*) FROM moz_places WHERE id IN "
+            "(SELECT id FROM moz_places_temp))"),
       getter_AddRefs(countStatement));
     NS_ENSURE_SUCCESS(rv, rv);
 
     hasMore = PR_FALSE;
     // initialize to mExpiresites to avoid expiring if something goes wrong
     PRInt32 pageCount = mHistory->mExpireSites;
     if (NS_SUCCEEDED(countStatement->ExecuteStep(&hasMore)) && hasMore) {
       rv = countStatement->GetInt32(0, &pageCount);
@@ -571,33 +611,54 @@ nsNavHistoryExpire::EraseVisits(mozIStor
   if (deletedVisitIds.IsEmpty())
     return NS_OK;
 
   // Reset the frecencies for the places that won't have any visits after
   // we delete them and make sure they aren't bookmarked either. This means we
   // keep the old frecencies when possible as an estimate for the new frecency
   // unless we know it has to be invalidated.
   // We must do this before deleting visits
-  nsresult rv = aConnection->ExecuteSimpleSQL(
-    NS_LITERAL_CSTRING(
-      "UPDATE moz_places "
-      "SET frecency = -MAX(visit_count, 1) "
-      "WHERE id IN ("
-        "SELECT h.id FROM moz_places h "
-        "WHERE NOT EXISTS (SELECT b.id FROM moz_bookmarks b WHERE b.fk = h.id) "
-          "AND NOT EXISTS "
-            "(SELECT v.id FROM moz_historyvisits v WHERE v.place_id = h.id AND "
-              "v.id NOT IN (") + deletedVisitIds +
-              NS_LITERAL_CSTRING(")) AND "
-              "h.id IN (") + placeIds +
-    NS_LITERAL_CSTRING("))"));
+  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "UPDATE moz_places_view "
+    "SET frecency = -MAX(visit_count, 1) "
+    "WHERE id IN ( "
+      "SELECT h.id FROM moz_places_temp h "
+      "WHERE "
+        "NOT EXISTS (SELECT id FROM moz_bookmarks WHERE fk = h.id) AND "
+        "NOT EXISTS ( "
+          "SELECT v.id FROM moz_historyvisits_temp v "
+          "WHERE v.place_id = h.id "
+          "AND v.id NOT IN (") + deletedVisitIds + NS_LITERAL_CSTRING(") "
+        ") AND "
+        "NOT EXISTS ( "
+          "SELECT v.id FROM moz_historyvisits v "
+          "WHERE v.place_id = h.id "
+          "AND v.id NOT IN (") + deletedVisitIds + NS_LITERAL_CSTRING(") "
+        ") AND "
+        "h.id IN (") + placeIds + NS_LITERAL_CSTRING(") "
+      "UNION ALL "
+      "SELECT h.id FROM moz_places h "
+      "WHERE "
+        "NOT EXISTS (SELECT id FROM moz_bookmarks WHERE fk = h.id) AND "
+        "NOT EXISTS ( "
+          "SELECT v.id FROM moz_historyvisits_temp v "
+          "WHERE v.place_id = h.id "
+          "AND v.id NOT IN (") + deletedVisitIds + NS_LITERAL_CSTRING(") "
+        ") AND "
+        "NOT EXISTS ( "
+          "SELECT v.id FROM moz_historyvisits v "
+          "WHERE v.place_id = h.id "
+          "AND v.id NOT IN (") + deletedVisitIds + NS_LITERAL_CSTRING(") "
+        ") AND "
+        "h.id IN (") + placeIds + NS_LITERAL_CSTRING(") "
+    ")"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aConnection->ExecuteSimpleSQL(
-    NS_LITERAL_CSTRING("DELETE FROM moz_historyvisits WHERE id IN (") +
+    NS_LITERAL_CSTRING("DELETE FROM moz_historyvisits_view WHERE id IN (") +
     deletedVisitIds +
     NS_LITERAL_CSTRING(")"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 
@@ -631,27 +692,43 @@ nsNavHistoryExpire::EraseHistory(mozISto
       deletedPlaceIds.AppendInt(aRecords[i].placeID);
     }
     aRecords[i].erased = PR_TRUE;
   }
 
   if (deletedPlaceIds.IsEmpty())
     return NS_OK;
 
-  return aConnection->ExecuteSimpleSQL(
-    NS_LITERAL_CSTRING("DELETE FROM moz_places WHERE id IN( "
-      "SELECT h.id "
-      "FROM moz_places h "
-      "WHERE h.id IN(") +
-        deletedPlaceIds +
-        NS_LITERAL_CSTRING(") AND NOT EXISTS "
-          "(SELECT id FROM moz_historyvisits WHERE place_id = h.id LIMIT 1) "
+  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DELETE FROM moz_places_view WHERE id IN( "
+        "SELECT h.id "
+        "FROM moz_places h "
+        "WHERE h.id IN(") + deletedPlaceIds + NS_LITERAL_CSTRING(") "
+          "AND NOT EXISTS "
+            "(SELECT id FROM moz_historyvisits WHERE place_id = h.id LIMIT 1) "
+          "AND NOT EXISTS "
+            "(SELECT id FROM moz_historyvisits_temp WHERE place_id = h.id LIMIT 1) "
           "AND NOT EXISTS "
-          "(SELECT id FROM moz_bookmarks WHERE fk = h.id LIMIT 1) "
-          "AND SUBSTR(h.url,0,6) <> 'place:')"));
+            "(SELECT id FROM moz_bookmarks WHERE fk = h.id LIMIT 1) "
+          "AND SUBSTR(h.url,0,6) <> 'place:' "
+        "UNION ALL "
+        "SELECT h.id "
+        "FROM moz_places_temp h "
+        "WHERE h.id IN(") + deletedPlaceIds + NS_LITERAL_CSTRING(") "
+          "AND NOT EXISTS "
+            "(SELECT id FROM moz_historyvisits WHERE place_id = h.id LIMIT 1) "
+          "AND NOT EXISTS "
+            "(SELECT id FROM moz_historyvisits_temp WHERE place_id = h.id LIMIT 1) "
+          "AND NOT EXISTS "
+            "(SELECT id FROM moz_bookmarks WHERE fk = h.id LIMIT 1) "
+          "AND SUBSTR(h.url,0,6) <> 'place:' "
+      ")"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
 }
 
 
 // nsNavHistoryExpire::EraseFavicons
 
 nsresult
 nsNavHistoryExpire::EraseFavicons(mozIStorageConnection* aConnection,
     const nsTArray<nsNavHistoryExpireRecord>& aRecords)
@@ -671,23 +748,29 @@ nsNavHistoryExpire::EraseFavicons(mozISt
       deletedFaviconIdsArray.AppendElement(aRecords[i].faviconID);
       deletedFaviconIds.AppendInt(aRecords[i].faviconID);
     }
   }
 
   if (deletedFaviconIds.IsEmpty())
     return NS_OK;
 
-  // delete only if id is not referenced in moz_places
-  return aConnection->ExecuteSimpleSQL(
-    NS_LITERAL_CSTRING("DELETE FROM moz_favicons WHERE id IN ( "
-      "SELECT f.id FROM moz_favicons f "
-      "LEFT OUTER JOIN moz_places h ON f.id = h.favicon_id "
-      "WHERE f.id IN (") + deletedFaviconIds +
-      NS_LITERAL_CSTRING(") AND h.favicon_id IS NULL)"));
+  // delete only if favicon id is not referenced
+  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DELETE FROM moz_favicons WHERE id IN ( "
+        "SELECT f.id FROM moz_favicons f "
+        "LEFT JOIN moz_places h ON f.id = h.favicon_id "
+        "LEFT JOIN moz_places_temp h_t ON f.id = h_t.favicon_id "
+        "WHERE f.id IN (") + deletedFaviconIds + NS_LITERAL_CSTRING(") "
+        "AND h.favicon_id IS NULL "
+        "AND h_t.favicon_id IS NULL "
+      ")"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
 }
 
 
 // nsNavHistoryExpire::EraseAnnotations
 
 nsresult
 nsNavHistoryExpire::EraseAnnotations(mozIStorageConnection* aConnection,
     const nsTArray<nsNavHistoryExpireRecord>& aRecords)
@@ -730,22 +813,26 @@ nsNavHistoryExpire::ExpireAnnotations(mo
 {
   mozStorageTransaction transaction(aConnection, PR_FALSE);
 
   // Note: The COALESCE is used to cover a short period where NULLs were inserted
   // into the lastModified column.
   PRTime now = PR_Now();
   nsCOMPtr<mozIStorageStatement> expirePagesStatement;
   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
-      "DELETE FROM moz_annos WHERE expiration = ?1 AND (?2 > MAX(COALESCE(lastModified, 0), dateAdded))"),
+      "DELETE FROM moz_annos "
+      "WHERE expiration = ?1 AND "
+        "(?2 > MAX(COALESCE(lastModified, 0), dateAdded))"),
     getter_AddRefs(expirePagesStatement));
   NS_ENSURE_SUCCESS(rv, rv);
   nsCOMPtr<mozIStorageStatement> expireItemsStatement;
   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
-      "DELETE FROM moz_items_annos WHERE expiration = ?1 AND (?2 > MAX(COALESCE(lastModified, 0), dateAdded))"),
+      "DELETE FROM moz_items_annos "
+      "WHERE expiration = ?1 AND "
+        "(?2 > MAX(COALESCE(lastModified, 0), dateAdded))"),
     getter_AddRefs(expireItemsStatement));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // remove days annos
   rv = expirePagesStatement->BindInt32Parameter(0, nsIAnnotationService::EXPIRE_DAYS);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = expirePagesStatement->BindInt64Parameter(1, (now - EXPIRATION_POLICY_DAYS));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -792,16 +879,19 @@ nsNavHistoryExpire::ExpireAnnotations(mo
   rv = expireItemsStatement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // remove EXPIRE_WITH_HISTORY annos for pages without visits
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
       "DELETE FROM moz_annos WHERE expiration = ") +
         nsPrintfCString("%d", nsIAnnotationService::EXPIRE_WITH_HISTORY) +
         NS_LITERAL_CSTRING(" AND NOT EXISTS "
+          "(SELECT id FROM moz_historyvisits_temp "
+          "WHERE place_id = moz_annos.place_id LIMIT 1) "
+        "AND NOT EXISTS "
           "(SELECT id FROM moz_historyvisits "
           "WHERE place_id = moz_annos.place_id LIMIT 1)"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
@@ -812,26 +902,41 @@ nsNavHistoryExpire::ExpireAnnotations(mo
 
 nsresult
 nsNavHistoryExpire::ExpireEmbeddedLinks(mozIStorageConnection* aConnection)
 {
   PRTime maxEmbeddedAge = PR_Now() - EMBEDDED_LINK_LIFETIME;
   nsCOMPtr<mozIStorageStatement> expireEmbeddedLinksStatement;
   // Note: This query also removes visit_type = 0 entries, for bug #375777.
   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
-    "DELETE FROM moz_historyvisits WHERE id IN ("
-      "SELECT id FROM moz_historyvisits WHERE visit_date < ?1 "
-      "AND (visit_type = ?2 OR visit_type = 0) LIMIT ?3)"),
+      "DELETE FROM moz_historyvisits_view WHERE id IN ("
+        "SELECT * FROM ( "
+          "SELECT id FROM moz_historyvisits_temp "
+          "WHERE visit_date < ?1 "
+          "AND visit_type IN (") +
+            nsPrintfCString("%d", nsINavHistoryService::TRANSITION_EMBED) +
+            NS_LITERAL_CSTRING(", 0) "
+          "LIMIT ?2 "
+        ") "
+        "UNION ALL "
+        "SELECT * FROM ( "
+          "SELECT id FROM moz_historyvisits "
+          "WHERE visit_date < ?1 "
+          "AND visit_type IN (") +
+            nsPrintfCString("%d", nsINavHistoryService::TRANSITION_EMBED) +
+            NS_LITERAL_CSTRING(", 0) "
+          "LIMIT ?2 "
+        ") "
+        "LIMIT ?2 "
+      ")"),
     getter_AddRefs(expireEmbeddedLinksStatement));
   NS_ENSURE_SUCCESS(rv, rv);
   rv = expireEmbeddedLinksStatement->BindInt64Parameter(0, maxEmbeddedAge);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = expireEmbeddedLinksStatement->BindInt32Parameter(1, nsINavHistoryService::TRANSITION_EMBED);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = expireEmbeddedLinksStatement->BindInt32Parameter(2, EXPIRATION_CAP_EMBEDDED);
+  rv = expireEmbeddedLinksStatement->BindInt32Parameter(1, EXPIRATION_CAP_EMBEDDED);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = expireEmbeddedLinksStatement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 
 // nsNavHistoryExpire::ExpireHistoryParanoid
@@ -842,21 +947,34 @@ nsNavHistoryExpire::ExpireEmbeddedLinks(
 //    The aMaxRecords parameter is an optional cap on the number of 
 //    records to delete. If its value is -1, all records will be deleted.
 
 nsresult
 nsNavHistoryExpire::ExpireHistoryParanoid(mozIStorageConnection* aConnection,
                                           PRInt32 aMaxRecords)
 {
   nsCAutoString query(
-    "DELETE FROM moz_places WHERE id IN ("
+    "DELETE FROM moz_places_view WHERE id IN ("
       "SELECT h.id FROM moz_places h "
-        "LEFT OUTER JOIN moz_historyvisits v ON h.id = v.place_id "
-        "LEFT OUTER JOIN moz_bookmarks b ON h.id = b.fk "
-      "WHERE v.id IS NULL AND b.id IS NULL AND SUBSTR(h.url,0,6) <> 'place:'");
+      "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
+      "LEFT JOIN moz_historyvisits_temp v_t ON h.id = v_t.place_id "
+      "LEFT JOIN moz_bookmarks b ON h.id = b.fk "
+      "WHERE v.id IS NULL "
+        "AND v_t.id IS NULL "
+        "AND b.id IS NULL "
+        "AND SUBSTR(h.url,0,6) <> 'place:' "
+      "UNION ALL "
+      "SELECT h.id FROM moz_places_temp h "
+      "LEFT JOIN moz_historyvisits v ON h.id = v.place_id "
+      "LEFT JOIN moz_historyvisits_temp v_t ON h.id = v_t.place_id "
+      "LEFT JOIN moz_bookmarks b ON h.id = b.fk "
+      "WHERE v.id IS NULL "
+        "AND v_t.id IS NULL "
+        "AND b.id IS NULL "
+        "AND SUBSTR(h.url,0,6) <> 'place:'");
   if (aMaxRecords != -1) {
     query.AppendLiteral(" LIMIT ");
     query.AppendInt(aMaxRecords);
   }
   query.AppendLiteral(")");
   nsresult rv = aConnection->ExecuteSimpleSQL(query);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
@@ -866,20 +984,23 @@ nsNavHistoryExpire::ExpireHistoryParanoi
 // nsNavHistoryExpire::ExpireFaviconsParanoid
 //
 //    Deletes any dangling favicons that aren't associated with any pages.
 
 nsresult
 nsNavHistoryExpire::ExpireFaviconsParanoid(mozIStorageConnection* aConnection)
 {
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "DELETE FROM moz_favicons WHERE id IN "
-    "(SELECT f.id FROM moz_favicons f "
-     "LEFT OUTER JOIN moz_places h ON f.id = h.favicon_id "
-     "WHERE h.favicon_id IS NULL)"));
+      "DELETE FROM moz_favicons WHERE id IN ("
+        "SELECT f.id FROM moz_favicons f "
+        "LEFT JOIN moz_places h ON f.id = h.favicon_id "
+        "LEFT JOIN moz_places_temp h_t ON f.id = h_t.favicon_id "
+        "WHERE h.favicon_id IS NULL "
+          "AND h_t.favicon_id IS NULL "
+      ")"));
   NS_ENSURE_SUCCESS(rv, rv);
   return rv;
 }
 
 
 // nsNavHistoryExpire::ExpireAnnotationsParanoid
 //
 //    Deletes session annotations, dangling annotations
@@ -893,69 +1014,74 @@ nsNavHistoryExpire::ExpireAnnotationsPar
     "DELETE FROM moz_annos WHERE expiration = ") +
     nsPrintfCString("%d", nsIAnnotationService::EXPIRE_SESSION);
   nsresult rv = aConnection->ExecuteSimpleSQL(session_query);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // delete all uri annos w/o a corresponding place id
   // or without any visits *and* not EXPIRE_NEVER.
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "DELETE FROM moz_annos WHERE id IN "
-      "(SELECT a.id FROM moz_annos a "
-      "LEFT OUTER JOIN moz_places p ON a.place_id = p.id "
-      "LEFT OUTER JOIN moz_historyvisits v ON a.place_id = v.place_id "
-      "WHERE p.id IS NULL "
-      "OR (v.id IS NULL AND a.expiration != ") +
-      nsPrintfCString("%d", nsIAnnotationService::EXPIRE_NEVER) +
-      NS_LITERAL_CSTRING("))"));
+      "DELETE FROM moz_annos WHERE id IN ("
+        "SELECT a.id FROM moz_annos a "
+        "LEFT JOIN moz_places h ON a.place_id = h.id "
+        "LEFT JOIN moz_places_temp h_t ON a.place_id = h_t.id "
+        "LEFT JOIN moz_historyvisits v ON a.place_id = v.place_id "
+        "LEFT JOIN moz_historyvisits_temp v_t ON a.place_id = v_t.place_id "
+        "WHERE (h.id IS NULL AND h_t.id IS NULL) "
+          "OR (v.id IS NULL AND v_t.id IS NULL AND a.expiration != ") +
+            nsPrintfCString("%d", nsIAnnotationService::EXPIRE_NEVER) +
+          NS_LITERAL_CSTRING(")"
+      ")"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // delete item annos w/o a corresponding item id
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "DELETE FROM moz_items_annos WHERE id IN "
       "(SELECT a.id FROM moz_items_annos a "
       "LEFT OUTER JOIN moz_bookmarks b ON a.item_id = b.id "
       "WHERE b.id IS NULL)"));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // delete all anno names w/o a corresponding uri or item entry
+  // delete all anno names w/o a corresponding anno
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "DELETE FROM moz_anno_attributes WHERE " 
-    "id NOT IN (SELECT DISTINCT a.id FROM moz_anno_attributes a "
-      "JOIN moz_annos b ON b.anno_attribute_id = a.id "
-      "JOIN moz_places p ON b.place_id = p.id) "
-    "AND "
-    "id NOT IN (SELECT DISTINCT a.id FROM moz_anno_attributes a "
-      "JOIN moz_items_annos c ON c.anno_attribute_id = a.id "
-      "JOIN moz_bookmarks p ON c.item_id = p.id)"));
+      "DELETE FROM moz_anno_attributes WHERE id IN (" 
+        "SELECT n.id FROM moz_anno_attributes n "
+        "LEFT JOIN moz_annos a ON n.id = a.anno_attribute_id "
+        "LEFT JOIN moz_items_annos t ON n.id = t.anno_attribute_id "
+        "WHERE a.anno_attribute_id IS NULL "
+          "AND t.anno_attribute_id IS NULL "
+      ")"));
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 
 // nsNavHistoryExpire::ExpireInputHistoryParanoid
 //
 //    Deletes dangling input history, decay potentially unused entries
 
 nsresult
 nsNavHistoryExpire::ExpireInputHistoryParanoid(mozIStorageConnection* aConnection)
 {
   // Delete dangling input history that have no associated pages
   nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "DELETE FROM moz_inputhistory WHERE place_id IN "
-    "(SELECT i.place_id FROM moz_inputhistory i "
-      "LEFT OUTER JOIN moz_places h ON i.place_id = h.id "
-      "WHERE h.id IS NULL)"));
+      "DELETE FROM moz_inputhistory WHERE place_id IN ( "
+        "SELECT place_id FROM moz_inputhistory "
+        "LEFT JOIN moz_places h ON h.id = place_id "
+        "LEFT JOIN moz_places_temp h_t ON h_t.id = place_id "
+        "WHERE h.id IS NULL "
+          "AND h_t.id IS NULL "
+      ")"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Decay potentially unused entries (e.g. those that are at 1) to allow
   // better chances for new entries that will start at 1
   rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "UPDATE moz_inputhistory "
-    "SET use_count = use_count * .9"));
+      "UPDATE moz_inputhistory "
+      "SET use_count = use_count * .9"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 
 // nsNavHistoryExpire::ExpireForDegenerateRuns
 //
--- a/toolkit/components/places/src/nsPlacesTriggers.h
+++ b/toolkit/components/places/src/nsPlacesTriggers.h
@@ -35,48 +35,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef __nsPlacesTriggers_h__
 #define __nsPlacesTriggers_h__
 
 /**
- * Trigger increments the visit count by one for each inserted visit that isn't
- * an invalid transition, embedded transition, or a download transition.
- */
-#define CREATE_VISIT_COUNT_INSERT_TRIGGER NS_LITERAL_CSTRING( \
-  "CREATE TRIGGER moz_historyvisits_afterinsert_v1_trigger " \
-  "AFTER INSERT ON moz_historyvisits FOR EACH ROW " \
-  "WHEN NEW.visit_type NOT IN (0, 4, 7) " /* invalid, EMBED, DOWNLOAD */ \
-  "BEGIN " \
-    "UPDATE moz_places " \
-    "SET visit_count = visit_count + 1 " \
-    "WHERE moz_places.id = NEW.place_id; " \
-  "END" \
-)
-
-/**
- * Trigger decrements the visit count by one for each removed visit that isn't
- * an invalid transition, embeded transition, or a download transition.  To be
- * safe, we ensure that the visit count will not fall below zero.
- */
-#define CREATE_VISIT_COUNT_DELETE_TRIGGER NS_LITERAL_CSTRING( \
-  "CREATE TRIGGER moz_historyvisits_afterdelete_v1_trigger " \
-  "AFTER DELETE ON moz_historyvisits FOR EACH ROW " \
-  "WHEN OLD.visit_type NOT IN (0, 4, 7) " /* invalid, EMBED, DOWNLOAD */ \
-  "BEGIN " \
-    "UPDATE moz_places " \
-    "SET visit_count = visit_count - 1 " \
-    "WHERE moz_places.id = OLD.place_id " \
-    "AND visit_count > 0; " \
-  "END" \
-)
-
-/**
  * Trigger checks to ensure that at least one bookmark is still using a keyword
  * when any bookmark is deleted.  If there are no more bookmarks using it, the
  * keyword is deleted.
  */
 #define CREATE_KEYWORD_VALIDITY_TRIGGER NS_LITERAL_CSTRING( \
   "CREATE TRIGGER moz_bookmarks_beforedelete_v1_trigger " \
   "BEFORE DELETE ON moz_bookmarks FOR EACH ROW " \
   "WHEN OLD.keyword_id NOT NULL " \
--- a/toolkit/components/places/tests/mochitest/bug_411966/redirect.js
+++ b/toolkit/components/places/tests/mochitest/bug_411966/redirect.js
@@ -159,21 +159,21 @@ function checkDB(data){
   // We have to wait since we use lazy_add, lazy_timer is 3s
   setTimeout("checkDBOnTimeout()", 4000);
 }
 
 function checkDBOnTimeout() {
   netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
 
   // Get all pages visited from the original typed one
-  var sql = "SELECT url FROM moz_historyvisits " +
-            "JOIN moz_places h ON h.id = place_id " +
+  var sql = "SELECT url FROM moz_historyvisits_view " +
+            "JOIN moz_places_view h ON h.id = place_id " +
             "WHERE from_visit IN " +
-              "(SELECT v.id FROM moz_historyvisits v " +
-              "JOIN moz_places p ON p.id = v.place_id " +
+              "(SELECT v.id FROM moz_historyvisits_view v " +
+              "JOIN moz_places_view p ON p.id = v.place_id " +
               "WHERE p.url = ?1)";
   var stmt = mDBConn.createStatement(sql);
   stmt.bindUTF8StringParameter(0, typedURI.spec);
 
   var empty = true;
   while (stmt.executeStep()) {
     empty = false;
     var visitedURI = stmt.getUTF8String(0);
--- a/toolkit/components/places/tests/unit/test_history.js
+++ b/toolkit/components/places/tests/unit/test_history.js
@@ -36,16 +36,18 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 // Get history service
 try {
   var histsvc = Cc["@mozilla.org/browser/nav-history-service;1"].getService(Ci.nsINavHistoryService);
+  var gh = Cc["@mozilla.org/browser/global-history;2"].
+           getService(Ci.nsIGlobalHistory2);
 } catch(ex) {
   do_throw("Could not get history service\n");
 } 
 
 /**
  * Adds a test URI visit to the database, and checks for a valid place ID.
  *
  * @param aURI
@@ -56,17 +58,19 @@ try {
  */
 function add_visit(aURI, aReferrer) {
   var placeID = histsvc.addVisit(aURI,
                                  Date.now() * 1000,
                                  aReferrer,
                                  histsvc.TRANSITION_TYPED, // user typed in URL bar
                                  false, // not redirect
                                  0);
+  dump("### Added visit with id of " + placeID + "\n");
   do_check_true(placeID > 0);
+  do_check_true(gh.isVisited(aURI));
   return placeID;
 }
 
 /**
  * Checks to see that a URI is in the database.
  *
  * @param aURI
  *        The URI to check.