Bug 695554 - Split a Database class out of the History service. (expected fake Ts_shutdown regressions!)
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 27 Oct 2011 11:11:34 +0200
changeset 79270 28288ae6d58c244d980145fde8c34d9b9564f7c9
parent 79269 32ab009026d7605ed5a019faa49f12e0f51659b4
child 79271 1ed8be9fed394427989006195532d11c524f5d0d
push idunknown
push userunknown
push dateunknown
bugs695554
milestone10.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 695554 - Split a Database class out of the History service. (expected fake Ts_shutdown regressions!) r=dietrich
toolkit/components/places/AsyncFaviconHelpers.cpp
toolkit/components/places/AsyncFaviconHelpers.h
toolkit/components/places/Database.cpp
toolkit/components/places/Database.h
toolkit/components/places/Helpers.cpp
toolkit/components/places/Helpers.h
toolkit/components/places/History.cpp
toolkit/components/places/History.h
toolkit/components/places/Makefile.in
toolkit/components/places/SQLFunctions.cpp
toolkit/components/places/SQLFunctions.h
toolkit/components/places/nsAnnoProtocolHandler.cpp
toolkit/components/places/nsAnnotationService.cpp
toolkit/components/places/nsAnnotationService.h
toolkit/components/places/nsFaviconService.cpp
toolkit/components/places/nsFaviconService.h
toolkit/components/places/nsNavBookmarks.cpp
toolkit/components/places/nsNavBookmarks.h
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/nsNavHistory.h
toolkit/components/places/nsNavHistoryResult.cpp
toolkit/components/places/nsPlacesImportExportService.cpp
toolkit/components/places/nsPlacesMacros.h
--- a/toolkit/components/places/AsyncFaviconHelpers.cpp
+++ b/toolkit/components/places/AsyncFaviconHelpers.cpp
@@ -32,30 +32,29 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * 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 ***** */
 
 #include "AsyncFaviconHelpers.h"
-#include "mozilla/storage.h"
-#include "nsNetUtil.h"
-#include "nsPrintfCString.h"
-#include "nsProxyRelease.h"
 
-#include "nsStreamUtils.h"
 #include "nsIContentSniffer.h"
 #include "nsICacheService.h"
 #include "nsICacheVisitor.h"
 #include "nsICachingChannel.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 
 #include "nsNavHistory.h"
-#include "nsNavBookmarks.h"
+#include "nsFaviconService.h"
+#include "mozilla/storage.h"
+#include "nsNetUtil.h"
+#include "nsPrintfCString.h"
+#include "nsStreamUtils.h"
 
 #define TO_CHARBUFFER(_buffer) \
   reinterpret_cast<char*>(const_cast<PRUint8*>(_buffer))
 #define TO_INTBUFFER(_string) \
   reinterpret_cast<PRUint8*>(const_cast<char*>(_string.get()))
 
 #define CONTENT_SNIFFING_SERVICES "content-sniffing-services"
 
@@ -65,37 +64,39 @@
  * is more in the future than this.
  * Currently set to one week from now.
  */
 #define MAX_FAVICON_EXPIRATION ((PRTime)7 * 24 * 60 * 60 * PR_USEC_PER_SEC)
 
 using namespace mozilla::places;
 using namespace mozilla::storage;
 
+namespace mozilla {
+namespace places {
+
 namespace {
 
 /**
  * Fetches information on a page from the Places database.
  *
  * @param aDBConn
  *        Database connection to history tables.
  * @param _page
  *        Page that should be fetched.
  */
 nsresult
-FetchPageInfo(StatementCache<mozIStorageStatement>& aStmtCache,
+FetchPageInfo(nsRefPtr<Database>& aDB,
               PageData& _page)
 {
   NS_PRECONDITION(_page.spec.Length(), "Must have a non-empty spec!");
   NS_PRECONDITION(!NS_IsMainThread(),
                   "This should not be called on the main thread");
 
   // This query fragment finds the bookmarked uri we want to set the icon for,
-  // walking up to three redirect levels.  It is borrowed from
-  // nsNavBookmarks::mDBFindRedirectedBookmark.  
+  // walking up to three redirect levels.  
   nsCString redirectedBookmarksFragment =
     nsPrintfCString(1024,
       "SELECT h.url "
       "FROM moz_bookmarks b "
       "WHERE b.fk = h.id "
       "UNION ALL " // Union not directly bookmarked pages.
       "SELECT (SELECT url FROM moz_places WHERE id = %s) "
       "FROM moz_historyvisits self "
@@ -113,22 +114,21 @@ FetchPageInfo(StatementCache<mozIStorage
       nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
       nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY,
       nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
       nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY,
       nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
       nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY
     );
 
-  nsCOMPtr<mozIStorageStatement> stmt =
-    aStmtCache.GetCachedStatement(NS_LITERAL_CSTRING(
-      "SELECT h.id, h.favicon_id, h.guid, "
-             "(") + redirectedBookmarksFragment + NS_LITERAL_CSTRING(") "
-      "FROM moz_places h WHERE h.url = :page_url"
-    ));
+  nsCOMPtr<mozIStorageStatement> stmt = aDB->GetStatement(NS_LITERAL_CSTRING(
+    "SELECT h.id, h.favicon_id, h.guid, "
+           "(") + redirectedBookmarksFragment + NS_LITERAL_CSTRING(") "
+    "FROM moz_places h WHERE h.url = :page_url"
+  ));
   NS_ENSURE_STATE(stmt);
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"),
                                 _page.spec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
@@ -168,17 +168,17 @@ FetchPageInfo(StatementCache<mozIStorage
       // history would be a privacy leak, bail out as if the page did not exist.
       return NS_ERROR_NOT_AVAILABLE;
     }
     else {
       // The page, or a redirect to it, is bookmarked.  If the bookmarked spec
       // is different from the requested one, use it.
       if (!_page.bookmarkedSpec.Equals(_page.spec)) {
         _page.spec = _page.bookmarkedSpec;
-        rv = FetchPageInfo(aStmtCache, _page);
+        rv = FetchPageInfo(aDB, _page);
         NS_ENSURE_SUCCESS(rv, rv);
       }
     }
   }
 
   return NS_OK;
 }
 
@@ -186,28 +186,27 @@ FetchPageInfo(StatementCache<mozIStorage
  * Fetches information on a icon from the Places database.
  *
  * @param aDBConn
  *        Database connection to history tables.
  * @param _icon
  *        Icon that should be fetched.
  */
 nsresult
-FetchIconInfo(StatementCache<mozIStorageStatement>& aStmtCache,
+FetchIconInfo(nsRefPtr<Database>& aDB,
               IconData& _icon)
 {
   NS_PRECONDITION(_icon.spec.Length(), "Must have a non-empty spec!");
   NS_PRECONDITION(!NS_IsMainThread(),
                   "This should not be called on the main thread");
 
-  nsCOMPtr<mozIStorageStatement> stmt =
-    aStmtCache.GetCachedStatement(NS_LITERAL_CSTRING(
-      "SELECT id, expiration, data, mime_type "
-      "FROM moz_favicons WHERE url = :icon_url"
-    ));
+  nsCOMPtr<mozIStorageStatement> stmt = aDB->GetStatement(
+    "SELECT id, expiration, data, mime_type "
+    "FROM moz_favicons WHERE url = :icon_url"
+  );
   NS_ENSURE_STATE(stmt);
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"),
                                 _icon.spec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
@@ -243,33 +242,32 @@ FetchIconInfo(StatementCache<mozIStorage
     rv = stmt->GetUTF8String(3, _icon.mimeType);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 nsresult
-FetchIconURL(StatementCache<mozIStorageStatement>& aStmtCache,
+FetchIconURL(nsRefPtr<Database>& aDB,
              const nsACString& aPageSpec,
              nsACString& aIconSpec)
 {
   NS_PRECONDITION(!aPageSpec.IsEmpty(), "Page spec must not be empty.");
   NS_PRECONDITION(!NS_IsMainThread(),
                   "This should not be called on the main thread.");
 
   aIconSpec.Truncate();
 
-  nsCOMPtr<mozIStorageStatement> stmt =
-    aStmtCache.GetCachedStatement(NS_LITERAL_CSTRING(
-      "SELECT f.url "
-      "FROM moz_places h "
-      "JOIN moz_favicons f ON h.favicon_id = f.id "
-      "WHERE h.url = :page_url"
-    ));
+  nsCOMPtr<mozIStorageStatement> stmt = aDB->GetStatement(
+    "SELECT f.url "
+    "FROM moz_places h "
+    "JOIN moz_favicons f ON h.favicon_id = f.id "
+    "WHERE h.url = :page_url"
+  );
   NS_ENSURE_STATE(stmt);
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"),
                                 aPageSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
@@ -398,58 +396,45 @@ OptimizeIconSize(IconData& aIcon,
       aIcon.mimeType = newMimeType;
     }
   }
   return NS_OK;
 }
 
 } // Anonymous namespace.
 
-namespace mozilla {
-namespace places {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncFaviconHelperBase
 
 AsyncFaviconHelperBase::AsyncFaviconHelperBase(
-  nsCOMPtr<mozIStorageConnection>& aDBConn
-, nsRefPtr<nsFaviconService>& aFaviconSvc
-, nsCOMPtr<nsIFaviconDataCallback>& aCallback)
-: mDBConn(aDBConn)
+  nsCOMPtr<nsIFaviconDataCallback>& aCallback
+) : mDB(Database::GetDatabase())
 {
   // Don't AddRef or Release in runnables for thread-safety.
-  mFaviconSvc.swap(aFaviconSvc);
   mCallback.swap(aCallback);
 }
 
 AsyncFaviconHelperBase::~AsyncFaviconHelperBase()
 {
   nsCOMPtr<nsIThread> thread;
   (void)NS_GetMainThread(getter_AddRefs(thread));
   if (mCallback) {
     (void)NS_ProxyRelease(thread, mCallback, true);
   }
-  if (mFaviconSvc) {
-    // Cast mFaviconSvc to nsIFaviconService before passing to NS_ProxyRelease
-    // so NS_ProxyRelease can unambiguously cast to nsISupports.
-    nsIFaviconService *faviconSvc;
-    mFaviconSvc.forget(&faviconSvc);
-    (void)NS_ProxyRelease(thread, faviconSvc, true);
-  }
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncFetchAndSetIconForPage
 
 // static
 nsresult
 AsyncFetchAndSetIconForPage::start(nsIURI* aFaviconURI,
                                    nsIURI* aPageURI,
                                    enum AsyncFaviconFetchMode aFetchMode,
-                                   nsCOMPtr<mozIStorageConnection>& aDBConn,
                                    nsIFaviconDataCallback* aCallback)
 {
   NS_PRECONDITION(NS_IsMainThread(),
                   "This should be called on the main thread");
 
   PageData page;
   nsresult rv = aPageURI->GetSpec(page.spec);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -471,82 +456,72 @@ AsyncFetchAndSetIconForPage::start(nsIUR
   // In future evaluate to store a resample of the image.  For now avoid that
   // for database size concerns.
   // Don't store favicons for error pages too.
   if (icon.spec.Equals(page.spec) ||
       icon.spec.Equals(FAVICON_ERRORPAGE_URL)) {
     return NS_OK;
   }
 
-  nsRefPtr<nsFaviconService> fs = nsFaviconService::GetFaviconService();
-  NS_ENSURE_TRUE(fs, NS_ERROR_OUT_OF_MEMORY);
   // The event will swap owning pointers, thus we need a new pointer.
   nsCOMPtr<nsIFaviconDataCallback> callback(aCallback);
   nsRefPtr<AsyncFetchAndSetIconForPage> event =
-    new AsyncFetchAndSetIconForPage(icon, page, aDBConn, fs, callback);
+    new AsyncFetchAndSetIconForPage(icon, page, callback);
 
   // Get the target thread and start the work.
-  nsCOMPtr<nsIEventTarget> target = do_GetInterface(aDBConn);
-  NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
-  rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsRefPtr<Database> DB = Database::GetDatabase();
+  NS_ENSURE_STATE(DB);
+  DB->DispatchToAsyncThread(event);
 
   return NS_OK;
 }
 
 AsyncFetchAndSetIconForPage::AsyncFetchAndSetIconForPage(
   IconData& aIcon
 , PageData& aPage
-, nsCOMPtr<mozIStorageConnection>& aDBConn
-, nsRefPtr<nsFaviconService>& aFaviconSvc
 , nsCOMPtr<nsIFaviconDataCallback>& aCallback
-)
-: AsyncFaviconHelperBase(aDBConn, aFaviconSvc, aCallback)
-, mIcon(aIcon)
-, mPage(aPage)
+) : AsyncFaviconHelperBase(aCallback)
+  , mIcon(aIcon)
+  , mPage(aPage)
 {
 }
 
 AsyncFetchAndSetIconForPage::~AsyncFetchAndSetIconForPage()
 {
 }
 
 NS_IMETHODIMP
 AsyncFetchAndSetIconForPage::Run()
 {
   NS_PRECONDITION(!NS_IsMainThread(),
                   "This should not be called on the main thread");
 
   // Try to fetch the icon from the database.
-  nsresult rv = FetchIconInfo(mFaviconSvc->mSyncStatements, mIcon);
+  nsresult rv = FetchIconInfo(mDB, mIcon);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool isInvalidIcon = mIcon.data.IsEmpty() ||
                        (mIcon.expiration && PR_Now() > mIcon.expiration);
   bool fetchIconFromNetwork = mIcon.fetchMode == FETCH_ALWAYS ||
                               (mIcon.fetchMode == FETCH_IF_MISSING && isInvalidIcon);
 
   if (!fetchIconFromNetwork) {
     // There is already a valid icon or we don't want to fetch a new one,
     // directly proceed with association.
     nsRefPtr<AsyncAssociateIconToPage> event =
-        new AsyncAssociateIconToPage(mIcon, mPage, mDBConn, mFaviconSvc, mCallback);
+        new AsyncAssociateIconToPage(mIcon, mPage, mCallback);
+    mDB->DispatchToAsyncThread(event);
 
-    // Get the target thread and start the work.
-    nsCOMPtr<nsIEventTarget> target = do_GetInterface(mDBConn);
-    NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
-    nsresult rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
-    NS_ENSURE_SUCCESS(rv, rv);
     return NS_OK;
   }
   else {
     // Fetch the icon from network.  When done this will associate the
     // icon to the page and notify.
     nsRefPtr<AsyncFetchAndSetIconFromNetwork> event =
-      new AsyncFetchAndSetIconFromNetwork(mIcon, mPage, mDBConn, mFaviconSvc, mCallback);
+      new AsyncFetchAndSetIconFromNetwork(mIcon, mPage, mCallback);
 
     // Start the work on the main thread.
     rv = NS_DispatchToMainThread(event);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
@@ -560,21 +535,19 @@ NS_IMPL_ISUPPORTS_INHERITED3(
 , nsIStreamListener
 , nsIInterfaceRequestor
 , nsIChannelEventSink
 )
 
 AsyncFetchAndSetIconFromNetwork::AsyncFetchAndSetIconFromNetwork(
   IconData& aIcon
 , PageData& aPage
-, nsCOMPtr<mozIStorageConnection>& aDBConn
-, nsRefPtr<nsFaviconService>& aFaviconSvc
 , nsCOMPtr<nsIFaviconDataCallback>& aCallback
 )
-: AsyncFaviconHelperBase(aDBConn, aFaviconSvc, aCallback)
+: AsyncFaviconHelperBase(aCallback)
 , mIcon(aIcon)
 , mPage(aPage)
 {
 }
 
 AsyncFetchAndSetIconFromNetwork::~AsyncFetchAndSetIconFromNetwork()
 {
   nsCOMPtr<nsIThread> thread;
@@ -658,114 +631,110 @@ AsyncFetchAndSetIconFromNetwork::AsyncOn
   return NS_OK;
 }
 
 NS_IMETHODIMP
 AsyncFetchAndSetIconFromNetwork::OnStopRequest(nsIRequest* aRequest,
                                                nsISupports* aContext,
                                                nsresult aStatusCode)
 {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsFaviconService* favicons = nsFaviconService::GetFaviconService();
+  NS_ENSURE_STATE(favicons);
+
   // If fetching the icon failed, add it to the failed cache.
   if (NS_FAILED(aStatusCode) || mIcon.data.Length() == 0) {
     nsCOMPtr<nsIURI> iconURI;
     nsresult rv = NS_NewURI(getter_AddRefs(iconURI), mIcon.spec);
     NS_ENSURE_SUCCESS(rv, rv);
-    rv = mFaviconSvc->AddFailedFavicon(iconURI);
+    rv = favicons->AddFailedFavicon(iconURI);
     NS_ENSURE_SUCCESS(rv, rv);
     return NS_OK;
   }
 
   nsresult rv = SniffMimeTypeForIconData(aRequest, mIcon.data, mIcon.mimeType);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // If the icon does not have a valid MIME type, add it to the failed cache.
   if (mIcon.mimeType.IsEmpty()) {
     nsCOMPtr<nsIURI> iconURI;
     rv = NS_NewURI(getter_AddRefs(iconURI), mIcon.spec);
     NS_ENSURE_SUCCESS(rv, rv);
-    rv = mFaviconSvc->AddFailedFavicon(iconURI);
+    rv = favicons->AddFailedFavicon(iconURI);
     NS_ENSURE_SUCCESS(rv, rv);
     return NS_OK;
   }
 
   mIcon.expiration = GetExpirationTimeFromChannel(mChannel);
 
-  rv = OptimizeIconSize(mIcon, mFaviconSvc);
+  rv = OptimizeIconSize(mIcon, favicons);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // If over the maximum size allowed, don't save data to the database to
   // avoid bloating it.
   if (mIcon.data.Length() > MAX_FAVICON_SIZE) {
     return NS_OK;
   }
 
   mIcon.status = ICON_STATUS_CHANGED;
 
   nsRefPtr<AsyncAssociateIconToPage> event =
-      new AsyncAssociateIconToPage(mIcon, mPage, mDBConn, mFaviconSvc, mCallback);
-
-  // Get the target thread and start the work.
-  nsCOMPtr<nsIEventTarget> target = do_GetInterface(mDBConn);
-  NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
-  rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
-  NS_ENSURE_SUCCESS(rv, rv);
+    new AsyncAssociateIconToPage(mIcon, mPage, mCallback);
+  mDB->DispatchToAsyncThread(event);
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncAssociateIconToPage
 
 AsyncAssociateIconToPage::AsyncAssociateIconToPage(
   IconData& aIcon
 , PageData& aPage
-, nsCOMPtr<mozIStorageConnection>& aDBConn
-, nsRefPtr<nsFaviconService>& aFaviconSvc
 , nsCOMPtr<nsIFaviconDataCallback>& aCallback
-)
-: AsyncFaviconHelperBase(aDBConn, aFaviconSvc, aCallback)
-, mIcon(aIcon)
-, mPage(aPage)
+) : AsyncFaviconHelperBase(aCallback)
+  , mIcon(aIcon)
+  , mPage(aPage)
 {
 }
 
 AsyncAssociateIconToPage::~AsyncAssociateIconToPage()
 {
 }
 
 NS_IMETHODIMP
 AsyncAssociateIconToPage::Run()
 {
   NS_PRECONDITION(!NS_IsMainThread(),
                   "This should not be called on the main thread");
 
-  nsresult rv = FetchPageInfo(mFaviconSvc->mSyncStatements, mPage);
+  nsresult rv = FetchPageInfo(mDB, mPage);
   if (rv == NS_ERROR_NOT_AVAILABLE){
     // We have never seen this page.  If we can add the page to history,
     // we will try to do it later, otherwise just bail out.
     if (!mPage.canAddToHistory) {
       return NS_OK;
     }
   }
   else {
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  mozStorageTransaction transaction(mDBConn, false,
+  mozStorageTransaction transaction(mDB->MainConn(), false,
                                     mozIStorageConnection::TRANSACTION_IMMEDIATE);
 
   // If there is no entry for this icon, or the entry is obsolete, replace it.
   if (mIcon.id == 0 || (mIcon.status & ICON_STATUS_CHANGED)) {
-    nsCOMPtr<mozIStorageStatement> stmt =
-      mFaviconSvc->mSyncStatements.GetCachedStatement(NS_LITERAL_CSTRING(
-        "INSERT OR REPLACE INTO moz_favicons "
-          "(id, url, data, mime_type, expiration) "
-        "VALUES ((SELECT id FROM moz_favicons WHERE url = :icon_url), "
-                ":icon_url, :data, :mime_type, :expiration) "
-      ));
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+      "INSERT OR REPLACE INTO moz_favicons "
+        "(id, url, data, mime_type, expiration) "
+      "VALUES ((SELECT id FROM moz_favicons WHERE url = :icon_url), "
+              ":icon_url, :data, :mime_type, :expiration) "
+    );
     NS_ENSURE_STATE(stmt);
     mozStorageStatementScoper scoper(stmt);
     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), mIcon.spec);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"),
                               TO_INTBUFFER(mIcon.data), mIcon.data.Length());
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("mime_type"), mIcon.mimeType);
@@ -773,29 +742,28 @@ AsyncAssociateIconToPage::Run()
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("expiration"), mIcon.expiration);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Get the new icon id.  Do this regardless mIcon.id, since other code
     // could have added a entry before us.  Indeed we interrupted the thread
     // after the previous call to FetchIconInfo.
-    rv = FetchIconInfo(mFaviconSvc->mSyncStatements, mIcon);
+    rv = FetchIconInfo(mDB, mIcon);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mIcon.status |= ICON_STATUS_SAVED;
   }
 
   // If the page does not have an id, try to insert a new one.
   if (mPage.id == 0) {
-    nsCOMPtr<mozIStorageStatement> stmt =
-      mFaviconSvc->mSyncStatements.GetCachedStatement(NS_LITERAL_CSTRING(
-        "INSERT INTO moz_places (url, rev_host, hidden, favicon_id, frecency, guid) "
-        "VALUES (:page_url, :rev_host, 1, :favicon_id, 0, GENERATE_GUID()) "
-      ));
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+      "INSERT INTO moz_places (url, rev_host, hidden, favicon_id, frecency, guid) "
+      "VALUES (:page_url, :rev_host, 1, :favicon_id, 0, GENERATE_GUID()) "
+    );
     NS_ENSURE_STATE(stmt);
     mozStorageStatementScoper scoper(stmt);
     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mPage.spec);
     NS_ENSURE_SUCCESS(rv, rv);
     // The rev_host can be null.
     if (mPage.revHost.IsEmpty()) {
       rv = stmt->BindNullByName(NS_LITERAL_CSTRING("rev_host"));
     }
@@ -804,36 +772,36 @@ AsyncAssociateIconToPage::Run()
     }
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("favicon_id"), mIcon.id);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Get the new id and GUID.
-    rv = FetchPageInfo(mFaviconSvc->mSyncStatements, mPage);
+    rv = FetchPageInfo(mDB, mPage);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mIcon.status |= ICON_STATUS_ASSOCIATED;
   }
   // Otherwise just associate the icon to the page, if needed.
   else if (mPage.iconId != mIcon.id) {
     nsCOMPtr<mozIStorageStatement> stmt;
     if (mPage.id) {
-      stmt = mFaviconSvc->mSyncStatements.GetCachedStatement(NS_LITERAL_CSTRING(
+      stmt = mDB->GetStatement(
         "UPDATE moz_places SET favicon_id = :icon_id WHERE id = :page_id"
-      ));
+      );
       NS_ENSURE_STATE(stmt);
       rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), mPage.id);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
-      stmt = mFaviconSvc->mSyncStatements.GetCachedStatement(NS_LITERAL_CSTRING(
+      stmt = mDB->GetStatement(
         "UPDATE moz_places SET favicon_id = :icon_id WHERE url = :page_url"
-      ));
+      );
       NS_ENSURE_STATE(stmt);
       rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mPage.spec);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("icon_id"), mIcon.id);
     NS_ENSURE_SUCCESS(rv, rv);
 
     mozStorageStatementScoper scoper(stmt);
@@ -842,184 +810,167 @@ AsyncAssociateIconToPage::Run()
 
     mIcon.status |= ICON_STATUS_ASSOCIATED;
   }
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Finally, dispatch an event to the main thread to notify observers.
-  nsCOMPtr<nsIRunnable> event = new NotifyIconObservers(mIcon, mPage, mDBConn, mFaviconSvc, mCallback);
+  nsCOMPtr<nsIRunnable> event = new NotifyIconObservers(mIcon, mPage, mCallback);
   rv = NS_DispatchToMainThread(event);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncGetFaviconURLForPage
 
 // static
 nsresult
 AsyncGetFaviconURLForPage::start(nsIURI* aPageURI,
-                                 nsCOMPtr<mozIStorageConnection>& aDBConn,
                                  nsIFaviconDataCallback* aCallback)
 {
   NS_ENSURE_ARG(aCallback);
   NS_ENSURE_ARG(aPageURI);
   NS_PRECONDITION(NS_IsMainThread(),
                   "This should be called on the main thread.");
 
-  nsRefPtr<nsFaviconService> fs = nsFaviconService::GetFaviconService();
-  NS_ENSURE_TRUE(fs, NS_ERROR_OUT_OF_MEMORY);
-
   nsCAutoString pageSpec;
   nsresult rv = aPageURI->GetSpec(pageSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIFaviconDataCallback> callback = aCallback;
   nsRefPtr<AsyncGetFaviconURLForPage> event =
-    new AsyncGetFaviconURLForPage(pageSpec, aDBConn, fs, callback);
+    new AsyncGetFaviconURLForPage(pageSpec, callback);
 
-  nsCOMPtr<nsIEventTarget> target = do_GetInterface(aDBConn);
-  NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
-  rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsRefPtr<Database> DB = Database::GetDatabase();
+  NS_ENSURE_STATE(DB);
+  DB->DispatchToAsyncThread(event);
+
   return NS_OK;
 }
 
 AsyncGetFaviconURLForPage::AsyncGetFaviconURLForPage(
   const nsACString& aPageSpec
-, nsCOMPtr<mozIStorageConnection>& aDBConn
-, nsRefPtr<nsFaviconService>& aFaviconSvc
-, nsCOMPtr<nsIFaviconDataCallback>& aCallback)
-: AsyncFaviconHelperBase(aDBConn, aFaviconSvc, aCallback)
+, nsCOMPtr<nsIFaviconDataCallback>& aCallback
+) : AsyncFaviconHelperBase(aCallback)
 {
   mPageSpec.Assign(aPageSpec);
 }
 
 AsyncGetFaviconURLForPage::~AsyncGetFaviconURLForPage()
 {
 }
 
 NS_IMETHODIMP
 AsyncGetFaviconURLForPage::Run()
 {
   NS_PRECONDITION(!NS_IsMainThread(),
                   "This should not be called on the main thread.");
 
   nsCAutoString iconSpec;
-  nsresult rv = FetchIconURL(mFaviconSvc->mSyncStatements,
-                             mPageSpec, iconSpec);
+  nsresult rv = FetchIconURL(mDB, mPageSpec, iconSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Now notify our callback of the icon spec we retrieved.
   IconData iconData;
   iconData.spec.Assign(iconSpec);
 
   PageData pageData;
   pageData.spec.Assign(mPageSpec);
 
   nsCOMPtr<nsIRunnable> event =
-    new NotifyIconObservers(iconData, pageData, mDBConn,
-                            mFaviconSvc, mCallback);
+    new NotifyIconObservers(iconData, pageData, mCallback);
   rv = NS_DispatchToMainThread(event);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// AsyncGetFaviconDataForPage
 
 // static
 nsresult
 AsyncGetFaviconDataForPage::start(nsIURI* aPageURI,
-                                  nsCOMPtr<mozIStorageConnection>& aDBConn,
                                   nsIFaviconDataCallback* aCallback)
 {
   NS_ENSURE_ARG(aCallback);
   NS_ENSURE_ARG(aPageURI);
   NS_PRECONDITION(NS_IsMainThread(),
                   "This should be called on the main thread.");
 
-  nsRefPtr<nsFaviconService> fs = nsFaviconService::GetFaviconService();
-  NS_ENSURE_TRUE(fs, NS_ERROR_OUT_OF_MEMORY);
-
   nsCAutoString pageSpec;
   nsresult rv = aPageURI->GetSpec(pageSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIFaviconDataCallback> callback = aCallback;
   nsRefPtr<AsyncGetFaviconDataForPage> event =
-    new AsyncGetFaviconDataForPage(pageSpec, aDBConn, fs, callback);
+    new AsyncGetFaviconDataForPage(pageSpec, callback);
 
-  nsCOMPtr<nsIEventTarget> target = do_GetInterface(aDBConn);
-  NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
-  rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsRefPtr<Database> DB = Database::GetDatabase();
+  NS_ENSURE_STATE(DB);
+  DB->DispatchToAsyncThread(event);
+
   return NS_OK;
 }
 
-AsyncGetFaviconDataForPage::AsyncGetFaviconDataForPage(const nsACString& aPageSpec, 
-                                                       nsCOMPtr<mozIStorageConnection>& aDBConn, 
-                                                       nsRefPtr<nsFaviconService>& aFaviconSvc, 
-                                                       nsCOMPtr<nsIFaviconDataCallback>& aCallback)
-  : AsyncFaviconHelperBase(aDBConn, aFaviconSvc, aCallback)
+AsyncGetFaviconDataForPage::AsyncGetFaviconDataForPage(
+  const nsACString& aPageSpec
+, nsCOMPtr<nsIFaviconDataCallback>& aCallback
+) : AsyncFaviconHelperBase(aCallback)
 {
   mPageSpec.Assign(aPageSpec);
 }
 
 AsyncGetFaviconDataForPage::~AsyncGetFaviconDataForPage()
 {
 }
 
 NS_IMETHODIMP
 AsyncGetFaviconDataForPage::Run()
 {
   NS_PRECONDITION(!NS_IsMainThread(),
                   "This should not be called on the main thread.");
 
   nsCAutoString iconSpec;
-  nsresult rv = FetchIconURL(mFaviconSvc->mSyncStatements,
-                             mPageSpec, iconSpec);
+  nsresult rv = FetchIconURL(mDB, mPageSpec, iconSpec);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!iconSpec.Length()) {
     return NS_ERROR_NOT_AVAILABLE;
   }
 
   IconData iconData;
   iconData.spec.Assign(iconSpec);
 
   PageData pageData;
   pageData.spec.Assign(mPageSpec);
 
-  rv = FetchIconInfo(mFaviconSvc->mSyncStatements, iconData);
+  rv = FetchIconInfo(mDB, iconData);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIRunnable> event =
-    new NotifyIconObservers(iconData, pageData, mDBConn,
-                            mFaviconSvc, mCallback);
+    new NotifyIconObservers(iconData, pageData, mCallback);
   rv = NS_DispatchToMainThread(event);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// NotifyIconObservers
 
 NotifyIconObservers::NotifyIconObservers(
   IconData& aIcon
 , PageData& aPage
-, nsCOMPtr<mozIStorageConnection>& aDBConn
-, nsRefPtr<nsFaviconService>& aFaviconSvc
 , nsCOMPtr<nsIFaviconDataCallback>& aCallback
 )
-: AsyncFaviconHelperBase(aDBConn, aFaviconSvc, aCallback)
+: AsyncFaviconHelperBase(aCallback)
 , mIcon(aIcon)
 , mPage(aPage)
 {
 }
 
 NotifyIconObservers::~NotifyIconObservers()
 {
 }
@@ -1036,36 +987,33 @@ NotifyIconObservers::Run()
 
   // Notify observers only if something changed.
   if (mIcon.status & ICON_STATUS_SAVED ||
       mIcon.status & ICON_STATUS_ASSOCIATED) {
     nsCOMPtr<nsIURI> pageURI;
     rv = NS_NewURI(getter_AddRefs(pageURI), mPage.spec);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    mFaviconSvc->SendFaviconNotifications(pageURI, iconURI, mPage.guid);
+    nsFaviconService* favicons = nsFaviconService::GetFaviconService();
+    NS_ENSURE_STATE(favicons);
+    (void)favicons->SendFaviconNotifications(pageURI, iconURI, mPage.guid);
 
     // If the page is bookmarked and the bookmarked url is different from the
     // updated one, start a new task to update its icon as well.
     if (!mPage.bookmarkedSpec.IsEmpty() &&
         !mPage.bookmarkedSpec.Equals(mPage.spec)) {
       // Create a new page struct to avoid polluting it with old data.
       PageData bookmarkedPage;
       bookmarkedPage.spec = mPage.bookmarkedSpec;
 
       // This will be silent, so be sure to not pass in the current callback.
       nsCOMPtr<nsIFaviconDataCallback> nullCallback;
       nsRefPtr<AsyncAssociateIconToPage> event =
-          new AsyncAssociateIconToPage(mIcon, bookmarkedPage, mDBConn, mFaviconSvc, nullCallback);
-
-      // Get the target thread and start the work.
-      nsCOMPtr<nsIEventTarget> target = do_GetInterface(mDBConn);
-      NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
-      nsresult rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
-      NS_ENSURE_SUCCESS(rv, rv);
+          new AsyncAssociateIconToPage(mIcon, bookmarkedPage, nullCallback);
+      mDB->DispatchToAsyncThread(event);
     }
   }
 
   if (mCallback) {
     (void)mCallback->OnFaviconDataAvailable(iconURI,
                                             mIcon.data.Length(),
                                             TO_INTBUFFER(mIcon.data),
                                             mIcon.mimeType);
--- a/toolkit/components/places/AsyncFaviconHelpers.h
+++ b/toolkit/components/places/AsyncFaviconHelpers.h
@@ -34,30 +34,24 @@
  * 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 ***** */
 
 #ifndef AsyncFaviconHelpers_h_
 #define AsyncFaviconHelpers_h_
 
-#include "nsCOMPtr.h"
-#include "nsCOMArray.h"
-#include "nsIURI.h"
-#include "nsThreadUtils.h"
-
-#include "nsFaviconService.h"
-#include "Helpers.h"
-
-#include "mozilla/storage.h"
-
+#include "nsIFaviconService.h"
 #include "nsIChannelEventSink.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIStreamListener.h"
 
+#include "Database.h"
+#include "mozilla/storage.h"
+
 #define ICON_STATUS_UNKNOWN 0
 #define ICON_STATUS_CHANGED 1 << 0
 #define ICON_STATUS_SAVED 1 << 1
 #define ICON_STATUS_ASSOCIATED 1 << 2
 
 namespace mozilla {
 namespace places {
 
@@ -111,31 +105,26 @@ struct PageData
   nsString revHost;
   bool canAddToHistory; // False for disabled history and unsupported schemas.
   PRInt64 iconId;
   nsCString guid;
 };
 
 /**
  * Base class for events declared in this file.  This class's main purpose is
- * to declare a destructor which releases mFaviconSvc and mCallback on the main
- * thread.
+ * to declare a destructor which releases mCallback on the main thread.
  */
 class AsyncFaviconHelperBase : public nsRunnable
 {
 protected:
-  AsyncFaviconHelperBase(nsCOMPtr<mozIStorageConnection>& aDBConn,
-                         nsRefPtr<nsFaviconService>& aFaviconSvc,
-                         nsCOMPtr<nsIFaviconDataCallback>& aCallback);
+  AsyncFaviconHelperBase(nsCOMPtr<nsIFaviconDataCallback>& aCallback);
 
   virtual ~AsyncFaviconHelperBase();
 
-  nsCOMPtr<mozIStorageConnection>& mDBConn;
-  // Strong reference since we don't want it to disappear out from under us.
-  nsRefPtr<nsFaviconService> mFaviconSvc;
+  nsRefPtr<Database> mDB;
   // Strong reference since we are responsible for its existence.
   nsCOMPtr<nsIFaviconDataCallback> mCallback;
 };
 
 /**
  * Async fetches icon from database or network, associates it with the required
  * page and finally notifies the change.
  */
@@ -149,43 +138,36 @@ public:
    *
    * @param aFaviconURI
    *        URI of the icon to be fetched and associated.
    * @param aPageURI
    *        URI of the page to which associate the icon.
    * @param aFetchMode
    *        Specifies whether a icon should be fetched from network if not found
    *        in the database.
-   * @param aDBConn
-   *        Database connection to use.
    * @param aCallback
    *        Function to be called when the fetch-and-associate process finishes.
    */
   static nsresult start(nsIURI* aFaviconURI,
                         nsIURI* aPageURI,
                         enum AsyncFaviconFetchMode aFetchMode,
-                        nsCOMPtr<mozIStorageConnection>& aDBConn,
                         nsIFaviconDataCallback* aCallback);
 
   /**
    * Constructor.
    *
    * @param aIcon
    *        Icon to be fetched and associated.
    * @param aPage
    *        Page to which associate the icon.
-   * @param aDBConn
-   *        Database connection to use.
    * @param aCallback
    *        Function to be called when the fetch-and-associate process finishes.
    */
   AsyncFetchAndSetIconForPage(IconData& aIcon,
                               PageData& aPage,
-                              nsCOMPtr<mozIStorageConnection>& aDBConn,
-                              nsRefPtr<nsFaviconService>& aFaviconSvc,
                               nsCOMPtr<nsIFaviconDataCallback>& aCallback);
 
   virtual ~AsyncFetchAndSetIconForPage();
 
 protected:
   IconData mIcon;
   PageData mPage;
 };
@@ -210,25 +192,21 @@ public:
 
   /**
    * Constructor.
    *
    * @param aIcon
    *        Icon to be fetched and associated.
    * @param aPage
    *        Page to which associate the icon.
-   * @param aDBConn
-   *        Database connection to use.
    * @param aCallback
    *        Function to be called when the fetch-and-associate process finishes.
    */
   AsyncFetchAndSetIconFromNetwork(IconData& aIcon,
                                   PageData& aPage,
-                                  nsCOMPtr<mozIStorageConnection>& aDBConn,
-                                  nsRefPtr<nsFaviconService>& aFaviconSvc,
                                   nsCOMPtr<nsIFaviconDataCallback>& aCallback);
 
   virtual ~AsyncFetchAndSetIconFromNetwork();
 
 protected:
   IconData mIcon;
   PageData mPage;
   nsCOMPtr<nsIChannel> mChannel;
@@ -245,25 +223,21 @@ public:
 
   /**
    * Constructor.
    *
    * @param aIcon
    *        Icon to be associated.
    * @param aPage
    *        Page to which associate the icon.
-   * @param aDBConn
-   *        Database connection to use.
    * @param aCallback
    *        Function to be called when the associate process finishes.
    */
   AsyncAssociateIconToPage(IconData& aIcon,
                            PageData& aPage,
-                           nsCOMPtr<mozIStorageConnection>& aDBConn,
-                           nsRefPtr<nsFaviconService>& aFaviconSvc,
                            nsCOMPtr<nsIFaviconDataCallback>& aCallback);
 
   virtual ~AsyncAssociateIconToPage();
 
 protected:
   IconData mIcon;
   PageData mPage;
 };
@@ -277,40 +251,31 @@ class AsyncGetFaviconURLForPage : public
 public:
   NS_DECL_NSIRUNNABLE
 
   /**
    * Creates the event and dispatches it to the I/O thread.
    *
    * @param aPageURI
    *        URL of the page whose favicon's URL we're fetching
-   * @param aDBConn
-   *        database connection to use
    * @param aCallback
    *        function to be called once the URL is retrieved from the database
    */
   static nsresult start(nsIURI* aPageURI,
-                        nsCOMPtr<mozIStorageConnection>& aDBConn,
                         nsIFaviconDataCallback* aCallback);
 
   /**
    * Constructor.
    *
    * @param aPageSpec
    *        URL of the page whose favicon's URL we're fetching
-   * @param aDBConn
-   *        database connection to use
-   * @param aFaviconSvc
-   *        the favicon service to query
    * @param aCallback
    *        function to be called once the URL is retrieved from the database
    */
   AsyncGetFaviconURLForPage(const nsACString& aPageSpec,
-                            nsCOMPtr<mozIStorageConnection>& aDBConn,
-                            nsRefPtr<nsFaviconService>& aFaviconSvc,
                             nsCOMPtr<nsIFaviconDataCallback>& aCallback);
 
   virtual ~AsyncGetFaviconURLForPage();
 
 private:
   nsCString mPageSpec;
 };
 
@@ -324,40 +289,31 @@ class AsyncGetFaviconDataForPage : publi
 public:
   NS_DECL_NSIRUNNABLE
 
   /**
    * Creates the event and dispatches it to the I/O thread.
    *
    * @param aPageURI
    *        URL of the page whose favicon URL and data we're fetching
-   * @param aDBConn
-   *        database connection to use
    * @param aCallback
    *        function to be called once the URL and data is retrieved from the database
    */
   static nsresult start(nsIURI* aPageURI,
-                        nsCOMPtr<mozIStorageConnection>& aDBConn,
                         nsIFaviconDataCallback* aCallback);
 
   /**
    * Constructor.
    *
    * @param aPageSpec
    *        URL of the page whose favicon URL and data we're fetching
-   * @param aDBConn
-   *        database connection to use
-   * @param aFaviconSvc
-   *        the favicon service to query
    * @param aCallback
    *        function to be called once the URL is retrieved from the database
    */
   AsyncGetFaviconDataForPage(const nsACString& aPageSpec,
-                             nsCOMPtr<mozIStorageConnection>& aDBConn,
-                             nsRefPtr<nsFaviconService>& aFaviconSvc,
                              nsCOMPtr<nsIFaviconDataCallback>& aCallback);
 
   virtual ~AsyncGetFaviconDataForPage();
 
 private:
   nsCString mPageSpec;
 };
 
@@ -366,18 +322,16 @@ private:
  */
 class NotifyIconObservers : public AsyncFaviconHelperBase
 {
 public:
   NS_DECL_NSIRUNNABLE
 
   NotifyIconObservers(IconData& aIcon,
                       PageData& aPage,
-                      nsCOMPtr<mozIStorageConnection>& aDBConn,
-                      nsRefPtr<nsFaviconService>& aFaviconSvc,
                       nsCOMPtr<nsIFaviconDataCallback>& aCallback);
   virtual ~NotifyIconObservers();
 
 protected:
   IconData mIcon;
   PageData mPage;
 };
 
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/Database.cpp
@@ -0,0 +1,1398 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Places code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Marco Bonardo <mak77@bonardo.net>
+ *
+ * Original contributor(s) of code moved from nsNavHistory.cpp:
+ *   Brett Wilson <brettw@gmail.com> (original author)
+ *   Dietrich Ayala <dietrich@mozilla.com>
+ *   Seth Spitzer <sspitzer@mozilla.com>
+ *   Asaf Romano <mano@mozilla.com>
+ *   Marco Bonardo <mak77@bonardo.net>
+ *   Edward Lee <edward.lee@engineering.uiuc.edu>
+ *   Michael Ventnor <m.ventnor@gmail.com>
+ *   Ehsan Akhgari <ehsan.akhgari@gmail.com>
+ *   Drew Willcoxon <adw@mozilla.com>
+ *   Philipp von Weitershausen <philipp@weitershausen.de>
+ *   Paolo Amadini <http://www.amadzone.org/>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * 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 ***** */
+
+#include "Database.h"
+
+#include "nsINavBookmarksService.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsILocalFile.h"
+
+#include "nsNavHistory.h"
+#include "nsPlacesTables.h"
+#include "nsPlacesIndexes.h"
+#include "nsPlacesTriggers.h"
+#include "nsPlacesMacros.h"
+#include "SQLFunctions.h"
+#include "Helpers.h"
+
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsDirectoryServiceUtils.h"
+#include "prsystem.h"
+#include "nsPrintfCString.h"
+#include "mozilla/Util.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Services.h"
+
+// Time between corrupt database backups.
+#define RECENT_BACKUP_TIME_MICROSEC (PRInt64)86400 * PR_USEC_PER_SEC // 24H
+
+// Filename of the database.
+#define DATABASE_FILENAME NS_LITERAL_STRING("places.sqlite")
+// Filename used to backup corrupt databases.
+#define DATABASE_CORRUPT_FILENAME NS_LITERAL_STRING("places.sqlite.corrupt")
+
+// Set when the database file was found corrupt by a previous maintenance.
+#define PREF_FORCE_DATABASE_REPLACEMENT "places.database.replaceOnStartup"
+// Set to the calculated optimal size of the database.  This is a target size
+// used to evaluate history limits.  It's not mandatory.
+#define PREF_OPTIMAL_DATABASE_SIZE "places.history.expiration.transient_optimal_database_size"
+
+// To calculate the cache size we take into account the available physical
+// memory and the current database size.  This is the percentage of memory
+// we reserve for the former case.
+#define DATABASE_CACHE_TO_MEMORY_PERC 2
+// The minimum size of the cache.  We should never work without a cache, since
+// that would badly hurt WAL journaling mode.
+#define DATABASE_CACHE_MIN_BYTES (PRUint64)5242880 // 5MiB
+// We calculate an optimal database size, based on hardware specs.  This
+// pertains more to expiration, but the code is pretty much the same used for
+// cache_size, so it's here to reduce code duplication.
+// This percentage of disk size is used to protect against calculating a too
+// large size on disks with tiny quota or available space.
+#define DATABASE_TO_DISK_PERC 2
+// Maximum size of the optimal database.  High-end hardware has plenty of
+// memory and disk space, but performances don't grow linearly.
+#define DATABASE_MAX_SIZE (PRInt64)167772160 // 160MiB
+// If the physical memory size is not available, use MEMSIZE_FALLBACK_BYTES
+// instead.  Must stay in sync with the code in nsPlacesExpiration.js.
+#define MEMSIZE_FALLBACK_BYTES 268435456 // 256 M
+
+// Maximum size for the WAL file.  It should be small enough since in case of
+// crashes we could lose all the transactions in the file.  But a too small
+// file could hurt performance.
+#define DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES 512
+
+#define BYTES_PER_MEBIBYTE 1048576
+
+// Old Sync GUID annotation.
+#define SYNCGUID_ANNO NS_LITERAL_CSTRING("sync/guid")
+
+using namespace mozilla;
+
+namespace mozilla {
+namespace places {
+
+namespace {
+
+////////////////////////////////////////////////////////////////////////////////
+//// Helpers
+
+/**
+ * Checks whether exists a database backup created not longer than
+ * RECENT_BACKUP_TIME_MICROSEC ago.
+ */
+bool
+hasRecentCorruptDB()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<nsIFile> profDir;
+  NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR, getter_AddRefs(profDir));
+  NS_ENSURE_TRUE(profDir, false);
+  nsCOMPtr<nsISimpleEnumerator> entries;
+  profDir->GetDirectoryEntries(getter_AddRefs(entries));
+  NS_ENSURE_TRUE(entries, false);
+  bool hasMore;
+  while (NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) {
+    nsCOMPtr<nsISupports> next;
+    entries->GetNext(getter_AddRefs(next));
+    NS_ENSURE_TRUE(next, false);
+    nsCOMPtr<nsIFile> currFile = do_QueryInterface(next);
+    NS_ENSURE_TRUE(currFile, false);
+
+    nsAutoString leafName;
+    if (NS_SUCCEEDED(currFile->GetLeafName(leafName)) &&
+        leafName.Length() >= DATABASE_CORRUPT_FILENAME.Length() &&
+        leafName.Find(".corrupt", DATABASE_FILENAME.Length()) != -1) {
+      PRInt64 lastMod = 0;
+      currFile->GetLastModifiedTime(&lastMod);
+      NS_ENSURE_TRUE(lastMod > 0, false);
+      return (PR_Now() - lastMod) > RECENT_BACKUP_TIME_MICROSEC;
+    }
+  }
+  return false;
+}
+
+/**
+ * Updates sqlite_stat1 table through ANALYZE.
+ * Since also nsPlacesExpiration.js executes ANALYZE, the analyzed tables
+ * must be the same in both components.  So ensure they are in sync.
+ *
+ * @param aDBConn
+ *        The database connection.
+ */
+nsresult
+updateSQLiteStatistics(mozIStorageConnection* aDBConn)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<mozIStorageAsyncStatement> analyzePlacesStmt;
+  aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
+    "ANALYZE moz_places"
+  ), getter_AddRefs(analyzePlacesStmt));
+  NS_ENSURE_STATE(analyzePlacesStmt);
+  nsCOMPtr<mozIStorageAsyncStatement> analyzeBookmarksStmt;
+  aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
+    "ANALYZE moz_bookmarks"
+  ), getter_AddRefs(analyzeBookmarksStmt));
+  NS_ENSURE_STATE(analyzeBookmarksStmt);
+  nsCOMPtr<mozIStorageAsyncStatement> analyzeVisitsStmt;
+  aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
+    "ANALYZE moz_historyvisits"
+  ), getter_AddRefs(analyzeVisitsStmt));
+  NS_ENSURE_STATE(analyzeVisitsStmt);
+  nsCOMPtr<mozIStorageAsyncStatement> analyzeInputStmt;
+  aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
+    "ANALYZE moz_inputhistory"
+  ), getter_AddRefs(analyzeInputStmt));
+  NS_ENSURE_STATE(analyzeInputStmt);
+
+  mozIStorageBaseStatement *stmts[] = {
+    analyzePlacesStmt,
+    analyzeBookmarksStmt,
+    analyzeVisitsStmt,
+    analyzeInputStmt
+  };
+
+  nsCOMPtr<mozIStoragePendingStatement> ps;
+  (void)aDBConn->ExecuteAsync(stmts, ArrayLength(stmts), nsnull,
+                              getter_AddRefs(ps));
+  return NS_OK;
+}
+
+/**
+ * Sets the connection journal mode to one of the JOURNAL_* types.
+ *
+ * @param aDBConn
+ *        The database connection.
+ * @param aJournalMode
+ *        One of the JOURNAL_* types.
+ * @returns the current journal mode.
+ * @note this may return a different journal mode than the required one, since
+ *       setting it may fail.
+ */
+enum JournalMode
+SetJournalMode(nsCOMPtr<mozIStorageConnection>& aDBConn,
+                             enum JournalMode aJournalMode)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCAutoString journalMode;
+  switch (aJournalMode) {
+    default:
+      MOZ_ASSERT("Trying to set an unknown journal mode.");
+      // Fall through to the default DELETE journal.
+    case JOURNAL_DELETE:
+      journalMode.AssignLiteral("delete");
+      break;
+    case JOURNAL_TRUNCATE:
+      journalMode.AssignLiteral("truncate");
+      break;
+    case JOURNAL_MEMORY:
+      journalMode.AssignLiteral("memory");
+      break;
+    case JOURNAL_WAL:
+      journalMode.AssignLiteral("wal");
+      break;
+  }
+
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsCAutoString query("PRAGMA journal_mode = ");
+  query.Append(journalMode);
+  aDBConn->CreateStatement(query, getter_AddRefs(statement));
+  NS_ENSURE_TRUE(statement, JOURNAL_DELETE);
+
+  bool hasResult = false;
+  if (NS_SUCCEEDED(statement->ExecuteStep(&hasResult)) && hasResult &&
+      NS_SUCCEEDED(statement->GetUTF8String(0, journalMode))) {
+    if (journalMode.EqualsLiteral("delete")) {
+      return JOURNAL_DELETE;
+    }
+    if (journalMode.EqualsLiteral("truncate")) {
+      return JOURNAL_TRUNCATE;
+    }
+    if (journalMode.EqualsLiteral("memory")) {
+      return JOURNAL_MEMORY;
+    }
+    if (journalMode.EqualsLiteral("wal")) {
+      return JOURNAL_WAL;
+    }
+    // This is an unknown journal.
+    MOZ_ASSERT(true);
+  }
+
+  return JOURNAL_DELETE;
+}
+
+} // Anonymous namespace
+
+////////////////////////////////////////////////////////////////////////////////
+//// Database
+
+PLACES_FACTORY_SINGLETON_IMPLEMENTATION(Database, gDatabase)
+
+NS_IMPL_THREADSAFE_ISUPPORTS2(Database
+, nsIObserver
+, nsISupportsWeakReference
+)
+
+Database::Database()
+  : mMainThreadStatements(mMainConn)
+  , mMainThreadAsyncStatements(mMainConn)
+  , mAsyncThreadStatements(mMainConn)
+  , mDBPageSize(0)
+  , mCurrentJournalMode(JOURNAL_DELETE)
+  , mDatabaseStatus(nsINavHistoryService::DATABASE_STATUS_OK)
+  , mShuttingDown(false)
+{
+  // Attempting to create two instances of the service?
+  MOZ_ASSERT(!gDatabase);
+  gDatabase = this;
+}
+
+Database::~Database()
+{
+  // Check to make sure it's us, in case somebody wrongly creates an extra
+  // instance of this singleton class.
+  MOZ_ASSERT(gDatabase == this);
+
+  // Remove the static reference to the service.
+  if (gDatabase == this) {
+    gDatabase = nsnull;
+  }
+}
+
+nsresult
+Database::Init()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsCOMPtr<mozIStorageService> storage =
+    do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
+  NS_ENSURE_STATE(storage);
+
+  // Init the database file and connect to it.
+  bool databaseCreated = false;
+  nsresult rv = InitDatabaseFile(storage, &databaseCreated);
+  if (NS_SUCCEEDED(rv) && databaseCreated) {
+    mDatabaseStatus = nsINavHistoryService::DATABASE_STATUS_CREATE;
+  }
+  else if (rv == NS_ERROR_FILE_CORRUPTED) {
+    // The database is corrupt, backup and replace it with a new one.
+    mDatabaseStatus = nsINavHistoryService::DATABASE_STATUS_CORRUPT;
+    rv = BackupAndReplaceDatabaseFile(storage);
+    // Fallback to catch-all handler, that notifies a database locked failure.
+  }
+
+  // If the database connection still cannot be opened, it may just be locked
+  // by third parties.  Send out a notification and interrupt initialization.
+  if (NS_FAILED(rv)) {
+    nsRefPtr<PlacesEvent> lockedEvent = new PlacesEvent(TOPIC_DATABASE_LOCKED);
+    (void)NS_DispatchToMainThread(lockedEvent);
+    return rv;
+  }
+
+  // Initialize the database schema.  In case of failure the existing schema is
+  // is corrupt or incoherent, thus the database should be replaced.
+  bool databaseMigrated = false;
+  rv = InitSchema(&databaseMigrated);
+  if (NS_FAILED(rv)) {
+    mDatabaseStatus = nsINavHistoryService::DATABASE_STATUS_CORRUPT;
+    rv = BackupAndReplaceDatabaseFile(storage);
+    NS_ENSURE_SUCCESS(rv, rv);
+    // Try to initialize the schema again on the new database.
+    rv = InitSchema(&databaseMigrated);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  if (databaseMigrated) {
+    mDatabaseStatus = nsINavHistoryService::DATABASE_STATUS_UPGRADED;
+  }
+
+  if (mDatabaseStatus != nsINavHistoryService::DATABASE_STATUS_OK) {
+    rv = updateSQLiteStatistics(MainConn());
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Initialize here all the items that are not part of the on-disk database,
+  // like views, temp triggers or temp tables.  The database should not be
+  // considered corrupt if any of the following fails.
+
+  rv = InitTempTriggers();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Notify we have finished database initialization.
+  // Enqueue the notification, so if we init another service that requires
+  // nsNavHistoryService we don't recursive try to get it.
+  nsRefPtr<PlacesEvent> completeEvent =
+    new PlacesEvent(TOPIC_PLACES_INIT_COMPLETE);
+  rv = NS_DispatchToMainThread(completeEvent);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Finally observe profile shutdown notifications.
+  nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
+  if (os) {
+    (void)os->AddObserver(this, TOPIC_PROFILE_CHANGE_TEARDOWN, true);
+    (void)os->AddObserver(this, TOPIC_PROFILE_BEFORE_CHANGE, true);
+  }
+
+  return NS_OK;
+}
+
+nsresult
+Database::InitDatabaseFile(nsCOMPtr<mozIStorageService>& aStorage,
+                           bool* aNewDatabaseCreated)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  *aNewDatabaseCreated = false;
+
+  nsCOMPtr<nsIFile> databaseFile;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                                       getter_AddRefs(databaseFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = databaseFile->Append(DATABASE_FILENAME);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool databaseFileExists = false;
+  rv = databaseFile->Exists(&databaseFileExists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (databaseFileExists &&
+      Preferences::GetBool(PREF_FORCE_DATABASE_REPLACEMENT, false)) {
+    // If this pref is set, Maintenance required a database replacement, due to
+    // integrity corruption.
+    // Be sure to clear the pref to avoid handling it more than once.
+    (void)Preferences::ClearUser(PREF_FORCE_DATABASE_REPLACEMENT);
+
+    return NS_ERROR_FILE_CORRUPTED;
+  }
+
+  // Open the database file.  If it does not exist a new one will be created.
+  // Use an unshared connection, it will consume more memory but avoid shared
+  // cache contentions across threads.
+  rv = aStorage->OpenUnsharedDatabase(databaseFile, getter_AddRefs(mMainConn));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  *aNewDatabaseCreated = !databaseFileExists;
+  return NS_OK;
+}
+
+nsresult
+Database::BackupAndReplaceDatabaseFile(nsCOMPtr<mozIStorageService>& aStorage)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  nsCOMPtr<nsIFile> profDir;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                                       getter_AddRefs(profDir));
+  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<nsIFile> databaseFile;
+  rv = profDir->Clone(getter_AddRefs(databaseFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = databaseFile->Append(DATABASE_FILENAME);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // If we have
+  // already failed in the last 24 hours avoid to create another corrupt file,
+  // since doing so, in some situation, could cause us to create a new corrupt
+  // file at every try to access any Places service.  That is bad because it
+  // would quickly fill the user's disk space without any notice.
+  if (!hasRecentCorruptDB()) {
+    nsCOMPtr<nsIFile> backup;
+    (void)aStorage->BackupDatabaseFile(databaseFile, DATABASE_CORRUPT_FILENAME,
+                                       profDir, getter_AddRefs(backup));
+  }
+
+  // Close database connection if open.
+  if (mMainConn) {
+    // If there's any not finalized statement or this fails for any reason
+    // we won't be able to remove the database.
+    rv = mMainConn->Close();
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Remove the broken database.
+  rv = databaseFile->Remove(false);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Create a new database file.
+  // Use an unshared connection, it will consume more memory but avoid shared
+  // cache contentions across threads.
+  rv = aStorage->OpenUnsharedDatabase(databaseFile, getter_AddRefs(mMainConn));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+Database::InitSchema(bool* aDatabaseMigrated)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  *aDatabaseMigrated = false;
+
+  // WARNING: any statement executed before setting the journal mode must be
+  // finalized, since SQLite doesn't allow changing the journal mode if there
+  // is any outstanding statement.
+
+  {
+    // Get the page size.  This may be different than the default if the
+    // database file already existed with a different page size.
+    nsCOMPtr<mozIStorageStatement> statement;
+    nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+      "PRAGMA page_size"
+    ), getter_AddRefs(statement));
+    NS_ENSURE_SUCCESS(rv, rv);
+    bool hasResult = false;
+    rv = statement->ExecuteStep(&hasResult);
+    NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && hasResult, NS_ERROR_FAILURE);
+    rv = statement->GetInt32(0, &mDBPageSize);
+    NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && mDBPageSize > 0, NS_ERROR_UNEXPECTED);
+  }
+
+  // Ensure that temp tables are held in memory, not on disk.
+  nsresult rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "PRAGMA temp_store = MEMORY"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // We want to work with a cache that is at a maximum half of the database
+  // size.  We also want it to respect the available memory size.
+
+  // Calculate memory size, fallback to a meaningful value if it fails.
+  PRUint64 memSizeBytes = PR_GetPhysicalMemorySize();
+  if (memSizeBytes == 0) {
+    memSizeBytes = MEMSIZE_FALLBACK_BYTES;
+  }
+
+  PRUint64 cacheSize = memSizeBytes * DATABASE_CACHE_TO_MEMORY_PERC / 100;
+
+  // Calculate an optimal database size for expiration purposes.
+  // We usually want to work with a cache that is half the database size.
+  // Limit the size to avoid extreme values on high-end hardware.
+  PRInt64 optimalDatabaseSize = NS_MIN(static_cast<PRInt64>(cacheSize) * 2,
+                                       DATABASE_MAX_SIZE);
+
+  // Protect against a full disk or tiny quota.
+  PRInt64 diskAvailableBytes = 0;
+  nsCOMPtr<nsIFile> databaseFile;
+  mMainConn->GetDatabaseFile(getter_AddRefs(databaseFile));
+  NS_ENSURE_STATE(databaseFile);
+  nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(databaseFile);
+  if (localFile &&
+      NS_SUCCEEDED(localFile->GetDiskSpaceAvailable(&diskAvailableBytes)) &&
+      diskAvailableBytes > 0) {
+    optimalDatabaseSize = NS_MIN(optimalDatabaseSize,
+                                 diskAvailableBytes * DATABASE_TO_DISK_PERC / 100);
+  }
+
+  // Share the calculated size if it's meaningful.
+  if (optimalDatabaseSize < PR_INT32_MAX) {
+    (void)Preferences::SetInt(PREF_OPTIMAL_DATABASE_SIZE,
+                              static_cast<PRInt32>(optimalDatabaseSize));
+  }
+
+  // Get the current database size. Due to chunked growth we have to use
+  // page_count to evaluate it.
+  PRUint64 databaseSizeBytes = 0;
+  {
+    nsCOMPtr<mozIStorageStatement> statement;
+    nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+      "PRAGMA page_count"
+    ), getter_AddRefs(statement));
+    NS_ENSURE_SUCCESS(rv, rv);
+    bool hasResult = false;
+    rv = statement->ExecuteStep(&hasResult);
+    NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && hasResult, NS_ERROR_FAILURE);
+    PRInt32 pageCount = 0;
+    rv = statement->GetInt32(0, &pageCount);
+    NS_ENSURE_SUCCESS(rv, rv);
+    databaseSizeBytes = pageCount * mDBPageSize;
+  }
+
+  // Set cache to a maximum of half the database size.
+  cacheSize = NS_MIN(cacheSize, databaseSizeBytes / 2);
+  // Ensure we never work without a minimum cache.
+  cacheSize = NS_MAX(cacheSize, DATABASE_CACHE_MIN_BYTES);
+
+  // Set the number of cached pages.
+  // We don't use PRAGMA default_cache_size, since the database could be moved
+  // among different devices and the value would adapt accordingly.
+  nsCAutoString cacheSizePragma("PRAGMA cache_size = ");
+  cacheSizePragma.AppendInt(cacheSize / mDBPageSize);
+  rv = mMainConn->ExecuteSimpleSQL(cacheSizePragma);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Be sure to set journal mode after page_size.  WAL would prevent the change
+  // otherwise.
+  if (NS_SUCCEEDED(SetJournalMode(mMainConn, JOURNAL_WAL))) {
+    // Set the WAL journal size limit.  We want it to be small, since in
+    // synchronous = NORMAL mode a crash could cause loss of all the
+    // transactions in the journal.  For added safety we will also force
+    // checkpointing at strategic moments.
+    PRInt32 checkpointPages =
+      static_cast<PRInt32>(DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES * 1024 / mDBPageSize);
+    nsCAutoString checkpointPragma("PRAGMA wal_autocheckpoint = ");
+    checkpointPragma.AppendInt(checkpointPages);
+    rv = mMainConn->ExecuteSimpleSQL(checkpointPragma);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  else {
+    // Ignore errors, if we fail here the database could be considered corrupt
+    // and we won't be able to go on, even if it's just matter of a bogus file
+    // system.  The default mode (DELETE) will be fine in such a case.
+    (void)SetJournalMode(mMainConn, JOURNAL_TRUNCATE);
+
+    // Set synchronous to FULL to ensure maximum data integrity, even in
+    // case of crashes or unclean shutdowns.
+    rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "PRAGMA synchronous = FULL"));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Grow places in 10MiB increments
+  (void)mMainConn->SetGrowthIncrement(10 * BYTES_PER_MEBIBYTE, EmptyCString());
+
+  // We use our functions during migration, so initialize them now.
+  rv = InitFunctions();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Get the database schema version.
+  PRInt32 currentSchemaVersion;
+  rv = mMainConn->GetSchemaVersion(&currentSchemaVersion);
+  NS_ENSURE_SUCCESS(rv, rv);
+  bool databaseInitialized = currentSchemaVersion > 0;
+
+  if (databaseInitialized && currentSchemaVersion == DATABASE_SCHEMA_VERSION) {
+    // The database is up to date and ready to go.
+    return NS_OK;
+  }
+
+  // We are going to update the database, so everything from now on should be in
+  // a transaction for performances.
+  mozStorageTransaction transaction(mMainConn, false);
+
+  if (databaseInitialized) {
+    // Migration How-to:
+    //
+    // 1. increment PLACES_SCHEMA_VERSION.
+    // 2. implement a method that performs upgrade to your version from the
+    //    previous one.
+    //
+    // NOTE: The downgrade process is pretty much complicated by the fact old
+    //       versions cannot know what a new version is going to implement.
+    //       The only thing we will do for downgrades is setting back the schema
+    //       version, so that next upgrades will run again the migration step.
+
+    if (currentSchemaVersion < DATABASE_SCHEMA_VERSION) {
+      *aDatabaseMigrated = true;
+
+      // Firefox 3.0 uses schema version 6.
+
+      if (currentSchemaVersion < 7) {
+        rv = MigrateV7Up();
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+
+      if (currentSchemaVersion < 8) {
+        rv = MigrateV8Up();
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+
+      // Firefox 3.5 uses schema version 8.
+
+      if (currentSchemaVersion < 9) {
+        rv = MigrateV9Up();
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+
+      if (currentSchemaVersion < 10) {
+        rv = MigrateV10Up();
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+
+      // Firefox 3.6 uses schema version 10.
+
+      if (currentSchemaVersion < 11) {
+        rv = MigrateV11Up();
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+
+      // Firefox 4 uses schema version 11.
+
+      // Firefox 8 uses schema version 12.
+
+      // Schema Upgrades must add migration code here.
+    }
+  }
+  else {
+    // This is a new database, so we have to create all the tables and indices.
+
+    // moz_places.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_PLACES);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_URL);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_FAVICON);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_REVHOST);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_VISITCOUNT);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_FRECENCY);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_LASTVISITDATE);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_GUID);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // moz_historyvisits.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_HISTORYVISITS);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_PLACEDATE);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_FROMVISIT);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_VISITDATE);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // moz_inputhistory.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_INPUTHISTORY);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // moz_bookmarks.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_BOOKMARKS);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_PLACETYPE);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_PARENTPOSITION);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_PLACELASTMODIFIED);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_GUID);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // moz_bookmarks_roots.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_BOOKMARKS_ROOTS);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // moz_keywords.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_KEYWORDS);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_KEYWORD_VALIDITY_TRIGGER);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // moz_favicons.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_FAVICONS);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // moz_anno_attributes.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_ANNO_ATTRIBUTES);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // moz_annos.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_ANNOS);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_ANNOS_PLACEATTRIBUTE);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // moz_items_annos.
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_MOZ_ITEMS_ANNOS);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_ITEMSANNOS_PLACEATTRIBUTE);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Set the schema version to the current one.
+  rv = mMainConn->SetSchemaVersion(DATABASE_SCHEMA_VERSION);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = transaction.Commit();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  ForceWALCheckpoint();
+
+  // ANY FAILURE IN THIS METHOD WILL CAUSE US TO MARK THE DATABASE AS CORRUPT
+  // AND TRY TO REPLACE IT.
+  // DO NOT PUT HERE ANYTHING THAT IS NOT RELATED TO INITIALIZATION OR MODIFYING
+  // THE DISK DATABASE.
+
+  return NS_OK;
+}
+
+nsresult
+Database::InitFunctions()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsresult rv = GetUnreversedHostFunction::create(mMainConn);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = MatchAutoCompleteFunction::create(mMainConn);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = CalculateFrecencyFunction::create(mMainConn);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = GenerateGUIDFunction::create(mMainConn);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+Database::InitTempTriggers()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  nsresult rv = mMainConn->ExecuteSimpleSQL(CREATE_HISTORYVISITS_AFTERINSERT_TRIGGER);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = mMainConn->ExecuteSimpleSQL(CREATE_HISTORYVISITS_AFTERDELETE_TRIGGER);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+Database::CheckAndUpdateGUIDs()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // First, import any bookmark guids already set by Sync.
+  nsCOMPtr<mozIStorageStatement> updateStmt;
+  nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "UPDATE moz_bookmarks "
+    "SET guid = :guid "
+    "WHERE id = :item_id "
+  ), getter_AddRefs(updateStmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<mozIStorageStatement> stmt;
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT item_id, content "
+    "FROM moz_items_annos "
+    "JOIN moz_anno_attributes "
+    "WHERE name = :anno_name "
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
+                                  SYNCGUID_ANNO);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool hasResult;
+  while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
+    PRInt64 itemId;
+    rv = stmt->GetInt64(0, &itemId);
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsCAutoString guid;
+    rv = stmt->GetUTF8String(1, guid);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // If we have an invalid guid, we don't need to do any more work.
+    if (!IsValidGUID(guid)) {
+      continue;
+    }
+
+    mozStorageStatementScoper updateScoper(updateStmt);
+    rv = updateStmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), itemId);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = updateStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("guid"), guid);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = updateStmt->Execute();
+    if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
+      // We just tried to insert a duplicate guid.  Ignore this error, and we
+      // will generate a new one next.
+      continue;
+    }
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Now, remove all the bookmark guid annotations that we just imported.
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "DELETE FROM moz_items_annos "
+    "WHERE anno_attribute_id = ( "
+      "SELECT id "
+      "FROM moz_anno_attributes "
+      "WHERE name = :anno_name "
+    ") "
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
+                                  SYNCGUID_ANNO);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = stmt->Execute();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Next, generate guids for any bookmark that does not already have one.
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "UPDATE moz_bookmarks "
+    "SET guid = GENERATE_GUID() "
+    "WHERE guid IS NULL "
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = stmt->Execute();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Now, import any history guids already set by Sync.
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "UPDATE moz_places "
+    "SET guid = :guid "
+    "WHERE id = :place_id "
+  ), getter_AddRefs(updateStmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT place_id, content "
+    "FROM moz_annos "
+    "JOIN moz_anno_attributes "
+    "WHERE name = :anno_name "
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
+                                  SYNCGUID_ANNO);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
+    PRInt64 placeId;
+    rv = stmt->GetInt64(0, &placeId);
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsCAutoString guid;
+    rv = stmt->GetUTF8String(1, guid);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // If we have an invalid guid, we don't need to do any more work.
+    if (!IsValidGUID(guid)) {
+      continue;
+    }
+
+    mozStorageStatementScoper updateScoper(updateStmt);
+    rv = updateStmt->BindInt64ByName(NS_LITERAL_CSTRING("place_id"), placeId);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = updateStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("guid"), guid);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = updateStmt->Execute();
+    if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
+      // We just tried to insert a duplicate guid.  Ignore this error, and we
+      // will generate a new one next.
+      continue;
+    }
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Now, remove all the place guid annotations that we just imported.
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "DELETE FROM moz_annos "
+    "WHERE anno_attribute_id = ( "
+      "SELECT id "
+      "FROM moz_anno_attributes "
+      "WHERE name = :anno_name "
+    ") "
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
+                                  SYNCGUID_ANNO);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = stmt->Execute();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Finally, generate guids for any places that do not already have one.
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+    "UPDATE moz_places "
+    "SET guid = GENERATE_GUID() "
+    "WHERE guid IS NULL "
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = stmt->Execute();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+Database::MigrateV7Up() 
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mozStorageTransaction transaction(mMainConn, false);
+
+  // 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.
+  bool lastModIndexExists = false;
+  nsresult rv = mMainConn->IndexExists(
+    NS_LITERAL_CSTRING("moz_bookmarks_itemlastmodifiedindex"),
+    &lastModIndexExists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!lastModIndexExists) {
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_PLACELASTMODIFIED);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // We need to do a one-time change of the moz_historyvisits.pageindex
+  // to speed up finding last visit date when joinin with moz_places.
+  // See bug 392399 for more details.
+  bool pageIndexExists = false;
+  rv = mMainConn->IndexExists(
+    NS_LITERAL_CSTRING("moz_historyvisits_pageindex"), &pageIndexExists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (pageIndexExists) {
+    // drop old index
+    rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP INDEX IF EXISTS moz_historyvisits_pageindex"));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // create the new multi-column index
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_PLACEDATE);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // for existing profiles, we may not have a frecency column
+  nsCOMPtr<mozIStorageStatement> hasFrecencyStatement;
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT frecency FROM moz_places"),
+    getter_AddRefs(hasFrecencyStatement));
+
+  if (NS_FAILED(rv)) {
+    // Add frecency column to moz_places, default to -1 so that all the
+    // frecencies are invalid
+    rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "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 = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_FRECENCY);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Invalidate all frecencies, since they need recalculation.
+    nsNavHistory* history = nsNavHistory::GetHistoryService();
+    NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
+    rv = history->invalidateFrecencies(EmptyCString());
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Temporary migration code for bug 396300
+  nsCOMPtr<mozIStorageStatement> moveUnfiledBookmarks;
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+      "UPDATE moz_bookmarks "
+      "SET parent = ("
+        "SELECT folder_id "
+        "FROM moz_bookmarks_roots "
+        "WHERE root_name = :root_name "
+      ") "
+      "WHERE type = :item_type "
+      "AND parent = ("
+        "SELECT folder_id "
+        "FROM moz_bookmarks_roots "
+        "WHERE root_name = :parent_name "
+      ")"),
+    getter_AddRefs(moveUnfiledBookmarks));
+  rv = moveUnfiledBookmarks->BindUTF8StringByName(
+    NS_LITERAL_CSTRING("root_name"), NS_LITERAL_CSTRING("unfiled")
+  );
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = moveUnfiledBookmarks->BindInt32ByName(
+    NS_LITERAL_CSTRING("item_type"), nsINavBookmarksService::TYPE_BOOKMARK
+  );
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = moveUnfiledBookmarks->BindUTF8StringByName(
+    NS_LITERAL_CSTRING("parent_name"), NS_LITERAL_CSTRING("places")
+  );
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = moveUnfiledBookmarks->Execute();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Create a statement to test for trigger creation
+  nsCOMPtr<mozIStorageStatement> triggerDetection;
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT name "
+      "FROM sqlite_master "
+      "WHERE type = 'trigger' "
+      "AND name = :trigger_name"),
+    getter_AddRefs(triggerDetection));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Check for existence
+  bool triggerExists;
+  rv = triggerDetection->BindUTF8StringByName(
+    NS_LITERAL_CSTRING("trigger_name"),
+    NS_LITERAL_CSTRING("moz_historyvisits_afterinsert_v1_trigger")
+  );
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = triggerDetection->ExecuteStep(&triggerExists);
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = triggerDetection->Reset();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // 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 = mMainConn->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 ") +
+              nsPrintfCString("(0,%d,%d,%d) ",
+                              nsINavHistoryService::TRANSITION_EMBED,
+                              nsINavHistoryService::TRANSITION_FRAMED_LINK,
+                              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->BindUTF8StringByName(
+    NS_LITERAL_CSTRING("trigger_name"),
+    NS_LITERAL_CSTRING("moz_bookmarks_beforedelete_v1_trigger")
+  );
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = triggerDetection->ExecuteStep(&triggerExists);
+  NS_ENSURE_SUCCESS(rv, rv);
+  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 = mMainConn->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"
+        ")"));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Now we create our trigger
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_KEYWORD_VALIDITY_TRIGGER);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return transaction.Commit();
+}
+
+
+nsresult
+Database::MigrateV8Up()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mozStorageTransaction transaction(mMainConn, false);
+
+  nsresult rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP TRIGGER IF EXISTS moz_historyvisits_afterinsert_v1_trigger"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP TRIGGER IF EXISTS moz_historyvisits_afterdelete_v1_trigger"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+
+  // bug #381795 - remove unused indexes
+  rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP INDEX IF EXISTS moz_places_titleindex"));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "DROP INDEX IF EXISTS moz_annos_item_idindex"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+
+  // Do a one-time re-creation of the moz_annos indexes (bug 415201)
+  bool oldIndexExists = false;
+  rv = mMainConn->IndexExists(NS_LITERAL_CSTRING("moz_annos_attributesindex"), &oldIndexExists);
+  NS_ENSURE_SUCCESS(rv, rv);
+  if (oldIndexExists) {
+    // drop old uri annos index
+    rv = mMainConn->ExecuteSimpleSQL(
+        NS_LITERAL_CSTRING("DROP INDEX moz_annos_attributesindex"));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // create new uri annos index
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_ANNOS_PLACEATTRIBUTE);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // drop old item annos index
+    rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "DROP INDEX IF EXISTS moz_items_annos_attributesindex"));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // create new item annos index
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_ITEMSANNOS_PLACEATTRIBUTE);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return transaction.Commit();
+}
+
+
+nsresult
+Database::MigrateV9Up()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  mozStorageTransaction transaction(mMainConn, false);
+  // Added in Bug 488966.  The last_visit_date column caches the last
+  // visit date, this enhances SELECT performances when we
+  // need to sort visits by visit date.
+  // The cached value is synced by triggers on every added or removed visit.
+  // See nsPlacesTriggers.h for details on the triggers.
+  bool oldIndexExists = false;
+  nsresult rv = mMainConn->IndexExists(
+    NS_LITERAL_CSTRING("moz_places_lastvisitdateindex"), &oldIndexExists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (!oldIndexExists) {
+    // Add last_visit_date column to moz_places.
+    rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "ALTER TABLE moz_places ADD last_visit_date INTEGER"));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_LASTVISITDATE);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // Now let's sync the column contents with real visit dates.
+    // This query can be really slow due to disk access, since it will basically
+    // dupe the table contents in the journal file, and then write them down
+    // in the database.
+    rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+        "UPDATE moz_places SET last_visit_date = "
+          "(SELECT MAX(visit_date) "
+           "FROM moz_historyvisits "
+           "WHERE place_id = moz_places.id)"));
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return transaction.Commit();
+}
+
+
+nsresult
+Database::MigrateV10Up()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // LastModified is set to the same value as dateAdded on item creation.
+  // This way we can use lastModified index to sort.
+  nsresult rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "UPDATE moz_bookmarks SET lastModified = dateAdded "
+      "WHERE lastModified IS NULL"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+
+nsresult
+Database::MigrateV11Up()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  // Temp tables are going away.
+  // For triggers correctness, every time we pass through this migration
+  // step, we must ensure correctness of visit_count values.
+  nsresult rv = mMainConn->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 ") +
+          nsPrintfCString("(0,%d,%d,%d) ",
+                          nsINavHistoryService::TRANSITION_EMBED,
+                          nsINavHistoryService::TRANSITION_FRAMED_LINK,
+                          nsINavHistoryService::TRANSITION_DOWNLOAD) +
+      NS_LITERAL_CSTRING(")")
+  );
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // For existing profiles, we may not have a moz_bookmarks.guid column
+  nsCOMPtr<mozIStorageStatement> hasGuidStatement;
+  rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+      "SELECT guid FROM moz_bookmarks"),
+    getter_AddRefs(hasGuidStatement));
+
+  if (NS_FAILED(rv)) {
+    // moz_bookmarks grew a guid column.  Add the column, but do not populate it
+    // with anything just yet.  We will do that soon.
+    rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "ALTER TABLE moz_bookmarks "
+      "ADD COLUMN guid TEXT"
+    ));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_GUID);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // moz_placess grew a guid column.  Add the column, but do not populate it
+    // with anything just yet.  We will do that soon.
+    rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "ALTER TABLE moz_places "
+      "ADD COLUMN guid TEXT"
+    ));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = mMainConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_GUID);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // We need to update our guids before we do any real database work.
+  rv = CheckAndUpdateGUIDs();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+void
+Database::Shutdown()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  MOZ_ASSERT(!mShuttingDown);
+
+  mMainThreadStatements.FinalizeStatements();
+  mMainThreadAsyncStatements.FinalizeStatements();
+
+  nsRefPtr< FinalizeStatementCacheProxy<mozIStorageStatement> > event =
+    new FinalizeStatementCacheProxy<mozIStorageStatement>(
+          mAsyncThreadStatements, NS_ISUPPORTS_CAST(nsIObserver*, this)
+        );
+  DispatchToAsyncThread(event);
+
+  nsRefPtr<PlacesEvent> closeListener =
+    new PlacesEvent(TOPIC_PLACES_CONNECTION_CLOSED);
+  (void)mMainConn->AsyncClose(closeListener);
+
+  // Don't set this earlier, otherwise some internal helper used on shutdown
+  // may bail out.
+  mShuttingDown = true;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+//// nsIObserver
+
+NS_IMETHODIMP
+Database::Observe(nsISupports *aSubject,
+                  const char *aTopic,
+                  const PRUnichar *aData)
+{
+  NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
+ 
+  if (strcmp(aTopic, TOPIC_PROFILE_CHANGE_TEARDOWN) == 0) {
+    // Tests simulating shutdown may cause multiple notifications.
+    if (mShuttingDown) {
+      return NS_OK;
+    }
+
+    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+    NS_ENSURE_STATE(os);
+
+    // If shutdown happens in the same mainthread loop as init, observers could
+    // handle the places-init-complete notification after xpcom-shutdown, when
+    // the connection does not exist anymore.  Removing those observers would
+    // be less expensive but may cause their RemoveObserver calls to throw.
+    // Thus notify the topic now, so they stop listening for it.
+    nsCOMPtr<nsISimpleEnumerator> e;
+    if (NS_SUCCEEDED(os->EnumerateObservers(TOPIC_PLACES_INIT_COMPLETE,
+                     getter_AddRefs(e))) && e) {
+      bool hasMore = false;
+      while (NS_SUCCEEDED(e->HasMoreElements(&hasMore)) && hasMore) {
+        nsCOMPtr<nsIObserver> observer;
+        if (NS_SUCCEEDED(e->GetNext(getter_AddRefs(observer)))) {
+          (void)observer->Observe(observer, TOPIC_PLACES_INIT_COMPLETE, nsnull);
+        }
+      }
+    }
+
+    // Notify all Places users that we are about to shutdown.
+    (void)os->NotifyObservers(nsnull, TOPIC_PLACES_SHUTDOWN, nsnull);
+  }
+
+  else if (strcmp(aTopic, TOPIC_PROFILE_BEFORE_CHANGE) == 0) {
+    // Tests simulating shutdown may cause re-entrance.
+    if (mShuttingDown) {
+      return NS_OK;
+    }
+
+    // Fire internal shutdown notifications.
+    nsCOMPtr<nsIObserverService> os = services::GetObserverService();
+    if (os) {
+      (void)os->NotifyObservers(nsnull, TOPIC_PLACES_WILL_CLOSE_CONNECTION, nsnull);
+    }
+
+#ifdef DEBUG
+    { // Sanity check for missing guids.
+      nsCOMPtr<mozIStorageStatement> stmt;
+      nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+        "SELECT 1 "
+        "FROM moz_places "
+        "WHERE guid IS NULL "
+        "UNION ALL "
+        "SELECT 1 "
+        "FROM moz_bookmarks "
+        "WHERE guid IS NULL "
+      ), getter_AddRefs(stmt));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      bool haveNullGuids;
+      rv = stmt->ExecuteStep(&haveNullGuids);
+      NS_ENSURE_SUCCESS(rv, rv);
+      NS_ASSERTION(!haveNullGuids,
+                   "Someone added an entry without adding a GUID!");
+    }
+#endif
+
+    // As the last step in the shutdown path, finalize the database handle.
+    Shutdown();
+  }
+
+  return NS_OK;
+}
+
+} // namespace places
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/Database.h
@@ -0,0 +1,320 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Places code.
+ *
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Marco Bonardo <mak77@bonardo.net> (Original Author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * 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 ***** */
+
+#ifndef mozilla_places_Database_h_
+#define mozilla_places_Database_h_
+
+#include "nsThreadUtils.h"
+#include "nsWeakReference.h"
+#include "nsIInterfaceRequestorUtils.h"
+#include "nsIObserver.h"
+#include "mozilla/storage.h"
+#include "mozilla/storage/StatementCache.h"
+
+// This is the schema version, update it at any schema change and add a
+// corresponding migrateVxx method below.
+#define DATABASE_SCHEMA_VERSION 12
+
+// Fired after Places inited.
+#define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
+// Fired when initialization fails due to a locked database.
+#define TOPIC_DATABASE_LOCKED "places-database-locked"
+// This topic is received when the profile is about to be lost.  Places does
+// initial shutdown work and notifies TOPIC_PLACES_SHUTDOWN to all listeners.
+// Any shutdown work that requires the Places APIs should happen here.
+#define TOPIC_PROFILE_CHANGE_TEARDOWN "profile-change-teardown"
+// This topic is received just before the profile is lost.  Places begins
+// shutting down the connection and notifies TOPIC_PLACES_WILL_CLOSE_CONNECTION
+// to all listeners.  Only critical database cleanups should happen here,
+// some APIs may bail out already.
+#define TOPIC_PROFILE_BEFORE_CHANGE "profile-before-change"
+// Fired when Places is shutting down.  Any code should stop accessing Places
+// APIs after this notification.  If you need to listen for Places shutdown
+// you should only use this notification, next ones are intended only for
+// internal Places use.
+#define TOPIC_PLACES_SHUTDOWN "places-shutdown"
+// For Internal use only.  Fired when connection is about to be closed, only
+// cleanup tasks should run at this stage, nothing should be added to the
+// database, nor APIs should be called.
+#define TOPIC_PLACES_WILL_CLOSE_CONNECTION "places-will-close-connection"
+// Fired when the connection has gone, nothing will work from now on.
+#define TOPIC_PLACES_CONNECTION_CLOSED "places-connection-closed"
+
+namespace mozilla {
+namespace places {
+
+enum JournalMode {
+  // Default SQLite journal mode.
+  JOURNAL_DELETE = 0
+  // Can reduce fsyncs on Linux when journal is deleted (See bug 460315).
+  // We fallback to this mode when WAL is unavailable.
+, JOURNAL_TRUNCATE
+  // Unsafe in case of crashes on database swap or low memory.
+, JOURNAL_MEMORY
+  // Can reduce number of fsyncs.  We try to use this mode by default.
+, JOURNAL_WAL
+};
+
+class Database : public nsIObserver
+               , public nsSupportsWeakReference
+{
+  typedef mozilla::storage::StatementCache<mozIStorageStatement> StatementCache;
+  typedef mozilla::storage::StatementCache<mozIStorageAsyncStatement> AsyncStatementCache;
+
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+
+  Database();
+
+  /**
+   * Initializes the database connection and the schema.
+   * In case of corruption the database is copied to a backup file and replaced.
+   */
+  nsresult Init();
+
+  /**
+   * Finalizes the cached statements and closes the database connection.
+   * A TOPIC_PLACES_CONNECTION_CLOSED notification is fired when done.
+   */
+  void Shutdown();
+
+  /**
+   * Getter to use when instantiating the class.
+   *
+   * @return Singleton instance of this class.
+   */
+  static already_AddRefed<Database> GetDatabase()
+  {
+    return GetSingleton();
+  }
+
+  /**
+   * Returns last known database status.
+   *
+   * @return one of the nsINavHistoryService::DATABASE_STATUS_* constants.
+   */
+  PRUint16 GetDatabaseStatus() const
+  {
+    return mDatabaseStatus;
+  }
+
+  /**
+   * Returns a pointer to the storage connection.
+   *
+   * @return The connection handle.
+   */
+  mozIStorageConnection* MainConn() const
+  {
+    return mMainConn;
+  }
+
+  /**
+   * Dispatches a runnable to the connection async thread, to be serialized
+   * with async statements.
+   *
+   * @param aEvent
+   *        The runnable to be dispatched.
+   */
+  void DispatchToAsyncThread(nsIRunnable* aEvent) const
+  {
+    if (mShuttingDown) {
+      return;
+    }
+    nsCOMPtr<nsIEventTarget> target = do_GetInterface(mMainConn);
+    if (target) {
+      (void)target->Dispatch(aEvent, NS_DISPATCH_NORMAL);
+    }
+  }
+
+  //////////////////////////////////////////////////////////////////////////////
+  //// Statements Getters.
+
+  /**
+   * Gets a cached synchronous statement.
+   *
+   * @param aQuery
+   *        SQL query literal.
+   * @return The cached statement.
+   * @note Always null check the result.
+   * @note Always use a scoper to reset the statement.
+   */
+  template<int N>
+  already_AddRefed<mozIStorageStatement>
+  GetStatement(const char (&aQuery)[N]) const
+  {
+    nsDependentCString query(aQuery, N - 1);
+    return GetStatement(query);
+  }
+
+  /**
+   * Gets a cached synchronous statement.
+   *
+   * @param aQuery
+   *        nsCString of SQL query.
+   * @return The cached statement.
+   * @note Always null check the result.
+   * @note Always use a scoper to reset the statement.
+   */
+  already_AddRefed<mozIStorageStatement>
+  GetStatement(const nsACString& aQuery) const
+  {
+    if (mShuttingDown) {
+      return nsnull;
+    }
+    if (NS_IsMainThread()) {
+      return mMainThreadStatements.GetCachedStatement(aQuery);
+    }
+    return mAsyncThreadStatements.GetCachedStatement(aQuery);
+  }
+
+  /**
+   * Gets a cached asynchronous statement.
+   *
+   * @param aQuery
+   *        SQL query literal.
+   * @return The cached statement.
+   * @note Always null check the result.
+   * @note AsyncStatements are automatically reset on execution.
+   */
+  template<int N>
+  already_AddRefed<mozIStorageAsyncStatement>
+  GetAsyncStatement(const char (&aQuery)[N]) const
+  {
+    nsDependentCString query(aQuery, N - 1);
+    return GetAsyncStatement(query);
+  }
+
+  /**
+   * Gets a cached asynchronous statement.
+   *
+   * @param aQuery
+   *        nsCString of SQL query.
+   * @return The cached statement.
+   * @note Always null check the result.
+   * @note AsyncStatements are automatically reset on execution.
+   */
+  already_AddRefed<mozIStorageAsyncStatement>
+  GetAsyncStatement(const nsACString& aQuery) const
+  {
+    if (mShuttingDown) {
+      return nsnull;
+    }
+    MOZ_ASSERT(NS_IsMainThread());
+    return mMainThreadAsyncStatements.GetCachedStatement(aQuery);
+  }
+
+protected:
+  /**
+   * Initializes the database file.  If the database does not exist or is
+   * corrupt, a new one is created.  In case of corruption it also creates a
+   * backup copy of the database.
+   *
+   * @param aStorage
+   *        mozStorage service instance.
+   * @param aNewDatabaseCreated
+   *        whether a new database file has been created.
+   */
+  nsresult InitDatabaseFile(nsCOMPtr<mozIStorageService>& aStorage,
+                            bool* aNewDatabaseCreated);
+
+  /**
+   * Creates a database backup and replaces the original file with a new
+   * one.
+   *
+   * @param aStorage
+   *        mozStorage service instance.
+   */
+  nsresult BackupAndReplaceDatabaseFile(nsCOMPtr<mozIStorageService>& aStorage);
+
+  /**
+   * Initializes the database.  This performs any necessary migrations for the
+   * database.  All migration is done inside a transaction that is rolled back
+   * if any error occurs.
+   * @param aDatabaseMigrated
+   *        Whether a schema upgrade happened.
+   */
+  nsresult InitSchema(bool* aDatabaseMigrated);
+
+  /**
+   * Initializes additionale SQLite functions, defined in SQLFunctions.h
+   */
+  nsresult InitFunctions();
+
+  /**
+   * Initializes triggers defined in nsPlacesTriggers.h
+   */  
+  nsresult InitTempTriggers();
+
+  /**
+   * Helpers used by schema upgrades.
+   */
+  nsresult MigrateV7Up();
+  nsresult MigrateV8Up();
+  nsresult MigrateV9Up();
+  nsresult MigrateV10Up();
+  nsresult MigrateV11Up();
+  nsresult CheckAndUpdateGUIDs();
+
+private:
+  ~Database();
+
+  /**
+   * Singleton getter, invoked by class instantiation.
+   *
+   * Note: does AddRef.
+   */
+  static Database* GetSingleton();
+
+  static Database* gDatabase;
+
+  nsCOMPtr<mozIStorageConnection> mMainConn;
+
+  mutable StatementCache mMainThreadStatements;
+  mutable AsyncStatementCache mMainThreadAsyncStatements;
+  mutable StatementCache mAsyncThreadStatements;
+
+  PRInt32 mDBPageSize;
+  enum JournalMode mCurrentJournalMode;
+  PRUint16 mDatabaseStatus;
+  bool mShuttingDown;
+};
+
+} // namespace places
+} // namespace mozilla
+
+#endif // mozilla_places_Database_h_
--- a/toolkit/components/places/Helpers.cpp
+++ b/toolkit/components/places/Helpers.cpp
@@ -348,24 +348,28 @@ IsValidGUID(const nsCString& aGUID)
       continue;
     }
     return false;
   }
   return true;
 }
 
 void
-ForceWALCheckpoint(mozIStorageConnection* aDBConn)
+ForceWALCheckpoint()
 {
-  nsCOMPtr<mozIStorageAsyncStatement> stmt;
-  (void)aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
-    "pragma wal_checkpoint "
-  ), getter_AddRefs(stmt));
-  nsCOMPtr<mozIStoragePendingStatement> handle;
-  (void)stmt->ExecuteAsync(nsnull, getter_AddRefs(handle));
+  nsRefPtr<Database> DB = Database::GetDatabase();
+  if (DB) {
+    nsCOMPtr<mozIStorageAsyncStatement> stmt = DB->GetAsyncStatement(
+      "pragma wal_checkpoint "
+    );
+    if (stmt) {
+      nsCOMPtr<mozIStoragePendingStatement> handle;
+      (void)stmt->ExecuteAsync(nsnull, getter_AddRefs(handle));
+    }
+  }
 }
 
 bool
 GetHiddenState(bool aIsRedirect,
                PRUint32 aTransitionType)
 {
   return aTransitionType == nsINavHistoryService::TRANSITION_FRAMED_LINK ||
          aTransitionType == nsINavHistoryService::TRANSITION_EMBED ||
--- a/toolkit/components/places/Helpers.h
+++ b/toolkit/components/places/Helpers.h
@@ -69,68 +69,16 @@ protected:
  * Macros to use in place of NS_DECL_MOZISTORAGESTATEMENTCALLBACK to declare the
  * methods this class assumes silent or notreached.
  */
 #define NS_DECL_ASYNCSTATEMENTCALLBACK \
   NS_IMETHOD HandleResult(mozIStorageResultSet *); \
   NS_IMETHOD HandleCompletion(PRUint16);
 
 /**
- * Macros to use for lazy statements initialization in Places services that use
- * GetStatement() method.
- */
-#ifdef DEBUG
-#define RETURN_IF_STMT(_stmt, _sql)                                            \
-  PR_BEGIN_MACRO                                                               \
-  if (address_of(_stmt) == address_of(aStmt)) {                                \
-    if (!_stmt) {                                                              \
-      nsresult rv = mDBConn->CreateStatement(_sql, getter_AddRefs(_stmt));     \
-      if (NS_FAILED(rv)) {                                                     \
-        nsCAutoString err;                                                     \
-        (void)mDBConn->GetLastErrorString(err);                                \
-        (void)fprintf(stderr, "$$$ compiling statement failed with '%s'\n",    \
-                      err.get());                                              \
-      }                                                                        \
-      NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && _stmt, nsnull);                       \
-    }                                                                          \
-    return _stmt.get();                                                        \
-  }                                                                            \
-  PR_END_MACRO
-#else
-#define RETURN_IF_STMT(_stmt, _sql)                                            \
-  PR_BEGIN_MACRO                                                               \
-  if (address_of(_stmt) == address_of(aStmt)) {                                \
-    if (!_stmt) {                                                              \
-      nsresult rv = mDBConn->CreateStatement(_sql, getter_AddRefs(_stmt));     \
-      NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && _stmt, nsnull);                       \
-    }                                                                          \
-    return _stmt.get();                                                        \
-  }                                                                            \
-  PR_END_MACRO
-#endif
-
-// Async statements don't need to be scoped, they are reset when done.
-// So use this version for statements used async, scoped version for statements
-// used sync.
-#define DECLARE_AND_ASSIGN_LAZY_STMT_RET(_localStmt, _globalStmt, _ret)            \
-  mozIStorageStatement* _localStmt = GetStatement(_globalStmt);                \
-  NS_ENSURE_TRUE(_localStmt, _ret)
-
-#define DECLARE_AND_ASSIGN_LAZY_STMT(_localStmt, _globalStmt)                  \
-  DECLARE_AND_ASSIGN_LAZY_STMT_RET(_localStmt, _globalStmt, NS_ERROR_UNEXPECTED)
-
-#define DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT_RET(_localStmt, _globalStmt, _ret)     \
-  DECLARE_AND_ASSIGN_LAZY_STMT_RET(_localStmt, _globalStmt, _ret);             \
-  mozStorageStatementScoper scoper(_localStmt)
-
-#define DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(_localStmt, _globalStmt)           \
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT_RET(_localStmt, _globalStmt, NS_ERROR_UNEXPECTED)
-
-
-/**
  * Utils to bind a specified URI (or URL) to a statement or binding params, at
  * the specified index or name.
  * @note URIs are always bound as UTF8.
  */
 class URIBinder // static
 {
 public:
   // Bind URI to statement by index.
@@ -262,21 +210,19 @@ protected:
   nsCOMPtr<nsISupports> mOwner;
   nsCOMPtr<nsIThread> mCallingThread;
 };
 
 /**
  * Forces a WAL checkpoint. This will cause all transactions stored in the
  * journal file to be committed to the main database.
  * 
- * @param aDBConn
- *        Connection to the database.
  * @note The checkpoint will force a fsync/flush.
  */
-void ForceWALCheckpoint(mozIStorageConnection* aDBConn);
+void ForceWALCheckpoint();
 
 /**
  * Determines if a visit should be marked as hidden given its transition type
  * and whether or not it was a redirect.
  *
  * @param aIsRedirect
  *        True if this visit was a redirect, false otherwise.
  * @param aTransitionType
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -884,34 +884,34 @@ private:
   bool FetchVisitInfo(VisitData& _place,
                       PRTime aThresholdStart = 0)
   {
     NS_PRECONDITION(!_place.spec.IsEmpty(), "must have a non-empty spec!");
 
     nsCOMPtr<mozIStorageStatement> stmt;
     // If we have a visitTime, we want information on that specific visit.
     if (_place.visitTime) {
-      stmt = mHistory->syncStatements.GetCachedStatement(
+      stmt = mHistory->GetStatement(
         "SELECT id, session, visit_date "
         "FROM moz_historyvisits "
         "WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
         "AND visit_date = :visit_date "
       );
       NS_ENSURE_TRUE(stmt, false);
 
       mozStorageStatementScoper scoper(stmt);
       nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("visit_date"),
                                           _place.visitTime);
       NS_ENSURE_SUCCESS(rv, rv);
 
       scoper.Abandon();
     }
     // Otherwise, we want information about the most recent visit.
     else {
-      stmt = mHistory->syncStatements.GetCachedStatement(
+      stmt = mHistory->GetStatement(
         "SELECT id, session, visit_date "
         "FROM moz_historyvisits "
         "WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
         "ORDER BY visit_date DESC "
       );
       NS_ENSURE_TRUE(stmt, false);
     }
     mozStorageStatementScoper scoper(stmt);
@@ -990,27 +990,27 @@ private:
    *        A reference to the referrer's visit data.
    */
   nsresult AddVisit(VisitData& _place,
                     const VisitData& aReferrer)
   {
     nsresult rv;
     nsCOMPtr<mozIStorageStatement> stmt;
     if (_place.placeId) {
-      stmt = mHistory->syncStatements.GetCachedStatement(
+      stmt = mHistory->GetStatement(
         "INSERT INTO moz_historyvisits "
           "(from_visit, place_id, visit_date, visit_type, session) "
         "VALUES (:from_visit, :page_id, :visit_date, :visit_type, :session) "
       );
       NS_ENSURE_STATE(stmt);
       rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), _place.placeId);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
-      stmt = mHistory->syncStatements.GetCachedStatement(
+      stmt = mHistory->GetStatement(
         "INSERT INTO moz_historyvisits "
           "(from_visit, place_id, visit_date, visit_type, session) "
         "VALUES (:from_visit, (SELECT id FROM moz_places WHERE url = :page_url), :visit_date, :visit_type, :session) "
       );
       NS_ENSURE_STATE(stmt);
       rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), _place.spec);
       NS_ENSURE_SUCCESS(rv, rv);
     }
@@ -1049,27 +1049,27 @@ private:
    *        The VisitData for the place we want to update.
    */
   nsresult UpdateFrecency(const VisitData& aPlace)
   {
     nsresult rv;
     { // First, set our frecency to the proper value.
       nsCOMPtr<mozIStorageStatement> stmt;
       if (aPlace.placeId) {
-        stmt = mHistory->syncStatements.GetCachedStatement(
+        stmt = mHistory->GetStatement(
           "UPDATE moz_places "
           "SET frecency = CALCULATE_FRECENCY(:page_id) "
           "WHERE id = :page_id"
         );
         NS_ENSURE_STATE(stmt);
         rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), aPlace.placeId);
         NS_ENSURE_SUCCESS(rv, rv);
       }
       else {
-        stmt = mHistory->syncStatements.GetCachedStatement(
+        stmt = mHistory->GetStatement(
           "UPDATE moz_places "
           "SET frecency = CALCULATE_FRECENCY(id) "
           "WHERE url = :page_url"
         );
         NS_ENSURE_STATE(stmt);
         rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aPlace.spec);
         NS_ENSURE_SUCCESS(rv, rv);
       }
@@ -1078,27 +1078,27 @@ private:
       rv = stmt->Execute();
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     { // Now, we need to mark the page as not hidden if the frecency is now
       // nonzero.
       nsCOMPtr<mozIStorageStatement> stmt;
       if (aPlace.placeId) {
-        stmt = mHistory->syncStatements.GetCachedStatement(
+        stmt = mHistory->GetStatement(
           "UPDATE moz_places "
           "SET hidden = 0 "
           "WHERE id = :page_id AND frecency <> 0"
         );
         NS_ENSURE_STATE(stmt);
         rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), aPlace.placeId);
         NS_ENSURE_SUCCESS(rv, rv);
       }
       else {
-        stmt = mHistory->syncStatements.GetCachedStatement(
+        stmt = mHistory->GetStatement(
           "UPDATE moz_places "
           "SET hidden = 0 "
           "WHERE url = :page_url AND frecency <> 0"
         );
         NS_ENSURE_STATE(stmt);
         rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aPlace.spec);
         NS_ENSURE_SUCCESS(rv, rv);
       }
@@ -1182,17 +1182,17 @@ public:
       return NS_OK;
     }
 
     NS_ASSERTION(mPlace.placeId > 0,
                  "We somehow have an invalid place id here!");
 
     // Now we can update our database record.
     nsCOMPtr<mozIStorageStatement> stmt =
-      mHistory->syncStatements.GetCachedStatement(
+      mHistory->GetStatement(
         "UPDATE moz_places "
         "SET title = :page_title "
         "WHERE id = :page_id "
       );
     NS_ENSURE_STATE(stmt);
 
     {
       mozStorageStatementScoper scoper(stmt);
@@ -1304,18 +1304,17 @@ NS_MEMORY_REPORTER_IMPLEMENT(HistoryServ
 } // anonymous namespace
 
 ////////////////////////////////////////////////////////////////////////////////
 //// History
 
 History* History::gService = NULL;
 
 History::History()
-  : syncStatements(mDBConn)
-  , mShuttingDown(false)
+  : mShuttingDown(false)
 {
   NS_ASSERTION(!gService, "Ruh-roh!  This service has already been created!");
   gService = this;
 
   nsCOMPtr<nsIObserverService> os = services::GetObserverService();
   NS_WARN_IF_FALSE(os, "Observer service was not found!");
   if (os) {
     (void)os->AddObserver(this, TOPIC_PLACES_SHUTDOWN, false);
@@ -1410,17 +1409,17 @@ History::GetIsVisitedStatement()
 }
 
 nsresult
 History::InsertPlace(const VisitData& aPlace)
 {
   NS_PRECONDITION(aPlace.placeId == 0, "should not have a valid place id!");
   NS_PRECONDITION(!NS_IsMainThread(), "must be called off of the main thread!");
 
-  nsCOMPtr<mozIStorageStatement> stmt = syncStatements.GetCachedStatement(
+  nsCOMPtr<mozIStorageStatement> stmt = GetStatement(
       "INSERT INTO moz_places "
         "(url, title, rev_host, hidden, typed, guid) "
       "VALUES (:url, :title, :rev_host, :hidden, :typed, :guid) "
     );
   NS_ENSURE_STATE(stmt);
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindStringByName(NS_LITERAL_CSTRING("rev_host"),
@@ -1456,17 +1455,17 @@ History::InsertPlace(const VisitData& aP
 
 nsresult
 History::UpdatePlace(const VisitData& aPlace)
 {
   NS_PRECONDITION(!NS_IsMainThread(), "must be called off of the main thread!");
   NS_PRECONDITION(aPlace.placeId > 0, "must have a valid place id!");
   NS_PRECONDITION(!aPlace.guid.IsVoid(), "must have a guid!");
 
-  nsCOMPtr<mozIStorageStatement> stmt = syncStatements.GetCachedStatement(
+  nsCOMPtr<mozIStorageStatement> stmt = GetStatement(
       "UPDATE moz_places "
       "SET title = :title, "
           "hidden = :hidden, "
           "typed = :typed, "
           "guid = :guid "
       "WHERE id = :page_id "
     );
   NS_ENSURE_STATE(stmt);
@@ -1498,17 +1497,17 @@ History::UpdatePlace(const VisitData& aP
 }
 
 bool
 History::FetchPageInfo(VisitData& _place)
 {
   NS_PRECONDITION(!_place.spec.IsEmpty(), "must have a non-empty spec!");
   NS_PRECONDITION(!NS_IsMainThread(), "must be called off of the main thread!");
 
-  nsCOMPtr<mozIStorageStatement> stmt = syncStatements.GetCachedStatement(
+  nsCOMPtr<mozIStorageStatement> stmt = GetStatement(
       "SELECT id, title, hidden, typed, guid "
       "FROM moz_places "
       "WHERE url = :page_url "
     );
   NS_ENSURE_TRUE(stmt, false);
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"),
@@ -1616,45 +1615,30 @@ History::GetSingleton()
 
   NS_ADDREF(gService);
   return gService;
 }
 
 mozIStorageConnection*
 History::GetDBConn()
 {
-  if (mDBConn) {
-    return mDBConn;
+  if (!mDB) {
+    mDB = Database::GetDatabase();
+    NS_ENSURE_TRUE(mDB, nsnull);
   }
-
-  nsNavHistory* navHistory = nsNavHistory::GetHistoryService();
-  NS_ENSURE_TRUE(navHistory, nsnull);
-
-  nsresult rv = navHistory->GetDBConnection(getter_AddRefs(mDBConn));
-  NS_ENSURE_SUCCESS(rv, nsnull);
-
-  return mDBConn;
+  return mDB->MainConn();
 }
 
 void
 History::Shutdown()
 {
   NS_ASSERTION(!mShuttingDown, "Shutdown was called more than once!");
 
   mShuttingDown = true;
 
-  // Clean up our statements and connection.
-  nsISupports* obj = static_cast<IHistory*>(this);
-  nsCOMPtr<nsIRunnable> event =
-    new FinalizeStatementCacheProxy<mozIStorageStatement>(syncStatements, obj);
-  nsCOMPtr<nsIEventTarget> target = do_GetInterface(mDBConn);
-  if (target) {
-    (void)target->Dispatch(event, NS_DISPATCH_NORMAL);
-  }
-
   if (mReadOnlyDBConn) {
     if (mIsVisitedStatement) {
       (void)mIsVisitedStatement->Finalize();
     }
     (void)mReadOnlyDBConn->AsyncClose(nsnull);
   }
 }
 
--- a/toolkit/components/places/History.h
+++ b/toolkit/components/places/History.h
@@ -37,25 +37,26 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_places_History_h_
 #define mozilla_places_History_h_
 
 #include "mozilla/IHistory.h"
 #include "mozIAsyncHistory.h"
+#include "Database.h"
+
 #include "mozilla/dom/Link.h"
 #include "nsTHashtable.h"
 #include "nsString.h"
 #include "nsURIHashKey.h"
 #include "nsTObserverArray.h"
 #include "nsDeque.h"
 #include "nsIObserver.h"
 #include "mozIStorageConnection.h"
-#include "mozilla/storage/StatementCache.h"
 
 namespace mozilla {
 namespace places {
 
 struct VisitData;
 
 #define NS_HISTORYSERVICE_CID \
   {0x0937a705, 0x91a6, 0x417a, {0x82, 0x92, 0xb2, 0x2e, 0xb1, 0x0d, 0xa8, 0x6c}}
@@ -122,37 +123,39 @@ public:
   static History* GetService();
 
   /**
    * Obtains a pointer that has had AddRef called on it.  Used by the service
    * manager only.
    */
   static History* GetSingleton();
 
-  /**
-   * Statement cache that is used for background thread statements only.
-   */
-  storage::StatementCache<mozIStorageStatement> syncStatements;
+  template<int N>
+  already_AddRefed<mozIStorageStatement>
+  GetStatement(const char (&aQuery)[N])
+  {
+    mozIStorageConnection* dbConn = GetDBConn();
+    NS_ENSURE_TRUE(dbConn, nsnull);
+    return mDB->GetStatement(aQuery);
+  }
 
 private:
   virtual ~History();
 
   /**
    * Obtains a read-write database connection.
    */
   mozIStorageConnection* GetDBConn();
 
   /**
-   * A read-write database connection used for adding history visits and setting
-   * a page's title.
-   *
-   * @note this should only be accessed by GetDBConn.
-   * @note this is the same connection as the one found on nsNavHistory.
+   * The database handle.  This is initialized lazily by the first call to
+   * GetDBConn(), so never use it directly, or, if you really need, always
+   * invoke GetDBConn() before.
    */
-  nsCOMPtr<mozIStorageConnection> mDBConn;
+  nsRefPtr<mozilla::places::Database> mDB;
 
   /**
    * A read-only database connection used for checking if a URI is visited.
    *
    * @note this should only be accessed by GetIsVisistedStatement and Shutdown.
    */
   nsCOMPtr<mozIStorageConnection> mReadOnlyDBConn;
 
--- a/toolkit/components/places/Makefile.in
+++ b/toolkit/components/places/Makefile.in
@@ -71,16 +71,17 @@ XPIDLSRCS += \
   nsPIPlacesDatabase.idl \
   nsPIPlacesHistoryListenersNotifier.idl \
   $(NULL)
 
 EXPORTS_NAMESPACES = mozilla/places
 
 EXPORTS_mozilla/places = \
   History.h \
+  Database.h \
   $(NULL)
 
 CPPSRCS = \
   nsAnnoProtocolHandler.cpp \
   nsAnnotationService.cpp \
   nsFaviconService.cpp \
   nsNavHistory.cpp \
   nsNavHistoryQuery.cpp \
@@ -90,16 +91,17 @@ CPPSRCS = \
   nsPlacesModule.cpp \
   SQLFunctions.cpp \
   Helpers.cpp \
   History.cpp \
   nsPlacesImportExportService.cpp \
   AsyncFaviconHelpers.cpp \
   PlaceInfo.cpp \
   VisitInfo.cpp \
+  Database.cpp \
   $(NULL)
 
 LOCAL_INCLUDES += -I$(srcdir)/../build
 
 # This is the default value.  Must be in sync with the one defined in SQLite.
 DEFINES += -DSQLITE_DEFAULT_PAGE_SIZE=32768
 
 EXTRA_COMPONENTS = \
--- a/toolkit/components/places/SQLFunctions.cpp
+++ b/toolkit/components/places/SQLFunctions.cpp
@@ -433,17 +433,17 @@ namespace places {
 
   //////////////////////////////////////////////////////////////////////////////
   //// CalculateFrecencyFunction
 
   /* static */
   nsresult
   CalculateFrecencyFunction::create(mozIStorageConnection *aDBConn)
   {
-    nsCOMPtr<CalculateFrecencyFunction> function =
+    nsRefPtr<CalculateFrecencyFunction> function =
       new CalculateFrecencyFunction();
 
     nsresult rv = aDBConn->CreateFunction(
       NS_LITERAL_CSTRING("calculate_frecency"), 1, function
     );
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
@@ -473,39 +473,41 @@ namespace places {
     PRInt64 bookmarkId = numEntries > 3 ? aArguments->AsInt64(3) : 0;
     PRInt32 visitCount = 0;
     PRInt32 hidden = 0;
     PRInt32 isQuery = 0;
     float pointsForSampledVisits = 0.0;
 
     // This is a const version of the history object for thread-safety.
     const nsNavHistory* history = nsNavHistory::GetConstHistoryService();
-    NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
+    NS_ENSURE_STATE(history);
+    nsRefPtr<Database> DB = Database::GetDatabase();
+    NS_ENSURE_STATE(DB);
 
     if (pageId > 0) {
       // The page is already in the database, and we can fetch current
       // params from the database.
-      nsCOMPtr<mozIStorageStatement> getPageInfo =
-        history->GetStatementByStoragePool(
-          "SELECT typed, hidden, visit_count, "
-            "(SELECT count(*) FROM moz_historyvisits WHERE place_id = :page_id), "
-            "EXISTS ( "
-              "SELECT 1 FROM moz_bookmarks "
-              "WHERE fk = :page_id "
-              "AND NOT EXISTS( "
-                "SELECT 1 "
-                "FROM moz_items_annos a "
-                "JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
-                "WHERE n.name = :anno_name "
-                  "AND a.item_id = parent "
-              ") "
-            "), "
-            "(url > 'place:' AND url < 'place;') "
-          "FROM moz_places "
-          "WHERE id = :page_id ");
+      nsRefPtr<mozIStorageStatement> getPageInfo = DB->GetStatement(
+        "SELECT typed, hidden, visit_count, "
+          "(SELECT count(*) FROM moz_historyvisits WHERE place_id = :page_id), "
+          "EXISTS ( "
+            "SELECT 1 FROM moz_bookmarks "
+            "WHERE fk = :page_id "
+            "AND NOT EXISTS( "
+              "SELECT 1 "
+              "FROM moz_items_annos a "
+              "JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
+              "WHERE n.name = :anno_name "
+                "AND a.item_id = parent "
+            ") "
+          "), "
+          "(url > 'place:' AND url < 'place;') "
+        "FROM moz_places "
+        "WHERE id = :page_id "
+      );
       NS_ENSURE_STATE(getPageInfo);
       mozStorageStatementScoper infoScoper(getPageInfo);
 
       rv = getPageInfo->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = getPageInfo->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
                                              NS_LITERAL_CSTRING("livemark/feedURI"));
       NS_ENSURE_SUCCESS(rv, rv);
@@ -527,33 +529,33 @@ namespace places {
       rv = getPageInfo->GetInt32(5, &isQuery);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // NOTE: This is not limited to visits with "visit_type NOT IN (0,4,7,8)"
       // because otherwise it would not return any visit for those transitions
       // causing an incorrect frecency, see CalculateFrecencyInternal().
       // In case of a temporary or permanent redirect, calculate the frecency
       // as if the original page was visited.
-      nsCAutoString visitsForFrecencySQL(NS_LITERAL_CSTRING(
-        "/* do not warn (bug 659740 - SQLite may ignore index if few visits exist) */"
-        "SELECT "
-          "ROUND((strftime('%s','now','localtime','utc') - v.visit_date/1000000)/86400), "
-          "IFNULL(r.visit_type, v.visit_type), "
-          "v.visit_date "
+      // Get a sample of the last visits to the page, to calculate its weight.
+      nsCOMPtr<mozIStorageStatement> getVisits = DB->GetStatement(
+        NS_LITERAL_CSTRING(
+          "/* do not warn (bug 659740 - SQLite may ignore index if few visits exist) */"
+          "SELECT "
+            "ROUND((strftime('%s','now','localtime','utc') - v.visit_date/1000000)/86400), "
+            "IFNULL(r.visit_type, v.visit_type), "
+            "v.visit_date "
           "FROM moz_historyvisits v "
           "LEFT JOIN moz_historyvisits r ON r.id = v.from_visit AND v.visit_type BETWEEN "
-          ) + nsPrintfCString("%d AND %d ", nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
-                                            nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
-          NS_LITERAL_CSTRING("WHERE v.place_id = :page_id "
-          "ORDER BY v.visit_date DESC ")
+        ) + nsPrintfCString("%d AND %d ", nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                                          nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY) +
+        NS_LITERAL_CSTRING(
+          "WHERE v.place_id = :page_id "
+          "ORDER BY v.visit_date DESC "
+        )
       );
-
-      // Get a sample of the last visits to the page, to calculate its weight.
-      nsCOMPtr<mozIStorageStatement> getVisits =
-        history->GetStatementByStoragePool(visitsForFrecencySQL);
       NS_ENSURE_STATE(getVisits);
       mozStorageStatementScoper visitsScoper(getVisits);
 
       rv = getVisits->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // Fetch only a limited number of recent visits.
       PRInt32 numSampledVisits = 0;
@@ -646,17 +648,17 @@ namespace places {
     // We need this service to be initialized on the main thread because it is
     // not threadsafe.  We are about to use it asynchronously, so initialize it
     // now.
     nsCOMPtr<nsIRandomGenerator> rg =
       do_GetService("@mozilla.org/security/random-generator;1");
     NS_ENSURE_STATE(rg);
 #endif
 
-    nsCOMPtr<GenerateGUIDFunction> function = new GenerateGUIDFunction();
+    nsRefPtr<GenerateGUIDFunction> function = new GenerateGUIDFunction();
     nsresult rv = aDBConn->CreateFunction(
       NS_LITERAL_CSTRING("generate_guid"), 0, function
     );
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
@@ -675,10 +677,64 @@ namespace places {
     nsCAutoString guid;
     nsresult rv = GenerateGUID(guid);
     NS_ENSURE_SUCCESS(rv, rv);
 
     NS_ADDREF(*_result = new UTF8TextVariant(guid));
     return NS_OK;
   }
 
+////////////////////////////////////////////////////////////////////////////////
+//// Get Unreversed Host Function
+
+  //////////////////////////////////////////////////////////////////////////////
+  //// GetUnreversedHostFunction
+
+  /* static */
+  nsresult
+  GetUnreversedHostFunction::create(mozIStorageConnection *aDBConn)
+  {
+    nsRefPtr<GetUnreversedHostFunction> function = new GetUnreversedHostFunction();
+    nsresult rv = aDBConn->CreateFunction(
+      NS_LITERAL_CSTRING("get_unreversed_host"), 1, function
+    );
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    return NS_OK;
+  }
+
+  NS_IMPL_THREADSAFE_ISUPPORTS1(
+    GetUnreversedHostFunction,
+    mozIStorageFunction
+  )
+
+  //////////////////////////////////////////////////////////////////////////////
+  //// mozIStorageFunction
+
+  NS_IMETHODIMP
+  GetUnreversedHostFunction::OnFunctionCall(mozIStorageValueArray *aArguments,
+                                            nsIVariant **_result)
+  {
+    // Must have non-null function arguments.
+    MOZ_ASSERT(aArguments);
+
+    nsAutoString src;
+    aArguments->GetString(0, src);
+
+    nsCOMPtr<nsIWritableVariant> result =
+      do_CreateInstance("@mozilla.org/variant;1");
+    NS_ENSURE_STATE(result);
+
+    if (src.Length()>1) {
+      src.Truncate(src.Length() - 1);
+      nsAutoString dest;
+      ReverseString(src, dest);
+      result->SetAsAString(dest);
+    }
+    else {
+      result->SetAsAString(EmptyString());
+    }
+    NS_ADDREF(*_result = result);
+    return NS_OK;
+  }
+
 } // namespace places
 } // namespace mozilla
--- a/toolkit/components/places/SQLFunctions.h
+++ b/toolkit/components/places/SQLFunctions.h
@@ -242,12 +242,35 @@ public:
    * Registers the function with the specified database connection.
    *
    * @param aDBConn
    *        The database connection to register with.
    */
   static nsresult create(mozIStorageConnection *aDBConn);
 };
 
+/**
+ * SQL function to unreverse the rev_host of a page.
+ *
+ * @param rev_host
+ *        The rev_host value of the page.
+ *
+ * @return the unreversed host of the page.
+ */
+class GetUnreversedHostFunction : public mozIStorageFunction
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_MOZISTORAGEFUNCTION
+
+  /**
+   * Registers the function with the specified database connection.
+   *
+   * @param aDBConn
+   *        The database connection to register with.
+   */
+  static nsresult create(mozIStorageConnection *aDBConn);
+};
+
 } // namespace places
 } // namespace storage
 
 #endif // mozilla_places_SQLFunctions_h_
--- a/toolkit/components/places/nsAnnoProtocolHandler.cpp
+++ b/toolkit/components/places/nsAnnoProtocolHandler.cpp
@@ -53,22 +53,21 @@
 #include "nsILoadGroup.h"
 #include "nsIStandardURL.h"
 #include "nsIStringStream.h"
 #include "nsISupportsUtils.h"
 #include "nsIURI.h"
 #include "nsNetUtil.h"
 #include "nsServiceManagerUtils.h"
 #include "nsStringStream.h"
-#include "mozIStorageStatementCallback.h"
-#include "mozIStorageResultSet.h"
-#include "mozIStorageRow.h"
-#include "mozIStorageError.h"
+#include "mozilla/storage.h"
 #include "nsIPipe.h"
 #include "Helpers.h"
+
+using namespace mozilla;
 using namespace mozilla::places;
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Global Functions
 
 /**
  * Creates a channel to obtain the default favicon.
  */
--- a/toolkit/components/places/nsAnnotationService.cpp
+++ b/toolkit/components/places/nsAnnotationService.cpp
@@ -38,27 +38,25 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/Util.h"
 
 #include "nsAnnotationService.h"
 #include "nsNavHistory.h"
+#include "nsPlacesTables.h"
+#include "nsPlacesIndexes.h"
+#include "nsPlacesMacros.h"
+#include "Helpers.h"
 
 #include "nsNetUtil.h"
 #include "nsIVariant.h"
 #include "nsString.h"
 #include "nsVariant.h"
-
-#include "nsPlacesTables.h"
-#include "nsPlacesIndexes.h"
-#include "nsPlacesMacros.h"
-#include "Helpers.h"
-
 #include "mozilla/storage.h"
 
 using namespace mozilla;
 
 #define ENSURE_ANNO_TYPE(_type, _statement)                                    \
   PR_BEGIN_MACRO                                                               \
   PRInt32 type = _statement->AsInt32(kAnnoIndex_Type);                         \
   NS_ENSURE_TRUE(type == nsIAnnotationService::_type, NS_ERROR_INVALID_ARG);   \
@@ -84,17 +82,17 @@ const PRInt32 nsAnnotationService::kAnno
 using namespace mozilla::places;
 
 PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsAnnotationService, gAnnotationService)
 
 NS_IMPL_ISUPPORTS1(nsAnnotationService,
                    nsIAnnotationService)
 
 
-nsAnnotationService::nsAnnotationService() : mShuttingDown(false)
+nsAnnotationService::nsAnnotationService()
 {
   NS_ASSERTION(!gAnnotationService,
                "Attempting to create two instances of the service!");
   gAnnotationService = this;
 }
 
 
 nsAnnotationService::~nsAnnotationService()
@@ -104,183 +102,35 @@ nsAnnotationService::~nsAnnotationServic
   if (gAnnotationService == this)
     gAnnotationService = nsnull;
 }
 
 
 nsresult
 nsAnnotationService::Init()
 {
-  // The history service will normally already be created and will call our
-  // static InitTables function. It will get autocreated here if it hasn't
-  // already been created.
-  nsNavHistory* history = nsNavHistory::GetHistoryService();
-  NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
-  mDBConn = history->GetStorageConnection();
+  mDB = Database::GetDatabase();
+  NS_ENSURE_STATE(mDB);
 
   return NS_OK;
 }
 
-
-mozIStorageStatement*
-nsAnnotationService::GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt)
-{
-  if (mShuttingDown)
-    return nsnull;
-
-  RETURN_IF_STMT(mDBGetAnnotationsForItem, NS_LITERAL_CSTRING(
-    "SELECT n.name "
-    "FROM moz_anno_attributes n "
-    "JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
-    "WHERE a.item_id = :item_id"));
-
-  RETURN_IF_STMT(mDBGetAnnotationsForPage, NS_LITERAL_CSTRING(
-    "SELECT n.name "
-    "FROM moz_anno_attributes n "
-    "JOIN moz_annos a ON a.anno_attribute_id = n.id "
-    "JOIN moz_places h ON h.id = a.place_id "
-    "WHERE h.url = :page_url"));
-
-  RETURN_IF_STMT(mDBGetPageAnnotationValue, NS_LITERAL_CSTRING(
-    "SELECT a.id, a.place_id, :anno_name, a.mime_type, a.content, a.flags, "
-           "a.expiration, a.type "
-    "FROM moz_anno_attributes n "
-    "JOIN moz_annos a ON n.id = a.anno_attribute_id "
-    "JOIN moz_places h ON h.id = a.place_id "
-    "WHERE h.url = :page_url "
-      "AND n.name = :anno_name"));
-
-  RETURN_IF_STMT(mDBGetItemAnnotationValue, NS_LITERAL_CSTRING(
-    "SELECT a.id, a.item_id, :anno_name, a.mime_type, a.content, a.flags, "
-           "a.expiration, a.type "
-    "FROM moz_anno_attributes n "
-    "JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
-    "WHERE a.item_id = :item_id "
-    "AND n.name = :anno_name"));
-
-  RETURN_IF_STMT(mDBAddAnnotationName, NS_LITERAL_CSTRING(
-    "INSERT OR IGNORE INTO moz_anno_attributes (name) VALUES (:anno_name)"));
-
-  RETURN_IF_STMT(mDBAddPageAnnotation, NS_LITERAL_CSTRING(
-    "INSERT OR REPLACE INTO moz_annos "
-      "(id, place_id, anno_attribute_id, mime_type, content, flags, "
-       "expiration, type, dateAdded, lastModified) "
-    "VALUES (:id, :fk, :name_id, :mime_type, :content, :flags, "
-    ":expiration, :type, :date_added, :last_modified)"));
-
-  RETURN_IF_STMT(mDBAddItemAnnotation, NS_LITERAL_CSTRING(
-    "INSERT OR REPLACE INTO moz_items_annos "
-      "(id, item_id, anno_attribute_id, mime_type, content, flags, "
-       "expiration, type, dateAdded, lastModified) "
-    "VALUES (:id, :fk, :name_id, :mime_type, :content, :flags, "
-    ":expiration, :type, :date_added, :last_modified)"));
-
-  RETURN_IF_STMT(mDBRemovePageAnnotation, NS_LITERAL_CSTRING(
-    "DELETE FROM moz_annos "
-    "WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
-      "AND anno_attribute_id = "
-        "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"));
-
-  RETURN_IF_STMT(mDBRemoveItemAnnotation, NS_LITERAL_CSTRING(
-    "DELETE FROM moz_items_annos "
-    "WHERE item_id = :item_id "
-      "AND anno_attribute_id = "
-        "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"));
-
-  RETURN_IF_STMT(mDBGetPagesWithAnnotation, NS_LITERAL_CSTRING(
-    "SELECT h.url "
-    "FROM moz_anno_attributes n "
-    "JOIN moz_annos a ON n.id = a.anno_attribute_id "
-    "JOIN moz_places h ON h.id = a.place_id "
-    "WHERE n.name = :anno_name"));
-
-  RETURN_IF_STMT(mDBGetItemsWithAnnotation, NS_LITERAL_CSTRING(
-    "SELECT a.item_id "
-    "FROM moz_anno_attributes n "
-    "JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
-    "WHERE n.name = :anno_name"));
-
-  RETURN_IF_STMT(mDBCheckPageAnnotation, NS_LITERAL_CSTRING(
-    "SELECT h.id, "
-           "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
-           "a.id, a.dateAdded "
-    "FROM moz_places h "
-    "LEFT JOIN moz_annos a ON a.place_id = h.id "
-                         "AND a.anno_attribute_id = nameid "
-    "WHERE h.url = :page_url"));
-
-  RETURN_IF_STMT(mDBCheckItemAnnotation, NS_LITERAL_CSTRING(
-    "SELECT b.id, "
-           "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
-           "a.id, a.dateAdded "
-    "FROM moz_bookmarks b "
-    "LEFT JOIN moz_items_annos a ON a.item_id = b.id "
-                               "AND a.anno_attribute_id = nameid "
-    "WHERE b.id = :item_id"));
-
-   return nsnull;
-}
-
-
-// nsAnnotationService::InitTables
-//
-//    All commands that initialize the schema of the DB go in here. This is
-//    called from history init before the dummy DB connection is started that
-//    will prevent us from modifying the schema.
-//
-//    The history service will always be created before us (we get it at the
-//    beginning of the init function which covers us if it's not).
-
-nsresult // static
-nsAnnotationService::InitTables(mozIStorageConnection* aDBConn)
-{
-  bool exists;
-  nsresult 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(CREATE_IDX_MOZ_ANNOS_PLACEATTRIBUTE);
-    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(CREATE_IDX_MOZ_ITEMSANNOS_PLACEATTRIBUTE);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return NS_OK;
-}
-
-
 nsresult
 nsAnnotationService::SetAnnotationStringInternal(nsIURI* aURI,
                                                  PRInt64 aItemId,
                                                  const nsACString& aName,
                                                  const nsAString& aValue,
                                                  PRInt32 aFlags,
                                                  PRUint16 aExpiration)
 {
-  mozStorageTransaction transaction(mDBConn, false);
-  mozIStorageStatement* statement;
+  mozStorageTransaction transaction(mDB->MainConn(), false);
+  nsCOMPtr<mozIStorageStatement> statement;
   nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
                                    nsIAnnotationService::TYPE_STRING,
-                                   &statement);
+                                   statement);
   NS_ENSURE_SUCCESS(rv, rv);
   mozStorageStatementScoper scoper(statement);
 
   rv = statement->BindStringByName(NS_LITERAL_CSTRING("content"), aValue);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -496,21 +346,21 @@ nsAnnotationService::SetItemAnnotationSt
 nsresult
 nsAnnotationService::SetAnnotationInt32Internal(nsIURI* aURI,
                                                 PRInt64 aItemId,
                                                 const nsACString& aName,
                                                 PRInt32 aValue,
                                                 PRInt32 aFlags,
                                                 PRUint16 aExpiration)
 {
-  mozStorageTransaction transaction(mDBConn, false);
-  mozIStorageStatement* statement;
+  mozStorageTransaction transaction(mDB->MainConn(), false);
+  nsCOMPtr<mozIStorageStatement> statement;
   nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
                                    nsIAnnotationService::TYPE_INT32,
-                                   &statement);
+                                   statement);
   NS_ENSURE_SUCCESS(rv, rv);
   mozStorageStatementScoper scoper(statement);
 
   rv = statement->BindInt32ByName(NS_LITERAL_CSTRING("content"), aValue);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -571,21 +421,21 @@ nsAnnotationService::SetItemAnnotationIn
 nsresult
 nsAnnotationService::SetAnnotationInt64Internal(nsIURI* aURI,
                                                 PRInt64 aItemId,
                                                 const nsACString& aName,
                                                 PRInt64 aValue,
                                                 PRInt32 aFlags,
                                                 PRUint16 aExpiration)
 {
-  mozStorageTransaction transaction(mDBConn, false);
-  mozIStorageStatement* statement;
+  mozStorageTransaction transaction(mDB->MainConn(), false);
+  nsCOMPtr<mozIStorageStatement> statement;
   nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
                                    nsIAnnotationService::TYPE_INT64,
-                                   &statement);
+                                   statement);
   NS_ENSURE_SUCCESS(rv, rv);
   mozStorageStatementScoper scoper(statement);
 
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("content"), aValue);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -646,21 +496,21 @@ nsAnnotationService::SetItemAnnotationIn
 nsresult
 nsAnnotationService::SetAnnotationDoubleInternal(nsIURI* aURI,
                                                  PRInt64 aItemId,
                                                  const nsACString& aName,
                                                  double aValue,
                                                  PRInt32 aFlags,
                                                  PRUint16 aExpiration)
 {
-  mozStorageTransaction transaction(mDBConn, false);
-  mozIStorageStatement* statement;
+  mozStorageTransaction transaction(mDB->MainConn(), false);
+  nsCOMPtr<mozIStorageStatement> statement;
   nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
                                    nsIAnnotationService::TYPE_DOUBLE,
-                                   &statement);
+                                   statement);
   NS_ENSURE_SUCCESS(rv, rv);
   mozStorageStatementScoper scoper(statement);
 
   rv = statement->BindDoubleByName(NS_LITERAL_CSTRING("content"), aValue);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -726,21 +576,21 @@ nsAnnotationService::SetAnnotationBinary
                                                  PRUint32 aDataLen,
                                                  const nsACString& aMimeType,
                                                  PRInt32 aFlags,
                                                  PRUint16 aExpiration)
 {
   if (aMimeType.Length() == 0)
     return NS_ERROR_INVALID_ARG;
 
-  mozStorageTransaction transaction(mDBConn, false);
-  mozIStorageStatement* statement;
+  mozStorageTransaction transaction(mDB->MainConn(), false);
+  nsCOMPtr<mozIStorageStatement> statement;
   nsresult rv = StartSetAnnotation(aURI, aItemId, aName, aFlags, aExpiration,
                                    nsIAnnotationService::TYPE_BINARY,
-                                   &statement);
+                                   statement);
   NS_ENSURE_SUCCESS(rv, rv);
   mozStorageStatementScoper scoper(statement);
 
   rv = statement->BindBlobByName(NS_LITERAL_CSTRING("content"), aData, aDataLen);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("mime_type"), aMimeType);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -805,18 +655,18 @@ nsAnnotationService::SetItemAnnotationBi
 
 NS_IMETHODIMP
 nsAnnotationService::GetPageAnnotationString(nsIURI* aURI,
                                              const nsACString& aName,
                                              nsAString& _retval)
 {
   NS_ENSURE_ARG(aURI);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(aURI, 0, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   ENSURE_ANNO_TYPE(TYPE_STRING, statement);
   rv = statement->GetString(kAnnoIndex_Content, _retval);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -826,18 +676,18 @@ nsAnnotationService::GetPageAnnotationSt
 
 NS_IMETHODIMP
 nsAnnotationService::GetItemAnnotationString(PRInt64 aItemId,
                                              const nsACString& aName,
                                              nsAString& _retval)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   ENSURE_ANNO_TYPE(TYPE_STRING, statement);
   rv = statement->GetString(kAnnoIndex_Content, _retval);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -848,18 +698,18 @@ nsAnnotationService::GetItemAnnotationSt
 NS_IMETHODIMP
 nsAnnotationService::GetPageAnnotation(nsIURI* aURI,
                                        const nsACString& aName,
                                        nsIVariant** _retval)
 {
   NS_ENSURE_ARG(aURI);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(aURI, 0, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
 
   nsCOMPtr<nsIWritableVariant> value = new nsVariant();
   PRInt32 type = statement->AsInt32(kAnnoIndex_Type);
   switch (type) {
@@ -896,18 +746,18 @@ nsAnnotationService::GetPageAnnotation(n
 NS_IMETHODIMP
 nsAnnotationService::GetItemAnnotation(PRInt64 aItemId,
                                        const nsACString& aName,
                                        nsIVariant** _retval)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
 
   nsCOMPtr<nsIWritableVariant> value = new nsVariant();
   PRInt32 type = statement->AsInt32(kAnnoIndex_Type);
   switch (type) {
@@ -944,18 +794,18 @@ nsAnnotationService::GetItemAnnotation(P
 NS_IMETHODIMP
 nsAnnotationService::GetPageAnnotationInt32(nsIURI* aURI,
                                         const nsACString& aName,
                                         PRInt32* _retval)
 {
   NS_ENSURE_ARG(aURI);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(aURI, 0, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   ENSURE_ANNO_TYPE(TYPE_INT32, statement);
   *_retval = statement->AsInt32(kAnnoIndex_Content);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -966,18 +816,18 @@ nsAnnotationService::GetPageAnnotationIn
 NS_IMETHODIMP
 nsAnnotationService::GetItemAnnotationInt32(PRInt64 aItemId,
                                             const nsACString& aName,
                                             PRInt32* _retval)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   ENSURE_ANNO_TYPE(TYPE_INT32, statement);
   *_retval = statement->AsInt32(kAnnoIndex_Content);
 
   return NS_OK;
@@ -987,18 +837,18 @@ nsAnnotationService::GetItemAnnotationIn
 NS_IMETHODIMP
 nsAnnotationService::GetPageAnnotationInt64(nsIURI* aURI,
                                             const nsACString& aName,
                                             PRInt64* _retval)
 {
   NS_ENSURE_ARG(aURI);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(aURI, 0, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   ENSURE_ANNO_TYPE(TYPE_INT64, statement);
   *_retval = statement->AsInt64(kAnnoIndex_Content);
 
   return NS_OK;
@@ -1008,18 +858,18 @@ nsAnnotationService::GetPageAnnotationIn
 NS_IMETHODIMP
 nsAnnotationService::GetItemAnnotationInt64(PRInt64 aItemId,
                                             const nsACString& aName,
                                             PRInt64* _retval)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   ENSURE_ANNO_TYPE(TYPE_INT64, statement);
   *_retval = statement->AsInt64(kAnnoIndex_Content);
 
   return NS_OK;
@@ -1029,18 +879,18 @@ nsAnnotationService::GetItemAnnotationIn
 NS_IMETHODIMP
 nsAnnotationService::GetPageAnnotationType(nsIURI* aURI,
                                            const nsACString& aName,
                                            PRUint16* _retval)
 {
   NS_ENSURE_ARG(aURI);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(aURI, 0, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   *_retval = statement->AsInt32(kAnnoIndex_Type);
 
   return NS_OK;
 }
@@ -1049,18 +899,18 @@ nsAnnotationService::GetPageAnnotationTy
 NS_IMETHODIMP
 nsAnnotationService::GetItemAnnotationType(PRInt64 aItemId,
                                            const nsACString& aName,
                                            PRUint16* _retval)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   *_retval = statement->AsInt32(kAnnoIndex_Type);
 
   return NS_OK;
 }
@@ -1069,18 +919,18 @@ nsAnnotationService::GetItemAnnotationTy
 NS_IMETHODIMP
 nsAnnotationService::GetPageAnnotationDouble(nsIURI* aURI,
                                              const nsACString& aName,
                                              double* _retval)
 {
   NS_ENSURE_ARG(aURI);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(aURI, 0, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   ENSURE_ANNO_TYPE(TYPE_DOUBLE, statement);
   *_retval = statement->AsDouble(kAnnoIndex_Content);
 
   return NS_OK;
@@ -1089,18 +939,18 @@ nsAnnotationService::GetPageAnnotationDo
 
 NS_IMETHODIMP
 nsAnnotationService::GetItemAnnotationDouble(PRInt64 aItemId,
                                              const nsACString& aName,
                                              double* _retval)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   ENSURE_ANNO_TYPE(TYPE_DOUBLE, statement);
   *_retval = statement->AsDouble(kAnnoIndex_Content);
 
   return NS_OK;
@@ -1113,18 +963,18 @@ nsAnnotationService::GetPageAnnotationBi
                                              PRUint8** _data,
                                              PRUint32* _dataLen,
                                              nsACString& _mimeType)
 {
   NS_ENSURE_ARG(aURI);
   NS_ENSURE_ARG_POINTER(_data);
   NS_ENSURE_ARG_POINTER(_dataLen);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(aURI, 0, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   ENSURE_ANNO_TYPE(TYPE_BINARY, statement);
   rv = statement->GetBlob(kAnnoIndex_Content, _dataLen, _data);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->GetUTF8String(kAnnoIndex_MimeType, _mimeType);
@@ -1140,18 +990,18 @@ nsAnnotationService::GetItemAnnotationBi
                                              PRUint8** _data,
                                              PRUint32* _dataLen,
                                              nsACString& _mimeType)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_data);
   NS_ENSURE_ARG_POINTER(_dataLen);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   ENSURE_ANNO_TYPE(TYPE_BINARY, statement);
   rv = statement->GetBlob(kAnnoIndex_Content, _dataLen, _data);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->GetUTF8String(kAnnoIndex_MimeType, _mimeType);
@@ -1169,18 +1019,18 @@ nsAnnotationService::GetPageAnnotationIn
                                            nsACString& _mimeType,
                                            PRUint16* _storageType)
 {
   NS_ENSURE_ARG(aURI);
   NS_ENSURE_ARG_POINTER(_flags);
   NS_ENSURE_ARG_POINTER(_expiration);
   NS_ENSURE_ARG_POINTER(_storageType);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(aURI, 0, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(aURI, 0, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   *_flags = statement->AsInt32(kAnnoIndex_Flags);
   *_expiration = (PRUint16)statement->AsInt32(kAnnoIndex_Expiration);
   rv = statement->GetUTF8String(kAnnoIndex_MimeType, _mimeType);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1205,18 +1055,18 @@ nsAnnotationService::GetItemAnnotationIn
                                            nsACString& _mimeType,
                                            PRUint16* _storageType)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_POINTER(_flags);
   NS_ENSURE_ARG_POINTER(_expiration);
   NS_ENSURE_ARG_POINTER(_storageType);
 
-  mozIStorageStatement* statement;
-  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, &statement);
+  nsCOMPtr<mozIStorageStatement> statement;
+  nsresult rv = StartGetAnnotation(nsnull, aItemId, aName, statement);
   if (NS_FAILED(rv))
     return rv;
 
   mozStorageStatementScoper scoper(statement);
   *_flags = statement->AsInt32(kAnnoIndex_Flags);
   *_expiration = (PRUint16)statement->AsInt32(kAnnoIndex_Expiration);
   rv = statement->GetUTF8String(kAnnoIndex_MimeType, _mimeType);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1267,17 +1117,26 @@ nsAnnotationService::GetPagesWithAnnotat
   return NS_OK;
 }
 
 
 nsresult
 nsAnnotationService::GetPagesWithAnnotationCOMArray(const nsACString& aName,
                                                     nsCOMArray<nsIURI>* _results)
 {
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetPagesWithAnnotation);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT h.url "
+    "FROM moz_anno_attributes n "
+    "JOIN moz_annos a ON n.id = a.anno_attribute_id "
+    "JOIN moz_places h ON h.id = a.place_id "
+    "WHERE n.name = :anno_name"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasMore = false;
   while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasMore)) &&
          hasMore) {
     nsCAutoString uristring;
     rv = stmt->GetUTF8String(0, uristring);
@@ -1330,17 +1189,25 @@ nsAnnotationService::GetItemsWithAnnotat
   return NS_OK;
 }
 
 
 nsresult
 nsAnnotationService::GetItemsWithAnnotationTArray(const nsACString& aName,
                                                   nsTArray<PRInt64>* _results)
 {
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetItemsWithAnnotation);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT a.item_id "
+    "FROM moz_anno_attributes n "
+    "JOIN moz_items_annos a ON n.id = a.anno_attribute_id "
+    "WHERE n.name = :anno_name"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasMore = false;
   while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) &&
          hasMore) {
     if (!_results->AppendElement(stmt->AsInt64(0)))
       return NS_ERROR_OUT_OF_MEMORY;
@@ -1392,24 +1259,40 @@ nsAnnotationService::GetPageAnnotationNa
 }
 
 
 nsresult
 nsAnnotationService::GetAnnotationNamesTArray(nsIURI* aURI,
                                               PRInt64 aItemId,
                                               nsTArray<nsCString>* _result)
 {
-  bool isItemAnnotation = (aItemId > 0);
-  mozIStorageStatement* statement = isItemAnnotation ?
-    GetStatement(mDBGetAnnotationsForItem) : GetStatement(mDBGetAnnotationsForPage);
-  NS_ENSURE_STATE(statement);
-
   _result->Clear();
 
+  bool isItemAnnotation = (aItemId > 0);
+  nsCOMPtr<mozIStorageStatement> statement;
+  if (isItemAnnotation) {
+    statement = mDB->GetStatement(
+      "SELECT n.name "
+      "FROM moz_anno_attributes n "
+      "JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
+      "WHERE a.item_id = :item_id"
+    );
+  }
+  else {
+    statement = mDB->GetStatement(
+      "SELECT n.name "
+      "FROM moz_anno_attributes n "
+      "JOIN moz_annos a ON a.anno_attribute_id = n.id "
+      "JOIN moz_places h ON h.id = a.place_id "
+      "WHERE h.url = :page_url"
+    );
+  }
+  NS_ENSURE_STATE(statement);
   mozStorageStatementScoper scoper(statement);
+
   nsresult rv;
   if (isItemAnnotation)
     rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   else
     rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult = false;
@@ -1504,18 +1387,33 @@ nsAnnotationService::ItemHasAnnotation(P
  *       It will be cleaned up by expiration.
  */
 nsresult
 nsAnnotationService::RemoveAnnotationInternal(nsIURI* aURI,
                                               PRInt64 aItemId,
                                               const nsACString& aName)
 {
   bool isItemAnnotation = (aItemId > 0);
-  mozIStorageStatement* statement = isItemAnnotation ?
-    GetStatement(mDBRemoveItemAnnotation) : GetStatement(mDBRemovePageAnnotation);
+  nsCOMPtr<mozIStorageStatement> statement;
+  if (isItemAnnotation) {
+    statement = mDB->GetStatement(
+      "DELETE FROM moz_items_annos "
+      "WHERE item_id = :item_id "
+        "AND anno_attribute_id = "
+          "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"
+    );
+  }
+  else {
+    statement = mDB->GetStatement(
+      "DELETE FROM moz_annos "
+      "WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
+        "AND anno_attribute_id = "
+          "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name)"
+    );
+  }
   NS_ENSURE_STATE(statement);
   mozStorageStatementScoper scoper(statement);
 
   nsresult rv;
   if (isItemAnnotation)
     rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   else
     rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
@@ -1562,23 +1460,24 @@ nsAnnotationService::RemoveItemAnnotatio
 
 
 NS_IMETHODIMP
 nsAnnotationService::RemovePageAnnotations(nsIURI* aURI)
 {
   NS_ENSURE_ARG(aURI);
 
   // Should this be precompiled or a getter?
-  nsCOMPtr<mozIStorageStatement> statement;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "DELETE FROM moz_annos WHERE place_id = "
-        "(SELECT id FROM moz_places WHERE url = :page_url)"),
-    getter_AddRefs(statement));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
+  nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
+    "DELETE FROM moz_annos WHERE place_id = "
+      "(SELECT id FROM moz_places WHERE url = :page_url)"
+  );
+  NS_ENSURE_STATE(statement);
+  mozStorageStatementScoper scoper(statement);
+
+  nsresult rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = statement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Update observers
   NOTIFY_ANNOS_OBSERVERS(OnPageAnnotationRemoved(aURI, EmptyCString()));
 
@@ -1587,22 +1486,23 @@ nsAnnotationService::RemovePageAnnotatio
 
 
 NS_IMETHODIMP
 nsAnnotationService::RemoveItemAnnotations(PRInt64 aItemId)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   // Should this be precompiled or a getter?
-  nsCOMPtr<mozIStorageStatement> statement;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "DELETE FROM moz_items_annos WHERE item_id = :item_id"),
-    getter_AddRefs(statement));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
+  nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
+    "DELETE FROM moz_items_annos WHERE item_id = :item_id"
+  );
+  NS_ENSURE_STATE(statement);
+  mozStorageStatementScoper scoper(statement);
+
+  nsresult rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = statement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   NOTIFY_ANNOS_OBSERVERS(OnItemAnnotationRemoved(aItemId, EmptyCString()));
 
   return NS_OK;
@@ -1620,49 +1520,49 @@ nsAnnotationService::CopyPageAnnotations
                                          bool aOverwriteDest)
 {
   NS_ENSURE_ARG(aSourceURI);
   NS_ENSURE_ARG(aDestURI);
 
   if (InPrivateBrowsingMode())
     return NS_OK;
 
-  mozStorageTransaction transaction(mDBConn, false);
+  mozStorageTransaction transaction(mDB->MainConn(), false);
 
-  nsCOMPtr<mozIStorageStatement> sourceStmt;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+  nsCOMPtr<mozIStorageStatement> sourceStmt = mDB->GetStatement(
     "SELECT h.id, n.id, n.name, a2.id "
     "FROM moz_places h "
     "JOIN moz_annos a ON a.place_id = h.id "
     "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id "
     "LEFT JOIN moz_annos a2 ON a2.place_id = "
       "(SELECT id FROM moz_places WHERE url = :dest_url) "
                           "AND a2.anno_attribute_id = n.id "
-    "WHERE url = :source_url"),
-    getter_AddRefs(sourceStmt));
-  NS_ENSURE_SUCCESS(rv, rv);
+    "WHERE url = :source_url"
+  );
+  NS_ENSURE_STATE(sourceStmt);
+  mozStorageStatementScoper sourceScoper(sourceStmt);
 
-  rv = URIBinder::Bind(sourceStmt, NS_LITERAL_CSTRING("source_url"), aSourceURI);
+  nsresult rv = URIBinder::Bind(sourceStmt, NS_LITERAL_CSTRING("source_url"), aSourceURI);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = URIBinder::Bind(sourceStmt, NS_LITERAL_CSTRING("dest_url"), aDestURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<mozIStorageStatement> copyStmt;
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "INSERT INTO moz_annos "
-      "(place_id, anno_attribute_id, mime_type, content, flags, expiration, "
-       "type, dateAdded, lastModified) "
-      "SELECT (SELECT id FROM moz_places WHERE url = :page_url), "
-             "anno_attribute_id, mime_type, content, flags, expiration, type, "
-             ":date, :date "
-      "FROM moz_annos "
-      "WHERE place_id = :page_id "
-      "AND anno_attribute_id = :name_id"),
-    getter_AddRefs(copyStmt));
-  NS_ENSURE_SUCCESS(rv, rv);
+  nsCOMPtr<mozIStorageStatement> copyStmt = mDB->GetStatement(
+    "INSERT INTO moz_annos "
+    "(place_id, anno_attribute_id, mime_type, content, flags, expiration, "
+     "type, dateAdded, lastModified) "
+    "SELECT (SELECT id FROM moz_places WHERE url = :page_url), "
+           "anno_attribute_id, mime_type, content, flags, expiration, type, "
+           ":date, :date "
+    "FROM moz_annos "
+    "WHERE place_id = :page_id "
+    "AND anno_attribute_id = :name_id"
+  );
+  NS_ENSURE_STATE(copyStmt);
+  mozStorageStatementScoper copyScoper(copyStmt);
 
   bool hasResult;
   while (NS_SUCCEEDED(sourceStmt->ExecuteStep(&hasResult)) && hasResult) {
     PRInt64 sourcePlaceId = sourceStmt->AsInt64(0);
     PRInt64 annoNameID = sourceStmt->AsInt64(1);
     nsCAutoString annoName;
     rv = sourceStmt->GetUTF8String(2, annoName);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1702,47 +1602,47 @@ nsAnnotationService::CopyPageAnnotations
 NS_IMETHODIMP
 nsAnnotationService::CopyItemAnnotations(PRInt64 aSourceItemId,
                                          PRInt64 aDestItemId,
                                          bool aOverwriteDest)
 {
   NS_ENSURE_ARG_MIN(aSourceItemId, 1);
   NS_ENSURE_ARG_MIN(aDestItemId, 1);
 
-  mozStorageTransaction transaction(mDBConn, false);
+  mozStorageTransaction transaction(mDB->MainConn(), false);
 
-  nsCOMPtr<mozIStorageStatement> sourceStmt;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+  nsCOMPtr<mozIStorageStatement> sourceStmt = mDB->GetStatement(
     "SELECT n.id, n.name, a2.id "
     "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 "
     "LEFT JOIN moz_items_annos a2 ON a2.item_id = :dest_item_id "
                                 "AND a2.anno_attribute_id = n.id "
-    "WHERE b.id = :source_item_id"),
-    getter_AddRefs(sourceStmt));
-  NS_ENSURE_SUCCESS(rv, rv);
+    "WHERE b.id = :source_item_id"
+  );
+  NS_ENSURE_STATE(sourceStmt);
+  mozStorageStatementScoper sourceScoper(sourceStmt);
 
-  rv = sourceStmt->BindInt64ByName(NS_LITERAL_CSTRING("source_item_id"), aSourceItemId);
+  nsresult rv = sourceStmt->BindInt64ByName(NS_LITERAL_CSTRING("source_item_id"), aSourceItemId);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = sourceStmt->BindInt64ByName(NS_LITERAL_CSTRING("dest_item_id"), aDestItemId);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  nsCOMPtr<mozIStorageStatement> copyStmt;
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+  nsCOMPtr<mozIStorageStatement> copyStmt = mDB->GetStatement(
       "INSERT OR REPLACE INTO moz_items_annos "
       "(item_id, anno_attribute_id, mime_type, content, flags, expiration, "
        "type, dateAdded, lastModified) "
       "SELECT :dest_item_id, anno_attribute_id, mime_type, content, flags, expiration, "
              "type, :date, :date "
       "FROM moz_items_annos "
       "WHERE item_id = :source_item_id "
-      "AND anno_attribute_id = :name_id"),
-    getter_AddRefs(copyStmt));
-  NS_ENSURE_SUCCESS(rv, rv);
+      "AND anno_attribute_id = :name_id"
+  );
+  NS_ENSURE_STATE(copyStmt);
+  mozStorageStatementScoper copyScoper(copyStmt);
 
   bool hasResult;
   while (NS_SUCCEEDED(sourceStmt->ExecuteStep(&hasResult)) && hasResult) {
     PRInt64 annoNameID = sourceStmt->AsInt64(0);
     nsCAutoString annoName;
     rv = sourceStmt->GetUTF8String(1, annoName);
     NS_ENSURE_SUCCESS(rv, rv);
     PRInt64 annoExistsOnDest = sourceStmt->AsInt64(2);
@@ -1830,18 +1730,39 @@ nsAnnotationService::GetAnnotationURI(ns
 
 nsresult
 nsAnnotationService::HasAnnotationInternal(nsIURI* aURI,
                                            PRInt64 aItemId,
                                            const nsACString& aName,
                                            bool* _hasAnno)
 {
   bool isItemAnnotation = (aItemId > 0);
-  mozIStorageStatement* stmt = isItemAnnotation ?
-    GetStatement(mDBCheckItemAnnotation) : GetStatement(mDBCheckPageAnnotation);
+  nsCOMPtr<mozIStorageStatement> stmt;
+  if (isItemAnnotation) {
+    stmt = mDB->GetStatement(
+      "SELECT b.id, "
+             "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
+             "a.id, a.dateAdded "
+      "FROM moz_bookmarks b "
+      "LEFT JOIN moz_items_annos a ON a.item_id = b.id "
+                                 "AND a.anno_attribute_id = nameid "
+      "WHERE b.id = :item_id"
+    );
+  }
+  else {
+    stmt = mDB->GetStatement(
+      "SELECT h.id, "
+             "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
+             "a.id, a.dateAdded "
+      "FROM moz_places h "
+      "LEFT JOIN moz_annos a ON a.place_id = h.id "
+                           "AND a.anno_attribute_id = nameid "
+      "WHERE h.url = :page_url"
+    );
+  }
   NS_ENSURE_STATE(stmt);
   mozStorageStatementScoper checkAnnoScoper(stmt);
 
   nsresult rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
   NS_ENSURE_SUCCESS(rv, rv);
   if (isItemAnnotation)
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   else
@@ -1875,37 +1796,56 @@ nsAnnotationService::HasAnnotationIntern
  * @note You have to reset the statement when you're done if this succeeds.
  * @throws NS_ERROR_NOT_AVAILABLE if the annotation is not found.
  */
 
 nsresult
 nsAnnotationService::StartGetAnnotation(nsIURI* aURI,
                                         PRInt64 aItemId,
                                         const nsACString& aName,
-                                        mozIStorageStatement** _statement)
+                                        nsCOMPtr<mozIStorageStatement>& aStatement)
 {
   bool isItemAnnotation = (aItemId > 0);
 
-  *_statement = isItemAnnotation ? GetStatement(mDBGetItemAnnotationValue)
-                                 : GetStatement(mDBGetPageAnnotationValue);
-  NS_ENSURE_STATE(*_statement);
-  mozStorageStatementScoper getAnnoScoper(*_statement);
+  if (isItemAnnotation) {
+    aStatement = mDB->GetStatement(
+      "SELECT a.id, a.item_id, :anno_name, a.mime_type, a.content, a.flags, "
+             "a.expiration, a.type "
+      "FROM moz_anno_attributes n "
+      "JOIN moz_items_annos a ON a.anno_attribute_id = n.id "
+      "WHERE a.item_id = :item_id "
+      "AND n.name = :anno_name"
+    );
+  }
+  else {
+    aStatement = mDB->GetStatement(
+      "SELECT a.id, a.place_id, :anno_name, a.mime_type, a.content, a.flags, "
+             "a.expiration, a.type "
+      "FROM moz_anno_attributes n "
+      "JOIN moz_annos a ON n.id = a.anno_attribute_id "
+      "JOIN moz_places h ON h.id = a.place_id "
+      "WHERE h.url = :page_url "
+        "AND n.name = :anno_name"
+    );
+  }
+  NS_ENSURE_STATE(aStatement);
+  mozStorageStatementScoper getAnnoScoper(aStatement);
 
   nsresult rv;
   if (isItemAnnotation)
-    rv = (*_statement)->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
+    rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   else
-    rv = URIBinder::Bind(*_statement, NS_LITERAL_CSTRING("page_url"), aURI);
+    rv = URIBinder::Bind(aStatement, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = (*_statement)->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
+  rv = aStatement->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult = false;
-  rv = (*_statement)->ExecuteStep(&hasResult);
+  rv = aStatement->ExecuteStep(&hasResult);
   if (NS_FAILED(rv) || !hasResult)
     return NS_ERROR_NOT_AVAILABLE;
 
   // on success, DON'T reset the statement, the caller needs to read from it,
   // and it is the caller's job to reset it.
   getAnnoScoper.Abandon();
 
   return NS_OK;
@@ -1931,39 +1871,66 @@ nsAnnotationService::InPrivateBrowsingMo
  */
 nsresult
 nsAnnotationService::StartSetAnnotation(nsIURI* aURI,
                                         PRInt64 aItemId,
                                         const nsACString& aName,
                                         PRInt32 aFlags,
                                         PRUint16 aExpiration,
                                         PRUint16 aType,
-                                        mozIStorageStatement** _statement)
+                                        nsCOMPtr<mozIStorageStatement>& aStatement)
 {
   bool isItemAnnotation = (aItemId > 0);
 
   // Ensure the annotation name exists.
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(addNameStmt, mDBAddAnnotationName);
+  nsCOMPtr<mozIStorageStatement> addNameStmt = mDB->GetStatement(
+    "INSERT OR IGNORE INTO moz_anno_attributes (name) VALUES (:anno_name)"
+  );
+  NS_ENSURE_STATE(addNameStmt);
+  mozStorageStatementScoper scoper(addNameStmt);
+
   nsresult rv = addNameStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = addNameStmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // We have to check 2 things:
   // - if the annotation already exists we should update it.
   // - we should not allow setting annotations on invalid URIs or itemIds.
   // This query will tell us:
   // - whether the item or page exists.
   // - whether the annotation already exists.
   // - the nameID associated with the annotation name.
   // - the id and dateAdded of the old annotation, if it exists.
-  mozIStorageStatement* stmt = isItemAnnotation ?
-    GetStatement(mDBCheckItemAnnotation) : GetStatement(mDBCheckPageAnnotation);
+  nsCOMPtr<mozIStorageStatement> stmt;
+  if (isItemAnnotation) {
+    stmt = mDB->GetStatement(
+      "SELECT b.id, "
+             "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
+             "a.id, a.dateAdded "
+      "FROM moz_bookmarks b "
+      "LEFT JOIN moz_items_annos a ON a.item_id = b.id "
+                                 "AND a.anno_attribute_id = nameid "
+      "WHERE b.id = :item_id"
+    );
+  }
+  else {
+    stmt = mDB->GetStatement(
+      "SELECT h.id, "
+             "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS nameid, "
+             "a.id, a.dateAdded "
+      "FROM moz_places h "
+      "LEFT JOIN moz_annos a ON a.place_id = h.id "
+                           "AND a.anno_attribute_id = nameid "
+      "WHERE h.url = :page_url"
+    );
+  }
   NS_ENSURE_STATE(stmt);
   mozStorageStatementScoper checkAnnoScoper(stmt);
+
   rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"), aName);
   NS_ENSURE_SUCCESS(rv, rv);
   if (isItemAnnotation)
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   else
     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1976,76 +1943,63 @@ nsAnnotationService::StartSetAnnotation(
     return NS_ERROR_INVALID_ARG;
   }
 
   PRInt64 fkId = stmt->AsInt64(0);
   PRInt64 nameID = stmt->AsInt64(1);
   PRInt64 oldAnnoId = stmt->AsInt64(2);
   PRInt64 oldAnnoDate = stmt->AsInt64(3);
 
-  *_statement = isItemAnnotation ? GetStatement(mDBAddItemAnnotation)
-                                 : GetStatement(mDBAddPageAnnotation);
-  NS_ENSURE_STATE(*_statement);
-  mozStorageStatementScoper setAnnoScoper(*_statement);
+  if (isItemAnnotation) {
+    aStatement = mDB->GetStatement(
+      "INSERT OR REPLACE INTO moz_items_annos "
+        "(id, item_id, anno_attribute_id, mime_type, content, flags, "
+         "expiration, type, dateAdded, lastModified) "
+      "VALUES (:id, :fk, :name_id, :mime_type, :content, :flags, "
+      ":expiration, :type, :date_added, :last_modified)"
+    );
+  }
+  else {
+    aStatement = mDB->GetStatement(
+      "INSERT OR REPLACE INTO moz_annos "
+        "(id, place_id, anno_attribute_id, mime_type, content, flags, "
+         "expiration, type, dateAdded, lastModified) "
+      "VALUES (:id, :fk, :name_id, :mime_type, :content, :flags, "
+      ":expiration, :type, :date_added, :last_modified)"
+    );
+  }
+  NS_ENSURE_STATE(aStatement);
+  mozStorageStatementScoper setAnnoScoper(aStatement);
 
   // Don't replace existing annotations.
   if (oldAnnoId > 0) {
-    rv = (*_statement)->BindInt64ByName(NS_LITERAL_CSTRING("id"), oldAnnoId);
+    rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), oldAnnoId);
     NS_ENSURE_SUCCESS(rv, rv);
-    rv = (*_statement)->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), oldAnnoDate);
+    rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), oldAnnoDate);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
-    rv = (*_statement)->BindNullByName(NS_LITERAL_CSTRING("id"));
+    rv = aStatement->BindNullByName(NS_LITERAL_CSTRING("id"));
     NS_ENSURE_SUCCESS(rv, rv);
-    rv = (*_statement)->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), PR_Now());
+    rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), PR_Now());
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  rv = (*_statement)->BindInt64ByName(NS_LITERAL_CSTRING("fk"), fkId);
+  rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("fk"), fkId);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = (*_statement)->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), nameID);
+  rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), nameID);
   NS_ENSURE_SUCCESS(rv, rv);
   // MimeType and Content will be bound by the caller.
-  rv = (*_statement)->BindInt32ByName(NS_LITERAL_CSTRING("flags"), aFlags);
+  rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("flags"), aFlags);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = (*_statement)->BindInt32ByName(NS_LITERAL_CSTRING("expiration"), aExpiration);
+  rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("expiration"), aExpiration);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = (*_statement)->BindInt32ByName(NS_LITERAL_CSTRING("type"), aType);
+  rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("type"), aType);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = (*_statement)->BindInt64ByName(NS_LITERAL_CSTRING("last_modified"), PR_Now());
+  rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("last_modified"), PR_Now());
   NS_ENSURE_SUCCESS(rv, rv);
 
   // on success, leave the statement open, the caller will set the value
   // and MIME type and execute the statement
   setAnnoScoper.Abandon();
 
   return NS_OK;
 }
-
-
-nsresult
-nsAnnotationService::FinalizeStatements() {
-  mShuttingDown = true;
-
-  mozIStorageStatement* stmts[] = {
-    mDBGetAnnotationsForPage
-  , mDBGetAnnotationsForItem
-  , mDBGetPageAnnotationValue
-  , mDBGetItemAnnotationValue
-  , mDBAddAnnotationName
-  , mDBAddPageAnnotation
-  , mDBAddItemAnnotation
-  , mDBRemovePageAnnotation
-  , mDBRemoveItemAnnotation
-  , mDBGetPagesWithAnnotation
-  , mDBGetItemsWithAnnotation
-  , mDBCheckPageAnnotation
-  , mDBCheckItemAnnotation
-  };
-
-  for (PRUint32 i = 0; i < ArrayLength(stmts); i++) {
-    nsresult rv = nsNavHistory::FinalizeStatement(stmts[i]);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return NS_OK;
-}
--- a/toolkit/components/places/nsAnnotationService.h
+++ b/toolkit/components/places/nsAnnotationService.h
@@ -39,38 +39,35 @@
 
 #ifndef nsAnnotationService_h___
 #define nsAnnotationService_h___
 
 #include "nsIAnnotationService.h"
 #include "nsTArray.h"
 #include "nsCOMArray.h"
 #include "nsCOMPtr.h"
-#include "mozIStorageService.h"
-#include "mozIStorageConnection.h"
 #include "nsServiceManagerUtils.h"
 #include "nsToolkitCompsCID.h"
+#include "Database.h"
 
 class nsAnnotationService : public nsIAnnotationService
 {
 public:
   nsAnnotationService();
 
   /**
    * Obtains the service's object.
    */
   static nsAnnotationService* GetSingleton();
 
   /**
    * Initializes the service's object.  This should only be called once.
    */
   nsresult Init();
 
-  static nsresult InitTables(mozIStorageConnection* aDBConn);
-
   static nsAnnotationService* GetAnnotationServiceIfAvailable() {
     return gAnnotationService;
   }
 
   /**
    * Returns a cached pointer to the annotation service for consumers in the
    * places directory.
    */
@@ -81,48 +78,24 @@ public:
         do_GetService(NS_ANNOTATIONSERVICE_CONTRACTID);
       NS_ENSURE_TRUE(serv, nsnull);
       NS_ASSERTION(gAnnotationService,
                    "Should have static instance pointer now");
     }
     return gAnnotationService;
   }
 
-  /**
-   * Finalize all internal statements.
-   */
-  nsresult FinalizeStatements();
-
   NS_DECL_ISUPPORTS
   NS_DECL_NSIANNOTATIONSERVICE
 
 private:
   ~nsAnnotationService();
 
 protected:
-  nsCOMPtr<mozIStorageService> mDBService;
-  nsCOMPtr<mozIStorageConnection> mDBConn;
-
-  /**
-   * Always use this getter and never use directly the statement nsCOMPtr.
-   */
-  mozIStorageStatement* GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt);
-  nsCOMPtr<mozIStorageStatement> mDBGetAnnotationsForPage;
-  nsCOMPtr<mozIStorageStatement> mDBGetAnnotationsForItem;
-  nsCOMPtr<mozIStorageStatement> mDBGetPageAnnotationValue;
-  nsCOMPtr<mozIStorageStatement> mDBGetItemAnnotationValue;
-  nsCOMPtr<mozIStorageStatement> mDBAddAnnotationName;
-  nsCOMPtr<mozIStorageStatement> mDBAddPageAnnotation;
-  nsCOMPtr<mozIStorageStatement> mDBAddItemAnnotation;
-  nsCOMPtr<mozIStorageStatement> mDBRemovePageAnnotation;
-  nsCOMPtr<mozIStorageStatement> mDBRemoveItemAnnotation;
-  nsCOMPtr<mozIStorageStatement> mDBGetPagesWithAnnotation;
-  nsCOMPtr<mozIStorageStatement> mDBGetItemsWithAnnotation;
-  nsCOMPtr<mozIStorageStatement> mDBCheckPageAnnotation;
-  nsCOMPtr<mozIStorageStatement> mDBCheckItemAnnotation;
+  nsRefPtr<mozilla::places::Database> mDB;
 
   nsCOMArray<nsIAnnotationObserver> mObservers;
 
   static nsAnnotationService* gAnnotationService;
 
   static const int kAnnoIndex_ID;
   static const int kAnnoIndex_PageOrItem;
   static const int kAnnoIndex_NameID;
@@ -137,25 +110,25 @@ protected:
   nsresult HasAnnotationInternal(nsIURI* aURI,
                                  PRInt64 aItemId,
                                  const nsACString& aName,
                                  bool* _hasAnno);
 
   nsresult StartGetAnnotation(nsIURI* aURI,
                               PRInt64 aItemId,
                               const nsACString& aName,
-                              mozIStorageStatement** _statement);
+                              nsCOMPtr<mozIStorageStatement>& aStatement);
 
   nsresult StartSetAnnotation(nsIURI* aURI,
                               PRInt64 aItemId,
                               const nsACString& aName,
                               PRInt32 aFlags,
                               PRUint16 aExpiration,
                               PRUint16 aType,
-                              mozIStorageStatement** _statement);
+                              nsCOMPtr<mozIStorageStatement>& aStatement);
 
   nsresult SetAnnotationStringInternal(nsIURI* aURI,
                                        PRInt64 aItemId,
                                        const nsACString& aName,
                                        const nsAString& aValue,
                                        PRInt32 aFlags,
                                        PRUint16 aExpiration);
   nsresult SetAnnotationInt32Internal(nsIURI* aURI,
@@ -186,18 +159,16 @@ protected:
                                        PRUint16 aExpiration);
 
   nsresult RemoveAnnotationInternal(nsIURI* aURI,
                                     PRInt64 aItemId,
                                     const nsACString& aName);
 
   bool InPrivateBrowsingMode() const;
 
-  bool mShuttingDown;
-
 public:
   nsresult GetPagesWithAnnotationCOMArray(const nsACString& aName,
                                           nsCOMArray<nsIURI>* _results);
   nsresult GetItemsWithAnnotationTArray(const nsACString& aName,
                                         nsTArray<PRInt64>* _result);
   nsresult GetAnnotationNamesTArray(nsIURI* aURI,
                                     PRInt64 aItemId,
                                     nsTArray<nsCString>* _result);
--- a/toolkit/components/places/nsFaviconService.cpp
+++ b/toolkit/components/places/nsFaviconService.cpp
@@ -44,35 +44,31 @@
  * This is the favicon service, which stores favicons for web pages with your
  * history as you browse. It is also used to save the favicons for bookmarks.
  *
  * DANGER: The history query system makes assumptions about the favicon storage
  * so that icons can be quickly generated for history/bookmark result sets. If
  * you change the database layout at all, you will have to update both services.
  */
 
-#include "mozilla/Util.h"
-
 #include "nsFaviconService.h"
 
-#include "nsPlacesTables.h"
+#include "nsNavHistory.h"
 #include "nsPlacesMacros.h"
 #include "Helpers.h"
 #include "AsyncFaviconHelpers.h"
 
-#include "nsNavBookmarks.h"
-#include "nsNavHistory.h"
-#include "nsIPrefService.h"
-
 #include "nsNetUtil.h"
 #include "nsReadableUtils.h"
 #include "nsStreamUtils.h"
 #include "nsStringStream.h"
 #include "plbase64.h"
 #include "nsIClassInfoImpl.h"
+#include "mozilla/Preferences.h"
+#include "mozilla/Util.h"
 
 // For large favicons optimization.
 #include "imgITools.h"
 #include "imgIContainer.h"
 
 // Default value for mOptimizedIconDimension
 #define OPTIMIZED_FAVICON_DIMENSION 16
 
@@ -114,21 +110,19 @@ PLACES_FACTORY_SINGLETON_IMPLEMENTATION(
 NS_IMPL_CLASSINFO(nsFaviconService, NULL, 0, NS_FAVICONSERVICE_CID)
 NS_IMPL_ISUPPORTS2_CI(
   nsFaviconService
 , nsIFaviconService
 , mozIAsyncFavicons
 )
 
 nsFaviconService::nsFaviconService()
-: mSyncStatements(mDBConn)
-, mFaviconsExpirationRunning(false)
-, mOptimizedIconDimension(OPTIMIZED_FAVICON_DIMENSION)
-, mFailedFaviconSerial(0)
-, mShuttingDown(false)
+  : mFaviconsExpirationRunning(false)
+  , mOptimizedIconDimension(OPTIMIZED_FAVICON_DIMENSION)
+  , mFailedFaviconSerial(0)
 {
   NS_ASSERTION(!gFaviconService,
                "Attempting to create two instances of the service!");
   gFaviconService = this;
 }
 
 
 nsFaviconService::~nsFaviconService()
@@ -138,118 +132,57 @@ nsFaviconService::~nsFaviconService()
   if (gFaviconService == this)
     gFaviconService = nsnull;
 }
 
 
 nsresult
 nsFaviconService::Init()
 {
-  // Creation of history service will call InitTables.
-  nsNavHistory* historyService = nsNavHistory::GetHistoryService();
-  NS_ENSURE_TRUE(historyService, NS_ERROR_OUT_OF_MEMORY);
-  mDBConn = historyService->GetStorageConnection();
-  NS_ENSURE_TRUE(mDBConn, NS_ERROR_FAILURE);
+  mDB = Database::GetDatabase();
+  NS_ENSURE_STATE(mDB);
 
   // Init failed favicon cache.
   if (!mFailedFavicons.Init(MAX_FAVICON_CACHE_SIZE))
     return NS_ERROR_OUT_OF_MEMORY;
 
-  nsCOMPtr<nsIPrefBranch> pb = do_GetService(NS_PREFSERVICE_CONTRACTID);
-  if (pb) {
-    (void)pb->GetIntPref("places.favicons.optimizeToDimension",
-                         &mOptimizedIconDimension);
-  }
+  mOptimizedIconDimension = Preferences::GetInt(
+    "places.favicons.optimizeToDimension", OPTIMIZED_FAVICON_DIMENSION
+  );
 
   return NS_OK;
 }
 
-
-mozIStorageStatement*
-nsFaviconService::GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt)
-{
-  if (mShuttingDown)
-    return nsnull;
-
-  RETURN_IF_STMT(mDBGetIconInfo, NS_LITERAL_CSTRING(
-    "SELECT id, length(data), expiration FROM moz_favicons "
-    "WHERE url = :icon_url"));
-
-  RETURN_IF_STMT(mDBGetURL, 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 = :page_url "
-    "LIMIT 1"));
-
-  RETURN_IF_STMT(mDBGetData, NS_LITERAL_CSTRING(
-    "SELECT f.data, f.mime_type FROM moz_favicons f WHERE url = :icon_url"));
-
-  RETURN_IF_STMT(mDBInsertIcon, NS_LITERAL_CSTRING(
-    "INSERT INTO moz_favicons (id, url, data, mime_type, expiration) "
-      "VALUES (:icon_id, :icon_url, :data, :mime_type, :expiration)"));
-
-  RETURN_IF_STMT(mDBUpdateIcon, NS_LITERAL_CSTRING(
-    "UPDATE moz_favicons SET data = :data, mime_type = :mime_type, "
-                            "expiration = :expiration "
-    "WHERE id = :icon_id"));
-
-  RETURN_IF_STMT(mDBSetPageFavicon, NS_LITERAL_CSTRING(
-    "UPDATE moz_places SET favicon_id = :icon_id WHERE id = :page_id"));
-
-  RETURN_IF_STMT(mDBRemoveOnDiskReferences, NS_LITERAL_CSTRING(
-    "UPDATE moz_places "
-    "SET favicon_id = NULL "
-    "WHERE favicon_id NOT NULL"));
-
-  RETURN_IF_STMT(mDBRemoveAllFavicons, NS_LITERAL_CSTRING(
-    "DELETE FROM moz_favicons WHERE id NOT IN ("
-      "SELECT favicon_id FROM moz_places WHERE favicon_id NOT NULL "
-    ")"));
-
-  return nsnull;
-}
-
-
-// nsFaviconService::InitTables
-//
-//    Called by the history service to create the favicon table. The history
-//    service uses this table in its queries, so it must exist even if
-//    nobody has called the favicon service.
-
-nsresult // static
-nsFaviconService::InitTables(mozIStorageConnection* aDBConn)
-{
-  nsresult rv;
-  bool exists = false;
-  aDBConn->TableExists(NS_LITERAL_CSTRING("moz_favicons"), &exists);
-  if (!exists) {
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_MOZ_FAVICONS);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return NS_OK;
-}
-
-
 NS_IMETHODIMP
 nsFaviconService::ExpireAllFavicons()
 {
   mFaviconsExpirationRunning = true;
-
-  mozIStorageBaseStatement *stmts[] = {
-    GetStatement(mDBRemoveOnDiskReferences),
-    GetStatement(mDBRemoveAllFavicons),
+  nsCOMPtr<mozIStorageAsyncStatement> unlinkIconsStmt = mDB->GetAsyncStatement(
+    "UPDATE moz_places "
+    "SET favicon_id = NULL "
+    "WHERE favicon_id NOT NULL"
+  );
+  NS_ENSURE_STATE(unlinkIconsStmt);
+  nsCOMPtr<mozIStorageAsyncStatement> removeIconsStmt = mDB->GetAsyncStatement(
+    "DELETE FROM moz_favicons WHERE id NOT IN ("
+      "SELECT favicon_id FROM moz_places WHERE favicon_id NOT NULL "
+    ")"
+  );
+  NS_ENSURE_STATE(removeIconsStmt);
+  
+  mozIStorageBaseStatement* stmts[] = {
+    unlinkIconsStmt.get()
+  , removeIconsStmt.get()
   };
-  NS_ENSURE_STATE(stmts[0] && stmts[1]);
   nsCOMPtr<mozIStoragePendingStatement> ps;
-  nsCOMPtr<ExpireFaviconsStatementCallbackNotifier> callback =
+  nsRefPtr<ExpireFaviconsStatementCallbackNotifier> callback =
     new ExpireFaviconsStatementCallbackNotifier(&mFaviconsExpirationRunning);
-  nsresult rv = mDBConn->ExecuteAsync(stmts, ArrayLength(stmts), callback,
-                                      getter_AddRefs(ps));
+  nsresult rv = mDB->MainConn()->ExecuteAsync(
+    stmts, ArrayLength(stmts), callback, getter_AddRefs(ps)
+  );
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsIFaviconService
@@ -271,17 +204,23 @@ nsFaviconService::SetFaviconUrlForPage(n
   if (history->InPrivateBrowsingMode()) {
     return NS_OK;
   }
 
   nsresult rv;
   PRInt64 iconId = -1;
   bool hasData = false;
   {
-    DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetIconInfo);
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+      "SELECT id, length(data), expiration FROM moz_favicons "
+      "WHERE url = :icon_url"
+    );
+    NS_ENSURE_STATE(stmt);
+    mozStorageStatementScoper scoper(stmt);
+
     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool hasResult = false;
     if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
       // We already have an entry for this icon, just get its stats.
       rv = stmt->GetInt64(0, &iconId);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -289,53 +228,70 @@ nsFaviconService::SetFaviconUrlForPage(n
       rv = stmt->GetInt32(1, &dataSize);
       NS_ENSURE_SUCCESS(rv, rv);
       if (dataSize > 0) {
         hasData = true;
       }
     }
   }
 
-  mozStorageTransaction transaction(mDBConn, false);
+  mozStorageTransaction transaction(mDB->MainConn(), false);
 
   if (iconId == -1) {
     // We did not find any entry for this icon, so create a new one.
-    DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBInsertIcon);
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+      "INSERT INTO moz_favicons (id, url, data, mime_type, expiration) "
+      "VALUES (:icon_id, :icon_url, :data, :mime_type, :expiration)"
+    );
+    NS_ENSURE_STATE(stmt);
+    mozStorageStatementScoper scoper(stmt);
+
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("icon_id"));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("data"));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("mime_type"));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("expiration"));
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
 
     {
-      DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(getInfoStmt, mDBGetIconInfo);
+      nsCOMPtr<mozIStorageStatement> getInfoStmt = mDB->GetStatement(
+        "SELECT id, length(data), expiration FROM moz_favicons "
+        "WHERE url = :icon_url"
+      );
+      NS_ENSURE_STATE(getInfoStmt);
+      mozStorageStatementScoper scoper(getInfoStmt);
+
       rv = URIBinder::Bind(getInfoStmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
       NS_ENSURE_SUCCESS(rv, rv);
       bool hasResult;
       rv = getInfoStmt->ExecuteStep(&hasResult);
       NS_ENSURE_SUCCESS(rv, rv);
       NS_ASSERTION(hasResult, "hasResult is false but the call succeeded?");
       iconId = getInfoStmt->AsInt64(0);
     }
   }
 
   // Now, link our icon entry with the page.
   PRInt64 pageId;
   nsCAutoString guid;
   rv = history->GetOrCreateIdForPage(aPageURI, &pageId, guid);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBSetPageFavicon);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "UPDATE moz_places SET favicon_id = :icon_id WHERE id = :page_id"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), pageId);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("icon_id"), iconId);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
@@ -402,17 +358,17 @@ nsFaviconService::SetAndLoadFaviconForPa
     else
       return NS_OK;
   }
 
   // Check if the icon already exists and fetch it from the network, if needed.
   // Finally associate the icon to the requested page if not yet associated.
   rv = AsyncFetchAndSetIconForPage::start(
     aFaviconURI, aPageURI, aForceReload ? FETCH_ALWAYS : FETCH_IF_MISSING,
-    mDBConn, aCallback
+    aCallback
   );
   NS_ENSURE_SUCCESS(rv, rv);
 
   // DB will be updated and observers notified when data has finished loading.
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -458,62 +414,76 @@ nsFaviconService::SetFaviconData(nsIURI*
     }
     else if (aDataLen > MAX_FAVICON_SIZE) {
       // We cannot optimize this favicon size and we are over the maximum size
       // allowed, so we will not save data to the db to avoid bloating it.
       return NS_ERROR_FAILURE;
     }
   }
 
-  mozIStorageStatement* statement;
+  nsCOMPtr<mozIStorageStatement> statement;
   {
     // this block forces the scoper to reset our statement: necessary for the
     // next statement
-    DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetIconInfo);
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+      "SELECT id, length(data), expiration FROM moz_favicons "
+      "WHERE url = :icon_url"
+    );
+    NS_ENSURE_STATE(stmt);
+    mozStorageStatementScoper scoper(stmt);
+
     rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool hasResult;
     rv = stmt->ExecuteStep(&hasResult);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (hasResult) {
       // Get id of the old entry and update it.
       PRInt64 id;
       rv = stmt->GetInt64(0, &id);
       NS_ENSURE_SUCCESS(rv, rv);
-      statement = GetStatement(mDBUpdateIcon);
+      statement = mDB->GetStatement(
+        "UPDATE moz_favicons SET data = :data, mime_type = :mime_type, "
+                                "expiration = :expiration "
+        "WHERE id = :icon_id"
+      );
       NS_ENSURE_STATE(statement);
+
       rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("icon_id"), id);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = statement->BindBlobByName(NS_LITERAL_CSTRING("data"), data, dataLen);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("mime_type"), *mimeType);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("expiration"), aExpiration);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     else {
       // Insert a new entry.
-      statement = GetStatement(mDBInsertIcon);
+      statement = mDB->GetStatement(
+        "INSERT INTO moz_favicons (id, url, data, mime_type, expiration) "
+        "VALUES (:icon_id, :icon_url, :data, :mime_type, :expiration)"
+      );
       NS_ENSURE_STATE(statement);
+
       rv = statement->BindNullByName(NS_LITERAL_CSTRING("icon_id"));
       NS_ENSURE_SUCCESS(rv, rv);
       rv = URIBinder::Bind(statement, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = statement->BindBlobByName(NS_LITERAL_CSTRING("data"), data, dataLen);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("mime_type"), *mimeType);
       NS_ENSURE_SUCCESS(rv, rv);
       rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("expiration"), aExpiration);
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
-
-  mozStorageStatementScoper scoper(statement);
+  mozStorageStatementScoper statementScoper(statement);
 
   rv = statement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 
@@ -605,17 +575,22 @@ nsFaviconService::GetFaviconData(nsIURI*
 
     *aData = bytes;
     *aDataLen = defaultData.Length();
     aMimeType.AssignLiteral(DEFAULT_MIME_TYPE);
 
     return NS_OK;
   }
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetData);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT f.data, f.mime_type FROM moz_favicons f WHERE url = :icon_url"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult = false;
   if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
     rv = stmt->GetUTF8String(1, aMimeType);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -688,17 +663,26 @@ nsFaviconService::GetFaviconDataAsDataUR
 
 
 NS_IMETHODIMP
 nsFaviconService::GetFaviconForPage(nsIURI* aPageURI, nsIURI** _retval)
 {
   NS_ENSURE_ARG(aPageURI);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetURL);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "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 = :page_url "
+    "LIMIT 1"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aPageURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
     nsCAutoString url;
     rv = stmt->GetUTF8String(1, url);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -711,40 +695,49 @@ nsFaviconService::GetFaviconForPage(nsIU
 
 NS_IMETHODIMP
 nsFaviconService::GetFaviconURLForPage(nsIURI *aPageURI,
                                        nsIFaviconDataCallback* aCallback)
 {
   NS_ENSURE_ARG(aPageURI);
   NS_ENSURE_ARG(aCallback);
 
-  nsresult rv = AsyncGetFaviconURLForPage::start(aPageURI, mDBConn, aCallback);
+  nsresult rv = AsyncGetFaviconURLForPage::start(aPageURI, aCallback);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFaviconService::GetFaviconDataForPage(nsIURI* aPageURI,
                                         nsIFaviconDataCallback* aCallback)
 {
   NS_ENSURE_ARG(aPageURI);
   NS_ENSURE_ARG(aCallback);
 
-  nsresult rv = AsyncGetFaviconDataForPage::start(aPageURI, mDBConn, aCallback);
+  nsresult rv = AsyncGetFaviconDataForPage::start(aPageURI, aCallback);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFaviconService::GetFaviconImageForPage(nsIURI* aPageURI, nsIURI** _retval)
 {
   NS_ENSURE_ARG(aPageURI);
   NS_ENSURE_ARG_POINTER(_retval);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetURL);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "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 = :page_url "
+    "LIMIT 1"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aPageURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   nsCOMPtr<nsIURI> faviconURI;
   if (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
     PRInt32 dataLen;
     rv = stmt->GetInt32(2, &dataLen);
@@ -933,56 +926,26 @@ nsFaviconService::OptimizeFaviconImage(c
 
   // Read the stream into a new buffer.
   rv = NS_ConsumeStream(iconStream, PR_UINT32_MAX, aNewData);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
-
-nsresult
-nsFaviconService::FinalizeStatements() {
-  mShuttingDown = true;
-
-  mozIStorageStatement* stmts[] = {
-    mDBGetURL,
-    mDBGetData,
-    mDBGetIconInfo,
-    mDBInsertIcon,
-    mDBUpdateIcon,
-    mDBSetPageFavicon,
-    mDBRemoveOnDiskReferences,
-    mDBRemoveAllFavicons,
-  };
-
-  for (PRUint32 i = 0; i < ArrayLength(stmts); i++) {
-    nsresult rv = nsNavHistory::FinalizeStatement(stmts[i]);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // Finalize the statementCache on the correct thread.
-  nsRefPtr<FinalizeStatementCacheProxy<mozIStorageStatement> > event =
-    new FinalizeStatementCacheProxy<mozIStorageStatement>(
-        mSyncStatements, NS_ISUPPORTS_CAST(nsIFaviconService*, this));
-  nsCOMPtr<nsIEventTarget> target = do_GetInterface(mDBConn);
-  NS_ENSURE_TRUE(target, NS_ERROR_OUT_OF_MEMORY);
-  nsresult rv = target->Dispatch(event, NS_DISPATCH_NORMAL);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-
 nsresult
 nsFaviconService::GetFaviconDataAsync(nsIURI* aFaviconURI,
                                       mozIStorageStatementCallback *aCallback)
 {
   NS_ASSERTION(aCallback, "Doesn't make sense to call this without a callback");
-  DECLARE_AND_ASSIGN_LAZY_STMT(stmt, mDBGetData);
+  nsCOMPtr<mozIStorageAsyncStatement> stmt = mDB->GetAsyncStatement(
+    "SELECT f.data, f.mime_type FROM moz_favicons f WHERE url = :icon_url"
+  );
+  NS_ENSURE_STATE(stmt);
+
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("icon_url"), aFaviconURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<mozIStoragePendingStatement> pendingStatement;
   return stmt->ExecuteAsync(aCallback, getter_AddRefs(pendingStatement));
 }
 
 ////////////////////////////////////////////////////////////////////////////////
--- a/toolkit/components/places/nsFaviconService.h
+++ b/toolkit/components/places/nsFaviconService.h
@@ -41,21 +41,19 @@
 
 #include "nsIFaviconService.h"
 #include "mozIAsyncFavicons.h"
 
 #include "nsCOMPtr.h"
 #include "nsString.h"
 #include "nsDataHashtable.h"
 #include "nsServiceManagerUtils.h"
-
 #include "nsToolkitCompsCID.h"
-
+#include "Database.h"
 #include "mozilla/storage.h"
-#include "mozilla/storage/StatementCache.h"
 
 // Favicons bigger than this size should not be saved to the db to avoid
 // bloating it with large image blobs.
 // This still allows us to accept a favicon even if we cannot optimize it.
 #define MAX_FAVICON_SIZE 10240
 
 // Most icons will be smaller than this rough estimate of the size of an
 // uncompressed 16x16 RGBA image of the same dimensions.
@@ -77,19 +75,16 @@ public:
    */
   static nsFaviconService* GetSingleton();
 
   /**
    * Initializes the service's object.  This should only be called once.
    */
   nsresult Init();
 
-  // called by nsNavHistory::Init
-  static nsresult InitTables(mozIStorageConnection* aDBConn);
-
   static nsFaviconService* GetFaviconServiceIfAvailable() {
     return gFaviconService;
   }
 
   /**
    * Returns a cached pointer to the favicon service for consumers in the
    * places directory.
    */
@@ -139,61 +134,36 @@ public:
    * @param aPageURI
    *        The URI of the page aFaviconURI is for.
    * @param aFaviconURI
    *        The URI for the favicon we want to test for on aPageURI.
    */
   void checkAndNotify(nsIURI* aPageURI, nsIURI* aFaviconURI);
 
   /**
-   * Finalize all internal statements.
-   */
-  nsresult FinalizeStatements();
-
-  /**
    * Call to send out favicon changed notifications. Should only be called
    * when there is data loaded for the favicon.
    * @param aPageURI
    *        The URI of the page to notify about.
    * @param aFaviconURI
    *        The moz-anno:favicon URI of the icon.
    * @param aGUID
    *        The unique ID associated with the page.
    */
   void SendFaviconNotifications(nsIURI* aPageURI, nsIURI* aFaviconURI,
                                 const nsACString& aGUID);
 
-  /**
-   * This cache should be used only for background thread statements.
-   *
-   * @pre must be running on the background thread of mDBConn.
-   */
-  mozilla::storage::StatementCache<mozIStorageStatement> mSyncStatements;
-
   NS_DECL_ISUPPORTS
   NS_DECL_NSIFAVICONSERVICE
   NS_DECL_MOZIASYNCFAVICONS
 
 private:
   ~nsFaviconService();
 
-  nsCOMPtr<mozIStorageConnection> mDBConn; // from history service
-
-  /**
-   * Always use this getter and never use directly the statement nsCOMPtr.
-   */
-  mozIStorageStatement* GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt);
-  nsCOMPtr<mozIStorageStatement> mDBGetURL; // returns URL, data len given page
-  nsCOMPtr<mozIStorageStatement> mDBGetData; // returns actual data given URL
-  nsCOMPtr<mozIStorageStatement> mDBGetIconInfo;
-  nsCOMPtr<mozIStorageStatement> mDBInsertIcon;
-  nsCOMPtr<mozIStorageStatement> mDBUpdateIcon;
-  nsCOMPtr<mozIStorageStatement> mDBSetPageFavicon;
-  nsCOMPtr<mozIStorageStatement> mDBRemoveOnDiskReferences;
-  nsCOMPtr<mozIStorageStatement> mDBRemoveAllFavicons;
+  nsRefPtr<mozilla::places::Database> mDB;
 
   static nsFaviconService* gFaviconService;
 
   /**
    * A cached URI for the default icon. We return this a lot, and don't want to
    * re-parse and normalize our unchanging string many times.  Important: do
    * not return this directly; use Clone() since callers may change the object
    * they get back. May be null, in which case it needs initialization.
@@ -213,18 +183,16 @@ private:
   PRUint32 mFailedFaviconSerial;
   nsDataHashtable<nsCStringHashKey, PRUint32> mFailedFavicons;
 
   nsresult SetFaviconUrlForPageInternal(nsIURI* aURI, nsIURI* aFavicon,
                                         bool* aHasData);
 
   friend class FaviconLoadListener;
 
-  bool mShuttingDown;
-
   // Caches the content of the default favicon if it's not already cached and
   // copies it into byteStr.
   nsresult GetDefaultFaviconData(nsCString& byteStr);
 
   // A string of bytes caching the default favicon's content.  Empty if not yet
   // cached.  Rather than accessing this directly, use GetDefaultFaviconData.
   nsCString mDefaultFaviconData;
 };
--- a/toolkit/components/places/nsNavBookmarks.cpp
+++ b/toolkit/components/places/nsNavBookmarks.cpp
@@ -34,36 +34,32 @@
  * use your version of this file under the terms of the MPL, indicate your
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * 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 ***** */
 
-#include "nsAppDirectoryServiceDefs.h"
 #include "nsNavBookmarks.h"
+
 #include "nsNavHistory.h"
-#include "mozStorageHelper.h"
-#include "nsIServiceManager.h"
+#include "nsAnnotationService.h"
+#include "nsILivemarkService.h"
+#include "nsPlacesMacros.h"
+#include "Helpers.h"
+
+#include "nsAppDirectoryServiceDefs.h"
 #include "nsNetUtil.h"
 #include "nsIDynamicContainer.h"
 #include "nsUnicharUtils.h"
-#include "nsFaviconService.h"
-#include "nsAnnotationService.h"
 #include "nsPrintfCString.h"
 #include "nsIUUIDGenerator.h"
 #include "prprf.h"
-#include "nsILivemarkService.h"
-#include "nsPlacesTriggers.h"
-#include "nsPlacesTables.h"
-#include "nsPlacesIndexes.h"
-#include "nsPlacesMacros.h"
-#include "Helpers.h"
-
+#include "mozilla/storage.h"
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/Util.h"
 
 #define BOOKMARKS_TO_KEYWORDS_INITIAL_CACHE_SIZE 64
 #define RECENT_BOOKMARKS_INITIAL_CACHE_SIZE 10
 // Threashold to expire old bookmarks if the initial cache size is exceeded.
 #define RECENT_BOOKMARKS_THRESHOLD PRTime((PRInt64)1 * 60 * PR_USEC_PER_SEC)
 
@@ -72,44 +68,23 @@
 
 #define END_CRITICAL_BOOKMARK_CACHE_SECTION(_itemId_) \
   MOZ_ASSERT(!mRecentBookmarksCache.GetEntry(_itemId_))
 
 #define TOPIC_PLACES_MAINTENANCE "places-maintenance-finished"
 
 using namespace mozilla;
 
-const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_Id = 0;
-const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_Guid = 1;
-const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_ParentId = 2;
-const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_LastModified = 3;
-const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_ParentGuid = 4;
-const PRInt32 nsNavBookmarks::kFindURIBookmarksIndex_GrandParentId = 5;
-
 // These columns sit to the right of the kGetInfoIndex_* columns.
 const PRInt32 nsNavBookmarks::kGetChildrenIndex_Position = 14;
 const PRInt32 nsNavBookmarks::kGetChildrenIndex_Type = 15;
 const PRInt32 nsNavBookmarks::kGetChildrenIndex_PlaceID = 16;
 const PRInt32 nsNavBookmarks::kGetChildrenIndex_ServiceContractId = 17;
 const PRInt32 nsNavBookmarks::kGetChildrenIndex_Guid = 18;
 
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_Id = 0;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_Url = 1;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_Title = 2;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_Position = 3;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_PlaceId = 4;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_ParentId = 5;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_Type = 6;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_ServiceContractId = 7;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_DateAdded = 8;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_LastModified = 9;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_Guid = 10;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_ParentGuid = 11;
-const PRInt32 nsNavBookmarks::kGetItemPropertiesIndex_GrandParentId = 12;
-
 using namespace mozilla::places;
 
 PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsNavBookmarks, gBookmarksService)
 
 #define BOOKMARKS_ANNO_PREFIX "bookmarks/"
 #define BOOKMARKS_TOOLBAR_FOLDER_ANNO NS_LITERAL_CSTRING(BOOKMARKS_ANNO_PREFIX "toolbarFolder")
 #define GUID_ANNO NS_LITERAL_CSTRING("placesInternal/GUID")
 #define READ_ONLY_ANNO NS_LITERAL_CSTRING("placesInternal/READ_ONLY")
@@ -146,23 +121,31 @@ public:
   : mBookmarksSvc(aBookmarksSvc)
   , mCallback(aCallback)
   , mData(aData)
   {
   }
 
   void Init()
   {
-    nsCOMPtr<mozIStorageStatement> stmt =
-      mBookmarksSvc->GetStatementById(DB_GET_BOOKMARKS_FOR_URI);
-    if (stmt) {
-      (void)URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"),
-                            mData.bookmark.url);
-      nsCOMPtr<mozIStoragePendingStatement> pendingStmt;
-      (void)stmt->ExecuteAsync(this, getter_AddRefs(pendingStmt));
+    nsRefPtr<Database> DB = Database::GetDatabase();
+    if (DB) {
+      nsCOMPtr<mozIStorageAsyncStatement> stmt = DB->GetAsyncStatement(
+        "SELECT b.id, b.guid, b.parent, b.lastModified, t.guid, t.parent "
+        "FROM moz_bookmarks b "
+        "JOIN moz_bookmarks t on t.id = b.parent "
+        "WHERE b.fk = (SELECT id FROM moz_places WHERE url = :page_url) "
+        "ORDER BY b.lastModified DESC, b.id DESC "
+      );
+      if (stmt) {
+        (void)URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"),
+                              mData.bookmark.url);
+        nsCOMPtr<mozIStoragePendingStatement> pendingStmt;
+        (void)stmt->ExecuteAsync(this, getter_AddRefs(pendingStmt));
+      }
     }
   }
 
   NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet)
   {
     nsCOMPtr<mozIStorageRow> row;
     while (NS_SUCCEEDED(aResultSet->GetNextRow(getter_AddRefs(row))) && row) {
       // Skip tags, for the use-cases of this async getter they are useless.
@@ -245,17 +228,16 @@ ExpireRecentBookmarksByParent(nsTHashtab
 nsNavBookmarks::nsNavBookmarks() : mItemCount(0)
                                  , mRoot(0)
                                  , mMenuRoot(0)
                                  , mTagsRoot(0)
                                  , mUnfiledRoot(0)
                                  , mToolbarRoot(0)
                                  , mCanNotify(false)
                                  , mCacheObservers("bookmark-observers")
-                                 , mShuttingDown(false)
                                  , mBatching(false)
 {
   NS_ASSERTION(!gBookmarksService,
                "Attempting to create two instances of the service!");
   gBookmarksService = this;
 }
 
 
@@ -263,389 +245,75 @@ nsNavBookmarks::~nsNavBookmarks()
 {
   NS_ASSERTION(gBookmarksService == this,
                "Deleting a non-singleton instance of the service");
   if (gBookmarksService == this)
     gBookmarksService = nsnull;
 }
 
 
-NS_IMPL_ISUPPORTS4(nsNavBookmarks,
-                   nsINavBookmarksService,
-                   nsINavHistoryObserver,
-                   nsIAnnotationObserver,
-                   nsIObserver)
+NS_IMPL_ISUPPORTS5(nsNavBookmarks
+, nsINavBookmarksService
+, nsINavHistoryObserver
+, nsIAnnotationObserver
+, nsIObserver
+, nsISupportsWeakReference
+)
 
 
 nsresult
 nsNavBookmarks::Init()
 {
   NS_TIME_FUNCTION;
 
-  nsNavHistory* history = nsNavHistory::GetHistoryService();
-  NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
-  mDBConn = history->GetStorageConnection();
-  NS_ENSURE_STATE(mDBConn);
+  mDB = Database::GetDatabase();
+  NS_ENSURE_STATE(mDB);
 
   mRecentBookmarksCache.Init(RECENT_BOOKMARKS_INITIAL_CACHE_SIZE);
   nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
   if (os) {
-    (void)os->AddObserver(this, TOPIC_PLACES_MAINTENANCE, false);
-    (void)os->AddObserver(this, TOPIC_PLACES_SHUTDOWN, false);
+    (void)os->AddObserver(this, TOPIC_PLACES_MAINTENANCE, true);
+    (void)os->AddObserver(this, TOPIC_PLACES_SHUTDOWN, true);
+    (void)os->AddObserver(this, TOPIC_PLACES_CONNECTION_CLOSED, true);
   }
 
-  // Get our read-only cloned connection.
-  nsresult rv = mDBConn->Clone(true, getter_AddRefs(mDBReadOnlyConn));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PRUint16 dbStatus;
-  rv = history->GetDatabaseStatus(&dbStatus);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = InitRoots(dbStatus != nsINavHistoryService::DATABASE_STATUS_OK);
+  PRUint16 dbStatus = mDB->GetDatabaseStatus();
+  nsresult rv = InitRoots(dbStatus != nsINavHistoryService::DATABASE_STATUS_OK);
   NS_ENSURE_SUCCESS(rv, rv);
 
   mCanNotify = true;
 
   // Observe annotations.
   nsAnnotationService* annosvc = nsAnnotationService::GetAnnotationService();
   NS_ENSURE_TRUE(annosvc, NS_ERROR_OUT_OF_MEMORY);
   annosvc->AddObserver(this);
 
   // Allows us to notify on title changes. MUST BE LAST so it is impossible
   // to fail after this call, or the history service will have a reference to
   // us and we won't go away.
-  history->AddObserver(this, false);
+  nsNavHistory* history = nsNavHistory::GetHistoryService();
+  NS_ENSURE_STATE(history);
+  history->AddObserver(this, true);
 
   // DO NOT PUT STUFF HERE that can fail. See observer comment above.
 
   return NS_OK;
 }
 
-
-/**
- * All commands that initialize the database schema should be here.
- * This is called from history init after database connection has been
- * established.
- */
-nsresult // static
-nsNavBookmarks::InitTables(mozIStorageConnection* aDBConn)
-{
-  bool exists;
-  nsresult rv = aDBConn->TableExists(NS_LITERAL_CSTRING("moz_bookmarks"), &exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (!exists) {
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_MOZ_BOOKMARKS);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // This index will make it faster to determine if a given item is
-    // bookmarked (used by history queries and vacuuming, for example).
-    // Making it compound with "type" speeds up type-differentiation
-    // queries, such as expiration and search.
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_PLACETYPE);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // The most common operation is to find the children given a parent and position.
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_PARENTPOSITION);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // fast access to lastModified is useful during sync and to get
-    // last modified bookmark title for tags container's children.
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_PLACELASTMODIFIED);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Selecting by guid needs to be fast.
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_GUID);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  rv = aDBConn->TableExists(NS_LITERAL_CSTRING("moz_bookmarks_roots"), &exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (!exists) {
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_MOZ_BOOKMARKS_ROOTS);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  rv = aDBConn->TableExists(NS_LITERAL_CSTRING("moz_keywords"), &exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (!exists) {
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_MOZ_KEYWORDS);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Create trigger to update as well
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_KEYWORD_VALIDITY_TRIGGER);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return NS_OK;
-}
-
-
-mozIStorageStatement*
-nsNavBookmarks::GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt)
-{
-  if (mShuttingDown)
-    return nsnull;
-
-  // Double ordering covers possible lastModified ties, that could happen when
-  // importing, syncing or due to extensions.
-  // Note: not using a JOIN is cheaper in this case.
-  RETURN_IF_STMT(mDBFindURIBookmarks, NS_LITERAL_CSTRING(
-    "SELECT b.id, b.guid, b.parent, b.lastModified, t.guid, t.parent "
-    "FROM moz_bookmarks b "
-    "JOIN moz_bookmarks t on t.id = b.parent "
-    "WHERE b.fk = (SELECT id FROM moz_places WHERE url = :page_url) "
-    "ORDER BY b.lastModified DESC, b.id DESC "));
-
-  // Select all children of a given folder, sorted by position.
-  // This is a LEFT JOIN because not all bookmarks types have a place.
-  // We 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.
-  RETURN_IF_STMT(mDBGetChildren, NS_LITERAL_CSTRING(
-    "SELECT h.id, h.url, IFNULL(b.title, h.title), h.rev_host, h.visit_count, "
-           "h.last_visit_date, f.url, null, b.id, b.dateAdded, b.lastModified, "
-           "b.parent, null, h.frecency, b.position, b.type, b.fk, "
-           "b.folder_type, b.guid "
-    "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 = :parent "
-    "ORDER BY b.position ASC"));
-
-  // Get information on a folder.
-  // This query has to always return results, so it can't be written as a join,
-  // apart doing a left join of 2 subqueries, but the cost would be the same.
-  RETURN_IF_STMT(mDBFolderInfo, NS_LITERAL_CSTRING(
-    "SELECT count(*), "
-            "(SELECT guid FROM moz_bookmarks WHERE id = :parent), "
-            "(SELECT parent FROM moz_bookmarks WHERE id = :parent) "
-    "FROM moz_bookmarks "
-    "WHERE parent = :parent"));
-
-  RETURN_IF_STMT(mDBGetChildAt, NS_LITERAL_CSTRING(
-    "SELECT id, fk, type FROM moz_bookmarks "
-    "WHERE parent = :parent AND position = :item_index"));
-
-  // Get bookmark/folder/separator properties.
-  // This is a LEFT JOIN because not all bookmarks types have a place.
-  RETURN_IF_STMT(mDBGetItemProperties, NS_LITERAL_CSTRING(
-    "SELECT b.id, h.url, b.title, b.position, b.fk, b.parent, b.type, "
-           "b.folder_type, b.dateAdded, b.lastModified, b.guid, "
-           "t.guid, t.parent "
-    "FROM moz_bookmarks b "
-    "LEFT JOIN moz_bookmarks t ON t.id = b.parent "
-    "LEFT JOIN moz_places h ON h.id = b.fk "
-    "WHERE b.id = :item_id"));
-
-  RETURN_IF_STMT(mDBGetItemIdForGUID, NS_LITERAL_CSTRING(
-    "SELECT item_id FROM moz_items_annos "
-    "WHERE content = :guid "
-    "LIMIT 1"));
-
-  RETURN_IF_STMT(mDBInsertBookmark, NS_LITERAL_CSTRING(
-    "INSERT INTO moz_bookmarks "
-      "(id, fk, type, parent, position, title, folder_type, "
-       "dateAdded, lastModified, guid) "
-    "VALUES (:item_id, :page_id, :item_type, :parent, :item_index, "
-            ":item_title, :folder_type, :date_added, :last_modified, "
-            "GENERATE_GUID())"));
-
-  // 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.
-  RETURN_IF_STMT(mDBIsBookmarkedInDatabase, NS_LITERAL_CSTRING(
-    "SELECT 1 FROM moz_bookmarks WHERE fk = :page_id"));
-
-  RETURN_IF_STMT(mDBIsURIBookmarkedInDatabase, NS_LITERAL_CSTRING(
-    "SELECT 1 FROM moz_bookmarks b "
-    "JOIN moz_places h ON b.fk = h.id "
-    "WHERE h.url = :page_url"));
-
-  // Checks to make sure a place id is a bookmark, and isn't a livemark.
-  RETURN_IF_STMT(mDBIsRealBookmark, NS_LITERAL_CSTRING(
-    "SELECT id "
-    "FROM moz_bookmarks "
-    "WHERE fk = :page_id "
-      "AND type = :item_type "
-      "AND parent NOT IN ("
-        "SELECT a.item_id "
-        "FROM moz_items_annos a "
-        "JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
-        "WHERE n.name = :anno_name"
-      ") "));
-
-  RETURN_IF_STMT(mDBGetLastBookmarkID, NS_LITERAL_CSTRING(
-    "SELECT id, guid "
-    "FROM moz_bookmarks "
-    "ORDER BY ROWID DESC "
-    "LIMIT 1"));
-
-  // lastModified is set to the same value as dateAdded.  We do this for
-  // performance reasons, since it will allow us to use an index to sort items
-  // by date.
-  RETURN_IF_STMT(mDBSetItemDateAdded, NS_LITERAL_CSTRING(
-    "UPDATE moz_bookmarks SET dateAdded = :date, lastModified = :date "
-    "WHERE id = :item_id"));
-
-  RETURN_IF_STMT(mDBSetItemLastModified, NS_LITERAL_CSTRING(
-    "UPDATE moz_bookmarks SET lastModified = :date WHERE id = :item_id"));
-
-  RETURN_IF_STMT(mDBSetItemIndex, NS_LITERAL_CSTRING(
-    "UPDATE moz_bookmarks SET position = :item_index WHERE id = :item_id"));
-
-  RETURN_IF_STMT(mDBGetKeywordForURI, NS_LITERAL_CSTRING(
-    "SELECT k.keyword "
-    "FROM moz_places h "
-    "JOIN moz_bookmarks b ON b.fk = h.id "
-    "JOIN moz_keywords k ON k.id = b.keyword_id "
-    "WHERE h.url = :page_url "));
-
-  RETURN_IF_STMT(mDBAdjustPosition, NS_LITERAL_CSTRING(
-    "UPDATE moz_bookmarks SET position = position + :delta "
-    "WHERE parent = :parent "
-      "AND position BETWEEN :from_index AND :to_index"));
-
-  RETURN_IF_STMT(mDBRemoveItem, NS_LITERAL_CSTRING(
-    "DELETE FROM moz_bookmarks WHERE id = :item_id"));
-
-  RETURN_IF_STMT(mDBGetLastChildId, NS_LITERAL_CSTRING(
-    "SELECT id FROM moz_bookmarks WHERE parent = :parent "
-    "ORDER BY position DESC LIMIT 1"));
-
-  RETURN_IF_STMT(mDBMoveItem, NS_LITERAL_CSTRING(
-    "UPDATE moz_bookmarks SET parent = :parent, position = :item_index "
-    "WHERE id = :item_id "));
-
-  RETURN_IF_STMT(mDBSetItemTitle, NS_LITERAL_CSTRING(
-    "UPDATE moz_bookmarks SET title = :item_title, lastModified = :date "
-    "WHERE id = :item_id "));
-
-  RETURN_IF_STMT(mDBChangeBookmarkURI, NS_LITERAL_CSTRING(
-    "UPDATE moz_bookmarks SET fk = :page_id, lastModified = :date "
-    "WHERE id = :item_id "));
-
-  // The next query finds the bookmarked ancestors in a redirects chain.
-  // It won't go further than 3 levels of redirects (a->b->c->your_place_id).
-  // To make this path 100% correct (up to any level) we would need either:
-  //  - A separate hash, build through recursive querying of the database.
-  //    This solution was previously implemented, but it had a negative effect
-  //    on startup since at each startup we have to recursively query the
-  //    database to rebuild a hash that is always the same across sessions.
-  //    It must be updated at each visit and bookmarks change too.  The code to
-  //    manage it is complex and prone to errors, sometimes causing incorrect
-  //    data fetches (for example wrong favicon for a redirected bookmark).
-  //  - A better way to track redirects for a visit.
-  //    We would need a separate table to track redirects, in the table we would
-  //    have visit_id, redirect_session.  To get all sources for
-  //    a visit then we could just join this table and get all visit_id that
-  //    are in the same redirect_session as our visit.  This has the drawback
-  //    that we can't ensure data integrity in the downgrade -> upgrade path,
-  //    since an old version would not update the table on new visits.
-  //
-  // For most cases these levels of redirects should be fine though, it's hard
-  // to hit a page that is 4 or 5 levels of redirects below a bookmarked page.
-  //
-  // As a bonus the query also checks first if place_id is already a bookmark,
-  // so you don't have to check that apart.
-
-#define COALESCE_PLACEID \
-  "COALESCE(greatgrandparent.place_id, grandparent.place_id, parent.place_id) "
-
-  nsCString redirectsFragment =
-    nsPrintfCString(3, "%d,%d",
-                    nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
-                    nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY);
-
-  RETURN_IF_STMT(mDBFindRedirectedBookmark, NS_LITERAL_CSTRING(
-    "SELECT "
-      "(SELECT url FROM moz_places WHERE id = :page_id) "
-    "FROM moz_bookmarks b "
-    "WHERE b.fk = :page_id "
-    "UNION ALL " // Not directly bookmarked.
-    "SELECT "
-      "(SELECT url FROM moz_places WHERE id = " COALESCE_PLACEID ") "
-    "FROM moz_historyvisits self "
-    "JOIN moz_bookmarks b ON b.fk = " COALESCE_PLACEID
-    "LEFT JOIN moz_historyvisits parent ON parent.id = self.from_visit "
-    "LEFT JOIN moz_historyvisits grandparent ON parent.from_visit = grandparent.id "
-      "AND parent.visit_type IN (") + redirectsFragment + NS_LITERAL_CSTRING(") "
-    "LEFT JOIN moz_historyvisits greatgrandparent ON grandparent.from_visit = greatgrandparent.id "
-      "AND grandparent.visit_type IN (") + redirectsFragment + NS_LITERAL_CSTRING(") "
-    "WHERE self.visit_type IN (") + redirectsFragment + NS_LITERAL_CSTRING(") "
-      "AND self.place_id = :page_id "
-    "LIMIT 1 " // Stop at the first result.
-  ));
-#undef COALESCE_PLACEID
-
-  return nsnull;
-}
-
-
-nsresult
-nsNavBookmarks::FinalizeStatements() {
-  mShuttingDown = true;
-
-  mozIStorageStatement* stmts[] = {
-    mDBGetChildren,
-    mDBFindURIBookmarks,
-    mDBFolderInfo,
-    mDBGetChildAt,
-    mDBGetItemProperties,
-    mDBGetItemIdForGUID,
-    mDBInsertBookmark,
-    mDBIsBookmarkedInDatabase,
-    mDBIsRealBookmark,
-    mDBGetLastBookmarkID,
-    mDBSetItemDateAdded,
-    mDBSetItemLastModified,
-    mDBSetItemIndex,
-    mDBGetKeywordForURI,
-    mDBAdjustPosition,
-    mDBRemoveItem,
-    mDBGetLastChildId,
-    mDBMoveItem,
-    mDBSetItemTitle,
-    mDBChangeBookmarkURI,
-    mDBIsURIBookmarkedInDatabase,
-    mDBFindRedirectedBookmark,
-  };
-
-  for (PRUint32 i = 0; i < ArrayLength(stmts); i++) {
-    nsresult rv = nsNavHistory::FinalizeStatement(stmts[i]);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // Since we are shutting down, close the read-only connection.
-  (void)mDBReadOnlyConn->AsyncClose(nsnull);
-
-#ifdef DEBUG
-  // Sanity check that all bookmarks have guids.
-  nsCOMPtr<mozIStorageStatement> stmt;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT * "
-    "FROM moz_bookmarks "
-    "WHERE guid IS NULL "
-  ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  bool haveNullGuids;
-  rv = stmt->ExecuteStep(&haveNullGuids);
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ASSERTION(!haveNullGuids,
-               "Someone added a bookmark without adding a GUID!");
-#endif
-
-  return NS_OK;
-}
-
-
 nsresult
 nsNavBookmarks::InitRoots(bool aForceCreate)
 {
+  // Get a read-only cloned connection to increase concurrency.
+  // It will be closed on destruction.
+  nsCOMPtr<mozIStorageConnection> DBConn;
+  mDB->MainConn()->Clone(true, getter_AddRefs(DBConn));
+  NS_ENSURE_STATE(DBConn);
+
   nsCOMPtr<mozIStorageStatement> stmt;
-  nsresult rv = mDBReadOnlyConn->CreateStatement(NS_LITERAL_CSTRING(
+  nsresult rv = DBConn->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT root_name, folder_id FROM moz_bookmarks_roots"
   ), getter_AddRefs(stmt));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
     nsCAutoString rootName;
     rv = stmt->GetUTF8String(0, rootName);
@@ -673,17 +341,17 @@ nsNavBookmarks::InitRoots(bool aForceCre
   }
 
   if (aForceCreate) {
     nsNavHistory* history = nsNavHistory::GetHistoryService();
     NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
     nsIStringBundle* bundle = history->GetBundle();
     NS_ENSURE_TRUE(bundle, NS_ERROR_OUT_OF_MEMORY);
 
-    mozStorageTransaction transaction(mDBConn, false);
+    mozStorageTransaction transaction(mDB->MainConn(), false);
 
     rv = CreateRoot(NS_LITERAL_CSTRING("places"), &mRoot, 0,
                     nsnull, nsnull);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = CreateRoot(NS_LITERAL_CSTRING("menu"), &mMenuRoot, mRoot, bundle,
                     NS_LITERAL_STRING("BookmarksMenuFolderTitle").get());
     NS_ENSURE_SUCCESS(rv, rv);
@@ -699,17 +367,17 @@ nsNavBookmarks::InitRoots(bool aForceCre
     rv = CreateRoot(NS_LITERAL_CSTRING("unfiled"), &mUnfiledRoot, mRoot, bundle,
                     NS_LITERAL_STRING("UnsortedBookmarksFolderTitle").get());
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = transaction.Commit();
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (!mBatching) {
-      ForceWALCheckpoint(mDBConn);
+      ForceWALCheckpoint();
     }
   }
 
   return NS_OK;
 }
 
 
 nsresult
@@ -722,21 +390,23 @@ nsNavBookmarks::CreateRoot(const nsCStri
   nsresult rv;
 
   if (*_itemId == 0) {
     // The root does not exist.  Create a new untitled folder for it.
     rv = CreateFolder(aParentId, EmptyCString(), DEFAULT_INDEX, _itemId);
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Create a entry  in moz_bookmarks_roots to link the folder to the root.
-    nsCOMPtr<mozIStorageStatement> stmt;
-    rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
       "INSERT INTO moz_bookmarks_roots (root_name, folder_id) "
       "VALUES (:root_name, :item_id)"
-    ), getter_AddRefs(stmt));
+    );
+    NS_ENSURE_STATE(stmt);
+    mozStorageStatementScoper scoper(stmt);
+
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("root_name"), name);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), *_itemId);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
   }
@@ -753,46 +423,63 @@ nsNavBookmarks::CreateRoot(const nsCStri
 
   return NS_OK;
 }
 
 
 bool
 nsNavBookmarks::IsRealBookmark(PRInt64 aPlaceId)
 {
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT_RET(stmt, mDBIsRealBookmark, false);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT id "
+    "FROM moz_bookmarks "
+    "WHERE fk = :page_id "
+      "AND type = :item_type "
+      "AND parent NOT IN ("
+        "SELECT a.item_id "
+        "FROM moz_items_annos a "
+        "JOIN moz_anno_attributes n ON a.anno_attribute_id = n.id "
+        "WHERE n.name = :anno_name"
+      ") "
+  );
+  NS_ENSURE_TRUE(stmt, false);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), aPlaceId);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Binding failed");
+  NS_ENSURE_SUCCESS(rv, false);
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("item_type"), TYPE_BOOKMARK);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Binding failed");
+  NS_ENSURE_SUCCESS(rv, false);
   rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
                                   NS_LITERAL_CSTRING(LMANNO_FEEDURI));
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Binding failed");
+  NS_ENSURE_SUCCESS(rv, false);
 
   // If we get any rows, then there exists at least one bookmark corresponding
   // to aPlaceId that is not a livemark item.
-  bool isBookmark;
+  bool isBookmark = false;
   rv = stmt->ExecuteStep(&isBookmark);
-  NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "ExecuteStep failed");
-  if (NS_SUCCEEDED(rv))
-    return isBookmark;
-
-  return false;
+  NS_ENSURE_SUCCESS(rv, false);
+
+  return isBookmark;
 }
 
 
 // nsNavBookmarks::IsBookmarkedInDatabase
 //
 //    This checks to see if the specified place_id is actually bookmarked.
 
 nsresult
 nsNavBookmarks::IsBookmarkedInDatabase(PRInt64 aPlaceId,
                                        bool* aIsBookmarked)
 {
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBIsBookmarkedInDatabase);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT 1 FROM moz_bookmarks WHERE fk = :page_id"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), aPlaceId);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->ExecuteStep(aIsBookmarked);
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 
@@ -804,17 +491,24 @@ nsNavBookmarks::AdjustIndices(PRInt64 aF
 {
   NS_ASSERTION(aStartIndex >= 0 && aEndIndex <= PR_INT32_MAX &&
                aStartIndex <= aEndIndex, "Bad indices");
 
   // Expire all cached items for this parent, since all positions are going to
   // change.
   ExpireRecentBookmarksByParent(&mRecentBookmarksCache, aFolderId);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBAdjustPosition);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "UPDATE moz_bookmarks SET position = position + :delta "
+      "WHERE parent = :parent "
+        "AND position BETWEEN :from_index AND :to_index"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("delta"), aDelta);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aFolderId);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("from_index"), aStartIndex);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("to_index"), aEndIndex);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -878,17 +572,26 @@ nsNavBookmarks::InsertBookmarkInDB(PRInt
                                    PRInt64* _itemId,
                                    nsACString& _guid)
 {
   // Check for a valid itemId.
   MOZ_ASSERT(_itemId && (*_itemId == -1 || *_itemId > 0));
   // Check for a valid placeId.
   MOZ_ASSERT(aPlaceId && (aPlaceId == -1 || aPlaceId > 0));
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBInsertBookmark);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "INSERT INTO moz_bookmarks "
+      "(id, fk, type, parent, position, title, folder_type, "
+       "dateAdded, lastModified, guid) "
+    "VALUES (:item_id, :page_id, :item_type, :parent, :item_index, "
+            ":item_title, :folder_type, :date_added, :last_modified, "
+            "GENERATE_GUID())"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
 
   nsresult rv;
   if (*_itemId != -1)
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), *_itemId);
   else
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("item_id"));
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -933,33 +636,40 @@ nsNavBookmarks::InsertBookmarkInDB(PRInt
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (*_itemId == -1) {
     // Get the newly inserted item id and GUID.
-    DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(lastInsertIdStmt, mDBGetLastBookmarkID);
+    nsCOMPtr<mozIStorageStatement> lastInsertIdStmt = mDB->GetStatement(
+      "SELECT id, guid "
+      "FROM moz_bookmarks "
+      "ORDER BY ROWID DESC "
+      "LIMIT 1"
+    );
+    NS_ENSURE_STATE(lastInsertIdStmt);
+    mozStorageStatementScoper lastInsertIdScoper(lastInsertIdStmt);
+
     bool hasResult;
     rv = lastInsertIdStmt->ExecuteStep(&hasResult);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_TRUE(hasResult, NS_ERROR_UNEXPECTED);
     rv = lastInsertIdStmt->GetInt64(0, _itemId);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = lastInsertIdStmt->GetUTF8String(1, _guid);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   if (aParentId > 0) {
     // Update last modified date of the ancestors.
     // TODO (bug 408991): Doing this for all ancestors would be slow without a
     //                    nested tree, so for now update only the parent.
-    rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
-                             aParentId, aDateAdded);
+    rv = SetItemDateInternal(LAST_MODIFIED, aParentId, aDateAdded);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
@@ -968,17 +678,17 @@ nsNavBookmarks::InsertBookmark(PRInt64 a
                                PRInt32 aIndex,
                                const nsACString& aTitle,
                                PRInt64* aNewBookmarkId)
 {
   NS_ENSURE_ARG(aURI);
   NS_ENSURE_ARG_POINTER(aNewBookmarkId);
   NS_ENSURE_ARG_MIN(aIndex, nsINavBookmarksService::DEFAULT_INDEX);
 
-  mozStorageTransaction transaction(mDBConn, false);
+  mozStorageTransaction transaction(mDB->MainConn(), false);
 
   nsNavHistory* history = nsNavHistory::GetHistoryService();
   NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
   PRInt64 placeId;
   nsCAutoString placeGuid;
   nsresult rv = history->GetOrCreateIdForPage(aURI, &placeId, placeGuid);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1010,17 +720,17 @@ nsNavBookmarks::InsertBookmark(PRInt64 a
   // Recalculate frecency for this entry, since it changed.
   rv = history->UpdateFrecency(placeId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!mBatching) {
-    ForceWALCheckpoint(mDBConn);
+    ForceWALCheckpoint();
   }
 
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemAdded(*aNewBookmarkId, aFolder, index, TYPE_BOOKMARK,
                                aURI, aTitle, dateAdded, guid, folderGuid));
 
   // If the bookmark has been added to a tag container, notify all
@@ -1066,17 +776,17 @@ nsNavBookmarks::RemoveItem(PRInt64 aItem
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnBeforeItemRemoved(bookmark.id,
                                        bookmark.type,
                                        bookmark.parentId,
                                        bookmark.guid,
                                        bookmark.parentGuid));
 
-  mozStorageTransaction transaction(mDBConn, false);
+  mozStorageTransaction transaction(mDB->MainConn(), false);
 
   // First, remove item annotations
   nsAnnotationService* annosvc = nsAnnotationService::GetAnnotationService();
   NS_ENSURE_TRUE(annosvc, NS_ERROR_OUT_OF_MEMORY);
   rv = annosvc->RemoveItemAnnotations(bookmark.id);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (bookmark.type == TYPE_FOLDER) {
@@ -1091,41 +801,46 @@ nsNavBookmarks::RemoveItem(PRInt64 aItem
 
     // Remove all of the folder's children.
     rv = RemoveFolderChildren(bookmark.id);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBRemoveItem);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "DELETE FROM moz_bookmarks WHERE id = :item_id"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), bookmark.id);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Fix indices in the parent.
   if (bookmark.position != DEFAULT_INDEX) {
     rv = AdjustIndices(bookmark.parentId,
                        bookmark.position + 1, PR_INT32_MAX, -1);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bookmark.lastModified = PR_Now();
-  rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
-                           bookmark.parentId, bookmark.lastModified);
+  rv = SetItemDateInternal(LAST_MODIFIED, bookmark.parentId,
+                           bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   END_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
 
   if (!mBatching) {
-    ForceWALCheckpoint(mDBConn);
+    ForceWALCheckpoint();
   }
 
   nsCOMPtr<nsIURI> uri;
   if (bookmark.type == TYPE_BOOKMARK) {
     nsNavHistory* history = nsNavHistory::GetHistoryService();
     NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
     rv = history->UpdateFrecency(bookmark.placeId);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1263,17 +978,17 @@ nsNavBookmarks::CreateContainerWithID(PR
 
   // Get the correct index for insertion.  This also ensures the parent exists.
   PRInt32 index, folderCount;
   PRInt64 grandParentId;
   nsCAutoString folderGuid;
   nsresult rv = FetchFolderInfo(aParent, &folderCount, folderGuid, &grandParentId);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mozStorageTransaction transaction(mDBConn, false);
+  mozStorageTransaction transaction(mDB->MainConn(), false);
 
   if (*aIndex == nsINavBookmarksService::DEFAULT_INDEX ||
       *aIndex >= folderCount) {
     index = folderCount;
   } else {
     index = *aIndex;
     // Create space for the insertion.
     rv = AdjustIndices(aParent, index, PR_INT32_MAX, 1);
@@ -1289,17 +1004,17 @@ nsNavBookmarks::CreateContainerWithID(PR
                           aTitle, dateAdded, nsnull, aContractId, aNewFolder,
                           guid);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!mBatching) {
-    ForceWALCheckpoint(mDBConn);
+    ForceWALCheckpoint();
   }
 
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemAdded(*aNewFolder, aParent, index, containerType,
                                nsnull, aTitle, dateAdded, guid, folderGuid));
 
   *aIndex = index;
@@ -1318,17 +1033,17 @@ nsNavBookmarks::InsertSeparator(PRInt64 
 
   // Get the correct index for insertion.  This also ensures the parent exists.
   PRInt32 index, folderCount;
   PRInt64 grandParentId;
   nsCAutoString folderGuid;
   nsresult rv = FetchFolderInfo(aParent, &folderCount, folderGuid, &grandParentId);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  mozStorageTransaction transaction(mDBConn, false);
+  mozStorageTransaction transaction(mDB->MainConn(), false);
 
   if (aIndex == nsINavBookmarksService::DEFAULT_INDEX ||
       aIndex >= folderCount) {
     index = folderCount;
   }
   else {
     index = aIndex;
     // Create space for the insertion.
@@ -1359,17 +1074,23 @@ nsNavBookmarks::InsertSeparator(PRInt64 
 
 
 nsresult
 nsNavBookmarks::GetLastChildId(PRInt64 aFolderId, PRInt64* aItemId)
 {
   NS_ASSERTION(aFolderId > 0, "Invalid folder id");
   *aItemId = -1;
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetLastChildId);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT id FROM moz_bookmarks WHERE parent = :parent "
+    "ORDER BY position DESC LIMIT 1"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aFolderId);
   NS_ENSURE_SUCCESS(rv, rv);
   bool found;
   rv = stmt->ExecuteStep(&found);
   NS_ENSURE_SUCCESS(rv, rv);
   if (found) {
     rv = stmt->GetInt64(0, aItemId);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1392,17 +1113,23 @@ nsNavBookmarks::GetIdForItemAt(PRInt64 a
   nsresult rv;
   if (aIndex == nsINavBookmarksService::DEFAULT_INDEX) {
     // Get last item within aFolder.
     rv = GetLastChildId(aFolder, aItemId);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
     // Get the item in aFolder with position aIndex.
-    DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetChildAt);
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+      "SELECT id, fk, type FROM moz_bookmarks "
+      "WHERE parent = :parent AND position = :item_index"
+    );
+    NS_ENSURE_STATE(stmt);
+    mozStorageStatementScoper scoper(stmt);
+
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aFolder);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("item_index"), aIndex);
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool found;
     rv = stmt->ExecuteStep(&found);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -1440,17 +1167,35 @@ nsNavBookmarks::GetDescendantChildren(PR
                                       const nsACString& aFolderGuid,
                                       PRInt64 aGrandParentId,
                                       nsTArray<BookmarkData>& aFolderChildrenArray) {
   // New children will be added from this index on.
   PRUint32 startIndex = aFolderChildrenArray.Length();
   nsresult rv;
   {
     // Collect children informations.
-    DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetChildren);
+    // Select all children of a given folder, sorted by position.
+    // This is a LEFT JOIN because not all bookmarks types have a place.
+    // We construct a result where the first columns exactly match
+    // kGetInfoIndex_* order, and additionally contains columns for position,
+    // item_child, and folder_child from moz_bookmarks.
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+      "SELECT h.id, h.url, IFNULL(b.title, h.title), h.rev_host, h.visit_count, "
+             "h.last_visit_date, f.url, null, b.id, b.dateAdded, b.lastModified, "
+             "b.parent, null, h.frecency, b.position, b.type, b.fk, "
+             "b.folder_type, b.guid "
+      "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 = :parent "
+      "ORDER BY b.position ASC"
+    );
+    NS_ENSURE_STATE(stmt);
+    mozStorageStatementScoper scoper(stmt);
+
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aFolderId);
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool hasMore;
     while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) && hasMore) {
       BookmarkData child;
       rv = stmt->GetInt64(nsNavHistory::kGetInfoIndex_ItemId, &child.id);
       NS_ENSURE_SUCCESS(rv, rv);
@@ -1552,44 +1297,43 @@ nsNavBookmarks::RemoveFolderChildren(PRI
         }
       }
     }
 
     BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(child.id);
   }
 
   // Delete items from the database now.
-  mozStorageTransaction transaction(mDBConn, false);
-
-  nsCOMPtr<mozIStorageStatement> deleteStatement;
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+  mozStorageTransaction transaction(mDB->MainConn(), false);
+
+  nsCOMPtr<mozIStorageStatement> deleteStatement = mDB->GetStatement(
+    NS_LITERAL_CSTRING(
       "DELETE FROM moz_bookmarks "
-      "WHERE parent IN (:parent") +
-        foldersToRemove +
-      NS_LITERAL_CSTRING(")"),
-    getter_AddRefs(deleteStatement));
-  NS_ENSURE_SUCCESS(rv, rv);
+      "WHERE parent IN (:parent") + foldersToRemove + NS_LITERAL_CSTRING(")")
+  );
+  NS_ENSURE_STATE(deleteStatement);
+  mozStorageStatementScoper deleteStatementScoper(deleteStatement);
+
   rv = deleteStatement->BindInt64ByName(NS_LITERAL_CSTRING("parent"), folder.id);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = deleteStatement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Clean up orphan items annotations.
-  rv = mDBConn->ExecuteSimpleSQL(
+  rv = mDB->MainConn()->ExecuteSimpleSQL(
     NS_LITERAL_CSTRING(
       "DELETE FROM moz_items_annos "
       "WHERE id IN ("
         "SELECT a.id from moz_items_annos a "
         "LEFT JOIN moz_bookmarks b ON a.item_id = b.id "
         "WHERE b.id ISNULL)"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Set the lastModified date.
-  rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
-                           folder.id, PR_Now());
+  rv = SetItemDateInternal(LAST_MODIFIED, folder.id, PR_Now());
   NS_ENSURE_SUCCESS(rv, rv);
 
   for (PRUint32 i = 0; i < folderChildrenArray.Length(); i++) {
     BookmarkData& child = folderChildrenArray[i];
     if (child.type == TYPE_BOOKMARK) {
       nsNavHistory* history = nsNavHistory::GetHistoryService();
       NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
       rv = history->UpdateFrecency(child.placeId);
@@ -1600,17 +1344,17 @@ nsNavBookmarks::RemoveFolderChildren(PRI
     }
     END_CRITICAL_BOOKMARK_CACHE_SECTION(child.id);
   }
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!mBatching) {
-    ForceWALCheckpoint(mDBConn);
+    ForceWALCheckpoint();
   }
 
   // Call observers in reverse order to serve children before their parent.
   for (PRInt32 i = folderChildrenArray.Length() - 1; i >= 0; --i) {
     BookmarkData& child = folderChildrenArray[i];
     nsCOMPtr<nsIURI> uri;
     if (child.type == TYPE_BOOKMARK) {
       // A broken url should not interrupt the removal process.
@@ -1662,17 +1406,17 @@ nsNavBookmarks::MoveItem(PRInt64 aItemId
   NS_ENSURE_TRUE(aItemId != mRoot, NS_ERROR_INVALID_ARG);
   NS_ENSURE_ARG_MIN(aItemId, 1);
   NS_ENSURE_ARG_MIN(aNewParent, 1);
   // -1 is append, but no other negative number is allowed.
   NS_ENSURE_ARG_MIN(aIndex, -1);
   // Disallow making an item its own parent.
   NS_ENSURE_TRUE(aItemId != aNewParent, NS_ERROR_INVALID_ARG);
 
-  mozStorageTransaction transaction(mDBConn, false);
+  mozStorageTransaction transaction(mDB->MainConn(), false);
 
   BookmarkData bookmark;
   nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // if parent and index are the same, nothing to do
   if (bookmark.parentId == aNewParent && bookmark.position == aIndex)
     return NS_OK;
@@ -1750,33 +1494,37 @@ nsNavBookmarks::MoveItem(PRInt64 aItemId
     rv = AdjustIndices(aNewParent, newIndex, PR_INT32_MAX, 1);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
 
   {
     // Update parent and position.
-    DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBMoveItem);
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+      "UPDATE moz_bookmarks SET parent = :parent, position = :item_index "
+      "WHERE id = :item_id "
+    );
+    NS_ENSURE_STATE(stmt);
+    mozStorageStatementScoper scoper(stmt);
+
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aNewParent);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("item_index"), newIndex);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), bookmark.id);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   PRTime now = PR_Now();
-  rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
-                           bookmark.parentId, now);
+  rv = SetItemDateInternal(LAST_MODIFIED, bookmark.parentId, now);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
-                           aNewParent, now);
+  rv = SetItemDateInternal(LAST_MODIFIED, aNewParent, now);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   END_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
 
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
@@ -1809,72 +1557,80 @@ nsNavBookmarks::FetchItemInfo(PRInt64 aI
   // Check if the requested id is in the recent cache and avoid the database
   // lookup if so.  Invalidate the cache after getting data if requested.
   BookmarkKeyClass* key = mRecentBookmarksCache.GetEntry(aItemId);
   if (key) {
     _bookmark = key->bookmark;
     return NS_OK;
   }
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetItemProperties);
+  // LEFT JOIN since not all bookmarks have an associated place.
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT b.id, h.url, b.title, b.position, b.fk, b.parent, b.type, "
+           "b.folder_type, b.dateAdded, b.lastModified, b.guid, "
+           "t.guid, t.parent "
+    "FROM moz_bookmarks b "
+    "LEFT JOIN moz_bookmarks t ON t.id = b.parent "
+    "LEFT JOIN moz_places h ON h.id = b.fk "
+    "WHERE b.id = :item_id"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(hasResult, NS_ERROR_INVALID_ARG);
 
   _bookmark.id = aItemId;
-  rv = stmt->GetUTF8String(kGetItemPropertiesIndex_Url, _bookmark.url);
+  rv = stmt->GetUTF8String(1, _bookmark.url);
   NS_ENSURE_SUCCESS(rv, rv);
   bool isNull;
-  rv = stmt->GetIsNull(kGetItemPropertiesIndex_Title, &isNull);
+  rv = stmt->GetIsNull(2, &isNull);
   NS_ENSURE_SUCCESS(rv, rv);
   if (isNull) {
     _bookmark.title.SetIsVoid(true);
   }
   else {
-    rv = stmt->GetUTF8String(kGetItemPropertiesIndex_Title, _bookmark.title);
+    rv = stmt->GetUTF8String(2, _bookmark.title);
     NS_ENSURE_SUCCESS(rv, rv);
   }
-  rv = stmt->GetInt32(kGetItemPropertiesIndex_Position, &_bookmark.position);
+  rv = stmt->GetInt32(3, &_bookmark.position);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stmt->GetInt64(kGetItemPropertiesIndex_PlaceId, &_bookmark.placeId);
+  rv = stmt->GetInt64(4, &_bookmark.placeId);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stmt->GetInt64(kGetItemPropertiesIndex_ParentId, &_bookmark.parentId);
+  rv = stmt->GetInt64(5, &_bookmark.parentId);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stmt->GetInt32(kGetItemPropertiesIndex_Type, &_bookmark.type);
+  rv = stmt->GetInt32(6, &_bookmark.type);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->GetIsNull(7, &isNull);
   NS_ENSURE_SUCCESS(rv, rv);
   if (isNull) {
     _bookmark.serviceCID.SetIsVoid(true);
   }
   else {
-    rv = stmt->GetUTF8String(kGetItemPropertiesIndex_ServiceContractId,
-                             _bookmark.serviceCID);
+    rv = stmt->GetUTF8String(7, _bookmark.serviceCID);
     NS_ENSURE_SUCCESS(rv, rv);
   }
-  rv = stmt->GetInt64(kGetItemPropertiesIndex_DateAdded, &_bookmark.dateAdded);
+  rv = stmt->GetInt64(8, &_bookmark.dateAdded);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stmt->GetInt64(kGetItemPropertiesIndex_LastModified,
-                      &_bookmark.lastModified);
+  rv = stmt->GetInt64(9, &_bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = stmt->GetUTF8String(kGetItemPropertiesIndex_Guid, _bookmark.guid);
+  rv = stmt->GetUTF8String(10, _bookmark.guid);
   NS_ENSURE_SUCCESS(rv, rv);
   // Getting properties of the root would show no parent.
-  rv = stmt->GetIsNull(kGetItemPropertiesIndex_ParentGuid, &isNull);
+  rv = stmt->GetIsNull(11, &isNull);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!isNull) {
-    rv = stmt->GetUTF8String(kGetItemPropertiesIndex_ParentGuid,
-                             _bookmark.parentGuid);
+    rv = stmt->GetUTF8String(11, _bookmark.parentGuid);
     NS_ENSURE_SUCCESS(rv, rv);
-    rv = stmt->GetInt64(kGetItemPropertiesIndex_GrandParentId,
-                        &_bookmark.grandParentId);
+    rv = stmt->GetInt64(12, &_bookmark.grandParentId);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
     _bookmark.grandParentId = -1;
   }
 
   // Make space for the new entry.
   ExpireNonrecentBookmarks(&mRecentBookmarksCache);
@@ -1883,31 +1639,46 @@ nsNavBookmarks::FetchItemInfo(PRInt64 aI
   if (key) {
     key->bookmark = _bookmark;
   }
 
   return NS_OK;
 }
 
 nsresult
-nsNavBookmarks::SetItemDateInternal(mozIStorageStatement* aStatement,
+nsNavBookmarks::SetItemDateInternal(enum BookmarkDate aDateType,
                                     PRInt64 aItemId,
                                     PRTime aValue)
 {
   BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(aItemId);
 
-  NS_ENSURE_STATE(aStatement);
-  mozStorageStatementScoper scoper(aStatement);
-
-  nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date"), aValue);
+  nsCOMPtr<mozIStorageStatement> stmt;
+  if (aDateType == DATE_ADDED) {
+    // lastModified is set to the same value as dateAdded.  We do this for
+    // performance reasons, since it will allow us to use an index to sort items
+    // by date.
+    stmt = mDB->GetStatement(
+      "UPDATE moz_bookmarks SET dateAdded = :date, lastModified = :date "
+      "WHERE id = :item_id"
+    );
+  }
+  else {
+    stmt = mDB->GetStatement(
+      "UPDATE moz_bookmarks SET lastModified = :date WHERE id = :item_id"
+    );
+  }
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("date"), aValue);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
+  rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = aStatement->Execute();
+  rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   END_CRITICAL_BOOKMARK_CACHE_SECTION(aItemId);
 
   // note, we are not notifying the observers
   // that the item has changed.
 
   return NS_OK;
@@ -1919,18 +1690,17 @@ nsNavBookmarks::SetItemDateAdded(PRInt64
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   BookmarkData bookmark;
   nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
   bookmark.dateAdded = aDateAdded;
 
-  rv = SetItemDateInternal(GetStatement(mDBSetItemDateAdded),
-                           bookmark.id, bookmark.dateAdded);
+  rv = SetItemDateInternal(DATE_ADDED, bookmark.id, bookmark.dateAdded);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Note: mDBSetItemDateAdded also sets lastModified to aDateAdded.
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemChanged(bookmark.id,
                                  NS_LITERAL_CSTRING("dateAdded"),
                                  false,
@@ -1964,18 +1734,17 @@ nsNavBookmarks::SetItemLastModified(PRIn
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   BookmarkData bookmark;
   nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
   bookmark.lastModified = aLastModified;
 
-  rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
-                           bookmark.id, bookmark.lastModified);
+  rv = SetItemDateInternal(LAST_MODIFIED, bookmark.id, bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Note: mDBSetItemDateAdded also sets lastModified to aDateAdded.
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemChanged(bookmark.id,
                                  NS_LITERAL_CSTRING("lastModified"),
                                  false,
@@ -2072,17 +1841,24 @@ nsNavBookmarks::SetItemGUID(PRInt64 aIte
 }
 
 
 NS_IMETHODIMP
 nsNavBookmarks::GetItemIdForGUID(const nsAString& aGUID, PRInt64* aItemId)
 {
   NS_ENSURE_ARG_POINTER(aItemId);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetItemIdForGUID);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT item_id FROM moz_items_annos "
+    "WHERE content = :guid "
+    "LIMIT 1"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = stmt->BindStringByName(NS_LITERAL_CSTRING("guid"), aGUID);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasMore = false;
   rv = stmt->ExecuteStep(&hasMore);
   if (NS_FAILED(rv) || ! hasMore) {
     *aItemId = -1;
     return NS_OK; // not found: return -1
@@ -2101,17 +1877,23 @@ nsNavBookmarks::SetItemTitle(PRInt64 aIt
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   BookmarkData bookmark;
   nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(statement, mDBSetItemTitle);
+  nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
+    "UPDATE moz_bookmarks SET title = :item_title, lastModified = :date "
+    "WHERE id = :item_id "
+  );
+  NS_ENSURE_STATE(statement);
+  mozStorageStatementScoper scoper(statement);
+
   // Support setting a null title, we support this in insertBookmark.
   if (aTitle.IsVoid()) {
     rv = statement->BindNullByName(NS_LITERAL_CSTRING("item_title"));
   }
   else {
     rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("item_title"),
                                          aTitle);
   }
@@ -2247,17 +2029,35 @@ nsresult
 nsNavBookmarks::QueryFolderChildren(
   PRInt64 aFolderId,
   nsNavHistoryQueryOptions* aOptions,
   nsCOMArray<nsNavHistoryResultNode>* aChildren)
 {
   NS_ENSURE_ARG_POINTER(aOptions);
   NS_ENSURE_ARG_POINTER(aChildren);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetChildren);
+  // Select all children of a given folder, sorted by position.
+  // This is a LEFT JOIN because not all bookmarks types have a place.
+  // We 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.
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT h.id, h.url, IFNULL(b.title, h.title), h.rev_host, h.visit_count, "
+           "h.last_visit_date, f.url, null, b.id, b.dateAdded, b.lastModified, "
+           "b.parent, null, h.frecency, b.position, b.type, b.fk, "
+           "b.folder_type, b.guid "
+    "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 = :parent "
+    "ORDER BY b.position ASC"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aFolderId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<mozIStorageValueArray> row = do_QueryInterface(stmt, &rv);
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRInt32 index = -1;
   bool hasResult;
@@ -2358,41 +2158,67 @@ nsresult
 nsNavBookmarks::QueryFolderChildrenAsync(
   nsNavHistoryFolderResultNode* aNode,
   PRInt64 aFolderId,
   mozIStoragePendingStatement** _pendingStmt)
 {
   NS_ENSURE_ARG_POINTER(aNode);
   NS_ENSURE_ARG_POINTER(_pendingStmt);
 
-  mozStorageStatementScoper scope(mDBGetChildren);
-
-  nsresult rv = mDBGetChildren->BindInt64ByName(NS_LITERAL_CSTRING("parent"),
-                                                aFolderId);
+  // Select all children of a given folder, sorted by position.
+  // This is a LEFT JOIN because not all bookmarks types have a place.
+  // We 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.
+  nsCOMPtr<mozIStorageAsyncStatement> stmt = mDB->GetAsyncStatement(
+    "SELECT h.id, h.url, IFNULL(b.title, h.title), h.rev_host, h.visit_count, "
+           "h.last_visit_date, f.url, null, b.id, b.dateAdded, b.lastModified, "
+           "b.parent, null, h.frecency, b.position, b.type, b.fk, "
+           "b.folder_type, b.guid "
+    "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 = :parent "
+    "ORDER BY b.position ASC"
+  );
+  NS_ENSURE_STATE(stmt);
+
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aFolderId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<mozIStoragePendingStatement> pendingStmt;
-  rv = mDBGetChildren->ExecuteAsync(aNode, getter_AddRefs(pendingStmt));
+  rv = stmt->ExecuteAsync(aNode, getter_AddRefs(pendingStmt));
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_IF_ADDREF(*_pendingStmt = pendingStmt);
   return NS_OK;
 }
 
 
 nsresult
 nsNavBookmarks::FetchFolderInfo(PRInt64 aFolderId,
                                 PRInt32* _folderCount,
                                 nsACString& _guid,
                                 PRInt64* _parentId)
 {
   *_folderCount = 0;
   *_parentId = -1;
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBFolderInfo);
+  // This query has to always return results, so it can't be written as a join,
+  // though a left join of 2 subqueries would have the same cost.
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT count(*), "
+            "(SELECT guid FROM moz_bookmarks WHERE id = :parent), "
+            "(SELECT parent FROM moz_bookmarks WHERE id = :parent) "
+    "FROM moz_bookmarks "
+    "WHERE parent = :parent"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("parent"), aFolderId);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(hasResult, NS_ERROR_UNEXPECTED);
 
@@ -2417,17 +2243,24 @@ nsNavBookmarks::FetchFolderInfo(PRInt64 
 
 
 NS_IMETHODIMP
 nsNavBookmarks::IsBookmarked(nsIURI* aURI, bool* aBookmarked)
 {
   NS_ENSURE_ARG(aURI);
   NS_ENSURE_ARG_POINTER(aBookmarked);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBIsURIBookmarkedInDatabase);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT 1 FROM moz_bookmarks b "
+    "JOIN moz_places h ON b.fk = h.id "
+    "WHERE h.url = :page_url"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->ExecuteStep(aBookmarked);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
@@ -2450,17 +2283,72 @@ nsNavBookmarks::GetBookmarkedURIFor(nsIU
     // This URI is unknown, just return null.
     return NS_OK;
   }
 
   // Check if a bookmark exists in the redirects chain for this URI.
   // The query will also check if the page is directly bookmarked, and return
   // the first found bookmark in case.  The check is directly on moz_bookmarks
   // without special filtering.
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBFindRedirectedBookmark);
+  // The next query finds the bookmarked ancestors in a redirects chain.
+  // It won't go further than 3 levels of redirects (a->b->c->your_place_id).
+  // To make this path 100% correct (up to any level) we would need either:
+  //  - A separate hash, build through recursive querying of the database.
+  //    This solution was previously implemented, but it had a negative effect
+  //    on startup since at each startup we have to recursively query the
+  //    database to rebuild a hash that is always the same across sessions.
+  //    It must be updated at each visit and bookmarks change too.  The code to
+  //    manage it is complex and prone to errors, sometimes causing incorrect
+  //    data fetches (for example wrong favicon for a redirected bookmark).
+  //  - A better way to track redirects for a visit.
+  //    We would need a separate table to track redirects, in the table we would
+  //    have visit_id, redirect_session.  To get all sources for
+  //    a visit then we could just join this table and get all visit_id that
+  //    are in the same redirect_session as our visit.  This has the drawback
+  //    that we can't ensure data integrity in the downgrade -> upgrade path,
+  //    since an old version would not update the table on new visits.
+  //
+  // For most cases these levels of redirects should be fine though, it's hard
+  // to hit a page that is 4 or 5 levels of redirects below a bookmarked page.
+  //
+  // As a bonus the query also checks first if place_id is already a bookmark,
+  // so you don't have to check that apart.
+
+#define COALESCE_PLACEID \
+  "COALESCE(greatgrandparent.place_id, grandparent.place_id, parent.place_id) "
+
+  nsCString redirectsFragment =
+    nsPrintfCString(3, "%d,%d",
+                    nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT,
+                    nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY);
+
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(NS_LITERAL_CSTRING(
+    "SELECT "
+      "(SELECT url FROM moz_places WHERE id = :page_id) "
+    "FROM moz_bookmarks b "
+    "WHERE b.fk = :page_id "
+    "UNION ALL " // Not directly bookmarked.
+    "SELECT "
+      "(SELECT url FROM moz_places WHERE id = " COALESCE_PLACEID ") "
+    "FROM moz_historyvisits self "
+    "JOIN moz_bookmarks b ON b.fk = " COALESCE_PLACEID
+    "LEFT JOIN moz_historyvisits parent ON parent.id = self.from_visit "
+    "LEFT JOIN moz_historyvisits grandparent ON parent.from_visit = grandparent.id "
+      "AND parent.visit_type IN (") + redirectsFragment + NS_LITERAL_CSTRING(") "
+    "LEFT JOIN moz_historyvisits greatgrandparent ON grandparent.from_visit = greatgrandparent.id "
+      "AND grandparent.visit_type IN (") + redirectsFragment + NS_LITERAL_CSTRING(") "
+    "WHERE self.visit_type IN (") + redirectsFragment + NS_LITERAL_CSTRING(") "
+      "AND self.place_id = :page_id "
+    "LIMIT 1 " // Stop at the first result.
+  ));
+#undef COALESCE_PLACEID
+
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), placeId);
   NS_ENSURE_SUCCESS(rv, rv);
   bool hasBookmarkedOrigin;
   if (NS_SUCCEEDED(stmt->ExecuteStep(&hasBookmarkedOrigin)) &&
       hasBookmarkedOrigin) {
     nsCAutoString spec;
     rv = stmt->GetUTF8String(0, spec);
     NS_ENSURE_SUCCESS(rv, rv);
@@ -2479,30 +2367,36 @@ nsNavBookmarks::ChangeBookmarkURI(PRInt6
   NS_ENSURE_ARG_MIN(aBookmarkId, 1);
   NS_ENSURE_ARG(aNewURI);
 
   BookmarkData bookmark;
   nsresult rv = FetchItemInfo(aBookmarkId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_ARG(bookmark.type == TYPE_BOOKMARK);
 
-  mozStorageTransaction transaction(mDBConn, false);
+  mozStorageTransaction transaction(mDB->MainConn(), false);
 
   nsNavHistory* history = nsNavHistory::GetHistoryService();
   NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
   PRInt64 newPlaceId;
   nsCAutoString newPlaceGuid;
   rv = history->GetOrCreateIdForPage(aNewURI, &newPlaceId, newPlaceGuid);
   NS_ENSURE_SUCCESS(rv, rv);
   if (!newPlaceId)
     return NS_ERROR_INVALID_ARG;
 
   BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(statement, mDBChangeBookmarkURI);
+  nsCOMPtr<mozIStorageStatement> statement = mDB->GetStatement(
+    "UPDATE moz_bookmarks SET fk = :page_id, lastModified = :date "
+    "WHERE id = :item_id "
+  );
+  NS_ENSURE_STATE(statement);
+  mozStorageStatementScoper scoper(statement);
+
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), newPlaceId);
   NS_ENSURE_SUCCESS(rv, rv);
   bookmark.lastModified = PR_Now();
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("date"),
                                   bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), bookmark.id);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -2561,77 +2455,97 @@ nsNavBookmarks::GetFolderIdForItem(PRInt
 
 nsresult
 nsNavBookmarks::GetBookmarkIdsForURITArray(nsIURI* aURI,
                                            nsTArray<PRInt64>& aResult,
                                            bool aSkipTags)
 {
   NS_ENSURE_ARG(aURI);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBFindURIBookmarks);
+  // Double ordering covers possible lastModified ties, that could happen when
+  // importing, syncing or due to extensions.
+  // Note: not using a JOIN is cheaper in this case.
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT b.id, b.guid, b.parent, b.lastModified, t.guid, t.parent "
+    "FROM moz_bookmarks b "
+    "JOIN moz_bookmarks t on t.id = b.parent "
+    "WHERE b.fk = (SELECT id FROM moz_places WHERE url = :page_url) "
+    "ORDER BY b.lastModified DESC, b.id DESC "
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool more;
   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&more))) && more) {
     if (aSkipTags) {
       // Skip tags, for the use-cases of this async getter they are useless.
       PRInt64 grandParentId;
-      nsresult rv = stmt->GetInt64(kFindURIBookmarksIndex_GrandParentId,
-                                   &grandParentId);
+      nsresult rv = stmt->GetInt64(5, &grandParentId);
       NS_ENSURE_SUCCESS(rv, rv);
       if (grandParentId == mTagsRoot) {
         continue;
       }
     }
     PRInt64 bookmarkId;
-    rv = stmt->GetInt64(kFindURIBookmarksIndex_Id, &bookmarkId);
+    rv = stmt->GetInt64(0, &bookmarkId);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ENSURE_TRUE(aResult.AppendElement(bookmarkId), NS_ERROR_OUT_OF_MEMORY);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
 nsNavBookmarks::GetBookmarksForURI(nsIURI* aURI,
                                    nsTArray<BookmarkData>& aBookmarks)
 {
   NS_ENSURE_ARG(aURI);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBFindURIBookmarks);
+  // Double ordering covers possible lastModified ties, that could happen when
+  // importing, syncing or due to extensions.
+  // Note: not using a JOIN is cheaper in this case.
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT b.id, b.guid, b.parent, b.lastModified, t.guid, t.parent "
+    "FROM moz_bookmarks b "
+    "JOIN moz_bookmarks t on t.id = b.parent "
+    "WHERE b.fk = (SELECT id FROM moz_places WHERE url = :page_url) "
+    "ORDER BY b.lastModified DESC, b.id DESC "
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool more;
   nsAutoString tags;
   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&more))) && more) {
     // Skip tags.
     PRInt64 grandParentId;
-    nsresult rv = stmt->GetInt64(kFindURIBookmarksIndex_GrandParentId,
-                                 &grandParentId);
+    nsresult rv = stmt->GetInt64(5, &grandParentId);
     NS_ENSURE_SUCCESS(rv, rv);
     if (grandParentId == mTagsRoot) {
       continue;
     }
 
     BookmarkData bookmark;
     bookmark.grandParentId = grandParentId;
-    rv = stmt->GetInt64(kFindURIBookmarksIndex_Id, &bookmark.id);
+    rv = stmt->GetInt64(0, &bookmark.id);
     NS_ENSURE_SUCCESS(rv, rv);
-    rv = stmt->GetUTF8String(kFindURIBookmarksIndex_Guid, bookmark.guid);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = stmt->GetInt64(kFindURIBookmarksIndex_ParentId, &bookmark.parentId);
+    rv = stmt->GetUTF8String(1, bookmark.guid);
     NS_ENSURE_SUCCESS(rv, rv);
-    rv = stmt->GetInt64(kFindURIBookmarksIndex_LastModified,
-                        &bookmark.lastModified);
+    rv = stmt->GetInt64(2, &bookmark.parentId);
     NS_ENSURE_SUCCESS(rv, rv);
-    rv = stmt->GetUTF8String(kFindURIBookmarksIndex_ParentGuid,
-                             bookmark.parentGuid);
+    rv = stmt->GetInt64(3, &bookmark.lastModified);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = stmt->GetUTF8String(4, bookmark.parentGuid);
     NS_ENSURE_SUCCESS(rv, rv);
 
     NS_ENSURE_TRUE(aBookmarks.AppendElement(bookmark), NS_ERROR_OUT_OF_MEMORY);
   }
 
   return NS_OK;
 }
 
@@ -2703,17 +2617,22 @@ nsNavBookmarks::SetItemIndex(PRInt64 aIt
   rv = FetchFolderInfo(bookmark.parentId, &folderCount, folderGuid, &grandParentId);
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(aNewIndex < folderCount, NS_ERROR_INVALID_ARG);
   // Check the parent's guid is the expected one.
   MOZ_ASSERT(bookmark.parentGuid == folderGuid);
 
   BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBSetItemIndex);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "UPDATE moz_bookmarks SET position = :item_index WHERE id = :item_id"
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), aItemId);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("item_index"), aNewIndex);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -2772,40 +2691,41 @@ nsNavBookmarks::SetKeywordForBookmark(PR
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Trying to set the same value or to remove a nonexistent keyword is a no-op.
   if (keyword.Equals(oldKeyword) || (keyword.IsEmpty() && oldKeyword.IsEmpty()))
     return NS_OK;
 
   BEGIN_CRITICAL_BOOKMARK_CACHE_SECTION(bookmark.id);
 
-  mozStorageTransaction transaction(mDBConn, false);
-
-  nsCOMPtr<mozIStorageStatement> updateBookmarkStmt;
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+  mozStorageTransaction transaction(mDB->MainConn(), false);
+
+  nsCOMPtr<mozIStorageStatement> updateBookmarkStmt = mDB->GetStatement(
     "UPDATE moz_bookmarks "
     "SET keyword_id = (SELECT id FROM moz_keywords WHERE keyword = :keyword), "
         "lastModified = :date "
     "WHERE id = :item_id "
-  ), getter_AddRefs(updateBookmarkStmt));
-  NS_ENSURE_SUCCESS(rv, rv);
+  );
+  NS_ENSURE_STATE(updateBookmarkStmt);
+  mozStorageStatementScoper updateBookmarkScoper(updateBookmarkStmt);
 
   if (keyword.IsEmpty()) {
     // Remove keyword association from the hash.
     mBookmarkToKeywordHash.Remove(bookmark.id);
     rv = updateBookmarkStmt->BindNullByName(NS_LITERAL_CSTRING("keyword"));
   }
    else {
     // We are associating bookmark to a new keyword. Create a new keyword
     // record if needed.
-    nsCOMPtr<mozIStorageStatement> newKeywordStmt;
-    rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+    nsCOMPtr<mozIStorageStatement> newKeywordStmt = mDB->GetStatement(
       "INSERT OR IGNORE INTO moz_keywords (keyword) VALUES (:keyword)"
-    ), getter_AddRefs(newKeywordStmt));
-    NS_ENSURE_SUCCESS(rv, rv);
+    );
+    NS_ENSURE_STATE(newKeywordStmt);
+    mozStorageStatementScoper newKeywordScoper(newKeywordStmt);
+
     rv = newKeywordStmt->BindStringByName(NS_LITERAL_CSTRING("keyword"),
                                           keyword);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = newKeywordStmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
 
     // Add new keyword association to the hash, removing the old one if needed.
     if (!oldKeyword.IsEmpty())
@@ -2846,17 +2766,26 @@ nsNavBookmarks::SetKeywordForBookmark(PR
 
 
 NS_IMETHODIMP
 nsNavBookmarks::GetKeywordForURI(nsIURI* aURI, nsAString& aKeyword)
 {
   NS_ENSURE_ARG(aURI);
   aKeyword.Truncate(0);
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetKeywordForURI);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT k.keyword "
+    "FROM moz_places h "
+    "JOIN moz_bookmarks b ON b.fk = h.id "
+    "JOIN moz_keywords k ON k.id = b.keyword_id "
+    "WHERE h.url = :page_url "
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasMore = false;
   rv = stmt->ExecuteStep(&hasMore);
   if (NS_FAILED(rv) || !hasMore) {
     aKeyword.SetIsVoid(true);
     return NS_OK; // not found: return void keyword string
@@ -2925,17 +2854,17 @@ nsNavBookmarks::GetURIForKeyword(const n
 nsresult
 nsNavBookmarks::EnsureKeywordsHash() {
   if (mBookmarkToKeywordHash.IsInitialized())
     return NS_OK;
 
   mBookmarkToKeywordHash.Init(BOOKMARKS_TO_KEYWORDS_INITIAL_CACHE_SIZE);
 
   nsCOMPtr<mozIStorageStatement> stmt;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+  nsresult rv = mDB->MainConn()->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT b.id, k.keyword "
     "FROM moz_bookmarks b "
     "JOIN moz_keywords k ON k.id = b.keyword_id "
   ), getter_AddRefs(stmt));
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasMore;
   while (NS_SUCCEEDED(stmt->ExecuteStep(&hasMore)) && hasMore) {
@@ -3033,22 +2962,27 @@ nsNavBookmarks::Observe(nsISupports *aSu
   NS_ASSERTION(NS_IsMainThread(), "This can only be called on the main thread");
 
   if (strcmp(aTopic, TOPIC_PLACES_MAINTENANCE) == 0) {
     // Maintenance can execute direct writes to the database, thus clear all
     // the cached bookmarks.
     mRecentBookmarksCache.Clear();
   }
   else if (strcmp(aTopic, TOPIC_PLACES_SHUTDOWN) == 0) {
-    nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
-    if (os) {
-      (void)os->RemoveObserver(this, TOPIC_PLACES_MAINTENANCE);
-      (void)os->RemoveObserver(this, TOPIC_PLACES_SHUTDOWN);
+    // Stop Observing annotations.
+    nsAnnotationService* annosvc = nsAnnotationService::GetAnnotationService();
+    if (annosvc) {
+      annosvc->RemoveObserver(this);
     }
   }
+  else if (strcmp(aTopic, TOPIC_PLACES_CONNECTION_CLOSED) == 0) {
+    // Don't even try to notify observers from this point on, the category
+    // cache would init services that could try to use our APIs.
+    mCanNotify = false;
+  }
 
   return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 //// nsINavHistoryObserver
 
 NS_IMETHODIMP
@@ -3060,17 +2994,17 @@ nsNavBookmarks::OnBeginUpdateBatch()
 }
 
 
 NS_IMETHODIMP
 nsNavBookmarks::OnEndUpdateBatch()
 {
   if (mBatching) {
     mBatching = false;
-    ForceWALCheckpoint(mDBConn);
+    ForceWALCheckpoint();
   }
 
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver, OnEndUpdateBatch());
   return NS_OK;
 }
 
 
@@ -3225,18 +3159,17 @@ nsNavBookmarks::OnPageAnnotationSet(nsIU
 NS_IMETHODIMP
 nsNavBookmarks::OnItemAnnotationSet(PRInt64 aItemId, const nsACString& aName)
 {
   BookmarkData bookmark;
   nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bookmark.lastModified = PR_Now();
-  rv = SetItemDateInternal(GetStatement(mDBSetItemLastModified),
-                           bookmark.id, bookmark.lastModified);
+  rv = SetItemDateInternal(LAST_MODIFIED, bookmark.id, bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemChanged(bookmark.id,
                                  aName,
                                  true,
                                  EmptyCString(),
--- a/toolkit/components/places/nsNavBookmarks.h
+++ b/toolkit/components/places/nsNavBookmarks.h
@@ -44,16 +44,20 @@
 
 #include "nsINavBookmarksService.h"
 #include "nsIAnnotationService.h"
 #include "nsITransaction.h"
 #include "nsNavHistory.h"
 #include "nsToolkitCompsCID.h"
 #include "nsCategoryCache.h"
 #include "nsTHashtable.h"
+#include "nsWeakReference.h"
+
+class nsNavBookmarks;
+class nsIOutputStream;
 
 namespace mozilla {
 namespace places {
 
   enum BookmarkStatementId {
     DB_FIND_REDIRECTED_BOOKMARK = 0
   , DB_GET_BOOKMARKS_FOR_URI
   };
@@ -104,25 +108,29 @@ namespace places {
     , creationTime(PR_Now())
     {
       NS_NOTREACHED("Do not call me!");
     }
     BookmarkData bookmark;
     PRTime creationTime;
   };
 
+  enum BookmarkDate {
+    DATE_ADDED = 0
+  , LAST_MODIFIED
+  };
+
 } // namespace places
 } // namespace mozilla
 
-class nsIOutputStream;
-
-class nsNavBookmarks : public nsINavBookmarksService,
-                       public nsINavHistoryObserver,
-                       public nsIAnnotationObserver,
-                       public nsIObserver
+class nsNavBookmarks : public nsINavBookmarksService
+                     , public nsINavHistoryObserver
+                     , public nsIAnnotationObserver
+                     , public nsIObserver
+                     , public nsSupportsWeakReference
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSINAVBOOKMARKSSERVICE
   NS_DECL_NSINAVHISTORYOBSERVER
   NS_DECL_NSIANNOTATIONOBSERVER
   NS_DECL_NSIOBSERVER
 
@@ -133,19 +141,16 @@ public:
    */
   static nsNavBookmarks* GetSingleton();
 
   /**
    * Initializes the service's object.  This should only be called once.
    */
   nsresult Init();
 
-  // called by nsNavHistory::Init
-  static nsresult InitTables(mozIStorageConnection* aDBConn);
-
   static nsNavBookmarks* GetBookmarksServiceIfAvailable() {
     return gBookmarksService;
   }
 
   static nsNavBookmarks* GetBookmarksService() {
     if (!gBookmarksService) {
       nsCOMPtr<nsINavBookmarksService> serv =
         do_GetService(NS_NAVBOOKMARKSSERVICE_CONTRACTID);
@@ -232,33 +237,16 @@ public:
    *        Id of the item to fetch information for.
    * @param aBookmark
    *        BookmarkData to store the information.
    */
   nsresult FetchItemInfo(PRInt64 aItemId,
                          BookmarkData& _bookmark);
 
   /**
-   * Finalize all internal statements.
-   */
-  nsresult FinalizeStatements();
-
-  mozIStorageStatement* GetStatementById(BookmarkStatementId aStatementId)
-  {
-    using namespace mozilla::places;
-    switch(aStatementId) {
-      case DB_FIND_REDIRECTED_BOOKMARK:
-        return GetStatement(mDBFindRedirectedBookmark);
-      case DB_GET_BOOKMARKS_FOR_URI:
-        return GetStatement(mDBFindURIBookmarks);
-    }
-    return nsnull;
-  }
-
-  /**
    * Notifies that a bookmark has been visited.
    *
    * @param aItemId
    *        The visited item id.
    * @param aData
    *        Details about the new visit.
    */
   void NotifyItemVisited(const ItemVisitData& aData);
@@ -335,41 +323,36 @@ private:
                            nsACString& _guid,
                            PRInt64* _parentId);
 
   nsresult GetFolderType(PRInt64 aFolder, nsACString& aType);
 
   nsresult GetLastChildId(PRInt64 aFolder, PRInt64* aItemId);
 
   /**
-   * This is the basic Places read-write connection, obtained from history.
+   * This is an handle to the Places database.
    */
-  nsCOMPtr<mozIStorageConnection> mDBConn;
-  /**
-   * Cloned read-only connection.  Can be used to read from the database
-   * without being locked out by writers.
-   */
-  nsCOMPtr<mozIStorageConnection> mDBReadOnlyConn;
+  nsRefPtr<mozilla::places::Database> mDB;
 
   nsString mGUIDBase;
   nsresult GetGUIDBase(nsAString& aGUIDBase);
 
   PRInt32 mItemCount;
 
   nsMaybeWeakPtrArray<nsINavBookmarkObserver> mObservers;
 
   PRInt64 mRoot;
   PRInt64 mMenuRoot;
   PRInt64 mTagsRoot;
   PRInt64 mUnfiledRoot;
   PRInt64 mToolbarRoot;
 
   nsresult IsBookmarkedInDatabase(PRInt64 aBookmarkID, bool* aIsBookmarked);
 
-  nsresult SetItemDateInternal(mozIStorageStatement* aStatement,
+  nsresult SetItemDateInternal(enum mozilla::places::BookmarkDate aDateType,
                                PRInt64 aItemId,
                                PRTime aValue);
 
   // Recursive method to build an array of folder's children
   nsresult GetDescendantChildren(PRInt64 aFolderId,
                                  const nsACString& aFolderGuid,
                                  PRInt64 aGrandParentId,
                                  nsTArray<BookmarkData>& aFolderChildrenArray);
@@ -438,85 +421,23 @@ private:
                                       nsTArray<PRInt64>& aResult,
                                       bool aSkipTags);
 
   nsresult GetBookmarksForURI(nsIURI* aURI,
                               nsTArray<BookmarkData>& _bookmarks);
 
   PRInt64 RecursiveFindRedirectedBookmark(PRInt64 aPlaceId);
 
-  /**
-   *  You should always use this getter and never use directly the nsCOMPtr.
-   */
-  mozIStorageStatement* GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt);
-
-  nsCOMPtr<mozIStorageStatement> mDBGetChildren;
-  // These columns sit to the right of the kGetInfoIndex_* columns.
   static const PRInt32 kGetChildrenIndex_Position;
   static const PRInt32 kGetChildrenIndex_Type;
   static const PRInt32 kGetChildrenIndex_PlaceID;
   static const PRInt32 kGetChildrenIndex_FolderTitle;
   static const PRInt32 kGetChildrenIndex_ServiceContractId;
   static const PRInt32 kGetChildrenIndex_Guid;
 
-  nsCOMPtr<mozIStorageStatement> mDBFindURIBookmarks;
-  static const PRInt32 kFindURIBookmarksIndex_Id;
-  static const PRInt32 kFindURIBookmarksIndex_Guid;
-  static const PRInt32 kFindURIBookmarksIndex_ParentId;
-  static const PRInt32 kFindURIBookmarksIndex_LastModified;
-  static const PRInt32 kFindURIBookmarksIndex_ParentGuid;
-  static const PRInt32 kFindURIBookmarksIndex_GrandParentId;
-
-  nsCOMPtr<mozIStorageStatement> mDBGetItemProperties;
-  static const PRInt32 kGetItemPropertiesIndex_Id;
-  static const PRInt32 kGetItemPropertiesIndex_Url;
-  static const PRInt32 kGetItemPropertiesIndex_Title;
-  static const PRInt32 kGetItemPropertiesIndex_Position;
-  static const PRInt32 kGetItemPropertiesIndex_PlaceId;
-  static const PRInt32 kGetItemPropertiesIndex_ParentId;
-  static const PRInt32 kGetItemPropertiesIndex_Type;
-  static const PRInt32 kGetItemPropertiesIndex_ServiceContractId;
-  static const PRInt32 kGetItemPropertiesIndex_DateAdded;
-  static const PRInt32 kGetItemPropertiesIndex_LastModified;
-  static const PRInt32 kGetItemPropertiesIndex_Guid;
-  static const PRInt32 kGetItemPropertiesIndex_ParentGuid;
-  static const PRInt32 kGetItemPropertiesIndex_GrandParentId;
-
-  nsCOMPtr<mozIStorageStatement> mDBInsertBookmark;
-  static const PRInt32 kInsertBookmarkIndex_Id;
-  static const PRInt32 kInsertBookmarkIndex_PlaceId;
-  static const PRInt32 kInsertBookmarkIndex_Type;
-  static const PRInt32 kInsertBookmarkIndex_Parent;
-  static const PRInt32 kInsertBookmarkIndex_Position;
-  static const PRInt32 kInsertBookmarkIndex_Title;
-  static const PRInt32 kInsertBookmarkIndex_ServiceContractId;
-  static const PRInt32 kInsertBookmarkIndex_DateAdded;
-  static const PRInt32 kInsertBookmarkIndex_LastModified;
-
-  nsCOMPtr<mozIStorageStatement> mDBFolderInfo;
-  nsCOMPtr<mozIStorageStatement> mDBGetItemIndex;
-  nsCOMPtr<mozIStorageStatement> mDBGetChildAt;
-  nsCOMPtr<mozIStorageStatement> mDBGetItemIdForGUID;
-  nsCOMPtr<mozIStorageStatement> mDBIsBookmarkedInDatabase;
-  nsCOMPtr<mozIStorageStatement> mDBIsURIBookmarkedInDatabase;
-  nsCOMPtr<mozIStorageStatement> mDBIsRealBookmark;
-  nsCOMPtr<mozIStorageStatement> mDBGetLastBookmarkID;
-  nsCOMPtr<mozIStorageStatement> mDBSetItemDateAdded;
-  nsCOMPtr<mozIStorageStatement> mDBSetItemLastModified;
-  nsCOMPtr<mozIStorageStatement> mDBSetItemIndex;
-  nsCOMPtr<mozIStorageStatement> mDBGetKeywordForURI;
-  nsCOMPtr<mozIStorageStatement> mDBGetBookmarksToKeywords;
-  nsCOMPtr<mozIStorageStatement> mDBAdjustPosition;
-  nsCOMPtr<mozIStorageStatement> mDBRemoveItem;
-  nsCOMPtr<mozIStorageStatement> mDBGetLastChildId;
-  nsCOMPtr<mozIStorageStatement> mDBMoveItem;
-  nsCOMPtr<mozIStorageStatement> mDBSetItemTitle;
-  nsCOMPtr<mozIStorageStatement> mDBChangeBookmarkURI;
-  nsCOMPtr<mozIStorageStatement> mDBFindRedirectedBookmark;
-
   class RemoveFolderTransaction : public nsITransaction {
   public:
     RemoveFolderTransaction(PRInt64 aID) : mID(aID) {}
 
     NS_DECL_ISUPPORTS
 
     NS_IMETHOD DoTransaction() {
       nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
@@ -567,18 +488,16 @@ private:
     nsString mType;
     PRInt32 mIndex;
   };
 
   // Used to enable and disable the observer notifications.
   bool mCanNotify;
   nsCategoryCache<nsINavBookmarkObserver> mCacheObservers;
 
-  bool mShuttingDown;
-
   // Tracks whether we are in batch mode.
   // Note: this is only tracking bookmarks batches, not history ones.
   bool mBatching;
 
   /**
    * Always call EnsureKeywordsHash() and check it for errors before actually
    * using the hash.  Internal keyword methods are already doing that.
    */
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -42,56 +42,47 @@
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * 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 ***** */
 
 #include <stdio.h>
 
-#include "mozilla/Util.h"
-
 #include "nsNavHistory.h"
 
+#include "mozIPlacesAutoComplete.h"
+#include "nsILivemarkService.h"
+#include "nsNavBookmarks.h"
+#include "nsAnnotationService.h"
+#include "nsFaviconService.h"
+#include "nsPlacesMacros.h"
+#include "History.h"
+#include "Helpers.h"
+
 #include "nsTArray.h"
 #include "nsCollationCID.h"
 #include "nsILocaleService.h"
-#include "nsIPrefBranch2.h"
-
 #include "nsNetUtil.h"
 #include "nsPrintfCString.h"
 #include "nsPromiseFlatString.h"
 #include "nsString.h"
 #include "nsUnicharUtils.h"
 #include "prsystem.h"
 #include "prtime.h"
 #include "nsEscape.h"
 #include "nsIEffectiveTLDService.h"
 #include "nsIClassInfoImpl.h"
 #include "nsThreadUtils.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsMathUtils.h"
-#include "mozIStorageAsyncStatement.h"
-#include "mozIPlacesAutoComplete.h"
-
-#include "nsNavBookmarks.h"
-#include "nsAnnotationService.h"
-#include "nsILivemarkService.h"
-#include "nsFaviconService.h"
-
-#include "nsPlacesTables.h"
-#include "nsPlacesIndexes.h"
-#include "nsPlacesTriggers.h"
-#include "nsPlacesMacros.h"
-#include "SQLFunctions.h"
-#include "Helpers.h"
-#include "History.h"
-
+#include "mozilla/storage.h"
 #include "mozilla/FunctionTimer.h"
 #include "mozilla/Util.h"
+#include "mozilla/Preferences.h"
 
 #ifdef MOZ_XUL
 #include "nsIAutoCompleteInput.h"
 #include "nsIAutoCompletePopup.h"
 #endif
 
 using namespace mozilla;
 using namespace mozilla::places;
@@ -99,98 +90,71 @@ using namespace mozilla::places;
 // The maximum number of things that we will store in the recent events list
 // before calling ExpireNonrecentEvents. This number should be big enough so it
 // is very difficult to get that many unconsumed events (for example, typed but
 // never visited) in the RECENT_EVENT_THRESHOLD. Otherwise, we'll start
 // checking each one for every page visit, which will be somewhat slower.
 #define RECENT_EVENT_QUEUE_MAX_LENGTH 128
 
 // preference ID strings
-#define PREF_PLACES_BRANCH_BASE                 "places."
-
-#define PREF_HISTORY_ENABLED                    "history.enabled"
-
-#define PREF_FRECENCY_NUM_VISITS                "frecency.numVisits"
-#define PREF_FRECENCY_FIRST_BUCKET_CUTOFF       "frecency.firstBucketCutoff"
-#define PREF_FRECENCY_SECOND_BUCKET_CUTOFF      "frecency.secondBucketCutoff"
-#define PREF_FRECENCY_THIRD_BUCKET_CUTOFF       "frecency.thirdBucketCutoff"
-#define PREF_FRECENCY_FOURTH_BUCKET_CUTOFF      "frecency.fourthBucketCutoff"
-#define PREF_FRECENCY_FIRST_BUCKET_WEIGHT       "frecency.firstBucketWeight"
-#define PREF_FRECENCY_SECOND_BUCKET_WEIGHT      "frecency.secondBucketWeight"
-#define PREF_FRECENCY_THIRD_BUCKET_WEIGHT       "frecency.thirdBucketWeight"
-#define PREF_FRECENCY_FOURTH_BUCKET_WEIGHT      "frecency.fourthBucketWeight"
-#define PREF_FRECENCY_DEFAULT_BUCKET_WEIGHT     "frecency.defaultBucketWeight"
-#define PREF_FRECENCY_EMBED_VISIT_BONUS         "frecency.embedVisitBonus"
-#define PREF_FRECENCY_FRAMED_LINK_VISIT_BONUS   "frecency.framedLinkVisitBonus"
-#define PREF_FRECENCY_LINK_VISIT_BONUS          "frecency.linkVisitBonus"
-#define PREF_FRECENCY_TYPED_VISIT_BONUS         "frecency.typedVisitBonus"
-#define PREF_FRECENCY_BOOKMARK_VISIT_BONUS      "frecency.bookmarkVisitBonus"
-#define PREF_FRECENCY_DOWNLOAD_VISIT_BONUS      "frecency.downloadVisitBonus"
-#define PREF_FRECENCY_PERM_REDIRECT_VISIT_BONUS "frecency.permRedirectVisitBonus"
-#define PREF_FRECENCY_TEMP_REDIRECT_VISIT_BONUS "frecency.tempRedirectVisitBonus"
-#define PREF_FRECENCY_DEFAULT_VISIT_BONUS       "frecency.defaultVisitBonus"
-#define PREF_FRECENCY_UNVISITED_BOOKMARK_BONUS  "frecency.unvisitedBookmarkBonus"
-#define PREF_FRECENCY_UNVISITED_TYPED_BONUS     "frecency.unvisitedTypedBonus"
-
-#define PREF_FORCE_DATABASE_REPLACEMENT         "database.replaceOnStartup"
-
-// To calculate the cache size we take into account the available physical
-// memory and the current database size.  This is the percentage of memory
-// we reserve for the former case.
-#define DATABASE_CACHE_TO_MEMORY_PERC 2
-// The minimum size of the cache.  We should never work without a cache, since
-// that would badly hurt WAL journaling mode.
-#define DATABASE_CACHE_MIN_BYTES (PRUint64)5242880 // 5MiB
-
-// We calculate an optimal database size, based on hardware specs.  This
-// pertains more to expiration, but the code is pretty much the same used for
-// cache_size, so it's here to reduce code duplication.
-// This percentage of disk size is used to protect against calculating a too
-// large size on disks with tiny quota or available space.
-#define DATABASE_TO_DISK_PERC 2
-// Maximum size of the optimal database.  High-end hardware has plenty of
-// memory and disk space, but performances don't grow linearly.
-#define DATABASE_MAX_SIZE (PRInt64)167772160 // 160MiB
-// Used to share the calculated optimal database size with other components.
-#define PREF_OPTIMAL_DATABASE_SIZE "history.expiration.transient_optimal_database_size"
-
-// If the physical memory size is not available, use MEMSIZE_FALLBACK_BYTES
-// instead.  Must stay in sync with the code in nsPlacesExpiration.js.
-#define MEMSIZE_FALLBACK_BYTES 268435456 // 256 M
-
-// Maximum size for the WAL file.  It should be small enough since in case of
-// crashes we could lose all the transactions in the file.  But a too small
-// file could hurt performance.
-#define DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES 512
-
-#define BYTES_PER_MEBIBYTE 1048576
-
-// This is the schema version, update it at any schema change and add a
-// corresponding migrateVxx method below.
-#define DATABASE_SCHEMA_VERSION 12
-
-// Filename of the database.
-#define DATABASE_FILENAME NS_LITERAL_STRING("places.sqlite")
-
-// Filename used to backup corrupt databases.
-#define DATABASE_CORRUPT_FILENAME NS_LITERAL_STRING("places.sqlite.corrupt")
+#define PREF_HISTORY_ENABLED                    "places.history.enabled"
+
+#define PREF_FREC_NUM_VISITS                    "places.frecency.numVisits"
+#define PREF_FREC_NUM_VISITS_DEF                10
+#define PREF_FREC_FIRST_BUCKET_CUTOFF           "places.frecency.firstBucketCutoff"
+#define PREF_FREC_FIRST_BUCKET_CUTOFF_DEF       4
+#define PREF_FREC_SECOND_BUCKET_CUTOFF          "places.frecency.secondBucketCutoff"
+#define PREF_FREC_SECOND_BUCKET_CUTOFF_DEF      14
+#define PREF_FREC_THIRD_BUCKET_CUTOFF           "places.frecency.thirdBucketCutoff"
+#define PREF_FREC_THIRD_BUCKET_CUTOFF_DEF       31
+#define PREF_FREC_FOURTH_BUCKET_CUTOFF          "places.frecency.fourthBucketCutoff"
+#define PREF_FREC_FOURTH_BUCKET_CUTOFF_DEF      90
+#define PREF_FREC_FIRST_BUCKET_WEIGHT           "places.frecency.firstBucketWeight"
+#define PREF_FREC_FIRST_BUCKET_WEIGHT_DEF       100
+#define PREF_FREC_SECOND_BUCKET_WEIGHT          "places.frecency.secondBucketWeight"
+#define PREF_FREC_SECOND_BUCKET_WEIGHT_DEF      70
+#define PREF_FREC_THIRD_BUCKET_WEIGHT           "places.frecency.thirdBucketWeight"
+#define PREF_FREC_THIRD_BUCKET_WEIGHT_DEF       50
+#define PREF_FREC_FOURTH_BUCKET_WEIGHT          "places.frecency.fourthBucketWeight"
+#define PREF_FREC_FOURTH_BUCKET_WEIGHT_DEF      30
+#define PREF_FREC_DEFAULT_BUCKET_WEIGHT         "places.frecency.defaultBucketWeight"
+#define PREF_FREC_DEFAULT_BUCKET_WEIGHT_DEF     10
+#define PREF_FREC_EMBED_VISIT_BONUS             "places.frecency.embedVisitBonus"
+#define PREF_FREC_EMBED_VISIT_BONUS_DEF         0
+#define PREF_FREC_FRAMED_LINK_VISIT_BONUS       "places.frecency.framedLinkVisitBonus"
+#define PREF_FREC_FRAMED_LINK_VISIT_BONUS_DEF   0
+#define PREF_FREC_LINK_VISIT_BONUS              "places.frecency.linkVisitBonus"
+#define PREF_FREC_LINK_VISIT_BONUS_DEF          100
+#define PREF_FREC_TYPED_VISIT_BONUS             "places.frecency.typedVisitBonus"
+#define PREF_FREC_TYPED_VISIT_BONUS_DEF         2000
+#define PREF_FREC_BOOKMARK_VISIT_BONUS          "places.frecency.bookmarkVisitBonus"
+#define PREF_FREC_BOOKMARK_VISIT_BONUS_DEF      75
+#define PREF_FREC_DOWNLOAD_VISIT_BONUS          "places.frecency.downloadVisitBonus"
+#define PREF_FREC_DOWNLOAD_VISIT_BONUS_DEF      0
+#define PREF_FREC_PERM_REDIRECT_VISIT_BONUS     "places.frecency.permRedirectVisitBonus"
+#define PREF_FREC_PERM_REDIRECT_VISIT_BONUS_DEF 0
+#define PREF_FREC_TEMP_REDIRECT_VISIT_BONUS     "places.frecency.tempRedirectVisitBonus"
+#define PREF_FREC_TEMP_REDIRECT_VISIT_BONUS_DEF 0
+#define PREF_FREC_DEFAULT_VISIT_BONUS           "places.frecency.defaultVisitBonus"
+#define PREF_FREC_DEFAULT_VISIT_BONUS_DEF       0
+#define PREF_FREC_UNVISITED_BOOKMARK_BONUS      "places.frecency.unvisitedBookmarkBonus"
+#define PREF_FREC_UNVISITED_BOOKMARK_BONUS_DEF  140
+#define PREF_FREC_UNVISITED_TYPED_BONUS         "places.frecency.unvisitedTypedBonus"
+#define PREF_FREC_UNVISITED_TYPED_BONUS_DEF     200
 
 // In order to avoid calling PR_now() too often we use a cached "now" value
 // for repeating stuff.  These are milliseconds between "now" cache refreshes.
 #define RENEW_CACHED_NOW_TIMEOUT ((PRInt32)3 * PR_MSEC_PER_SEC)
 
 // USECS_PER_DAY == PR_USEC_PER_SEC * 60 * 60 * 24;
 static const PRInt64 USECS_PER_DAY = LL_INIT(20, 500654080);
 
 // character-set annotation
 #define CHARSET_ANNO NS_LITERAL_CSTRING("URIProperties/characterSet")
 
-// Sync guid annotation
-#define SYNCGUID_ANNO NS_LITERAL_CSTRING("sync/guid")
-
 // Download destination file URI annotation
 #define DESTINATIONFILEURI_ANNO \
   NS_LITERAL_CSTRING("downloads/destinationFileURI")
 
 // Download destination file name annotation
 #define DESTINATIONFILENAME_ANNO \
   NS_LITERAL_CSTRING("downloads/destinationFileName")
 
@@ -215,16 +179,42 @@ static const PRInt64 USECS_PER_DAY = LL_
 #ifdef MOZ_XUL
 #define TOPIC_AUTOCOMPLETE_FEEDBACK_INCOMING "autocomplete-will-enter-text"
 #endif
 #define TOPIC_IDLE_DAILY "idle-daily"
 #define TOPIC_PREF_CHANGED "nsPref:changed"
 #define TOPIC_PROFILE_TEARDOWN "profile-change-teardown"
 #define TOPIC_PROFILE_CHANGE "profile-before-change"
 
+static const char* kObservedPrefs[] = {
+  PREF_HISTORY_ENABLED
+, PREF_FREC_NUM_VISITS
+, PREF_FREC_FIRST_BUCKET_CUTOFF
+, PREF_FREC_SECOND_BUCKET_CUTOFF
+, PREF_FREC_THIRD_BUCKET_CUTOFF
+, PREF_FREC_FOURTH_BUCKET_CUTOFF
+, PREF_FREC_FIRST_BUCKET_WEIGHT
+, PREF_FREC_SECOND_BUCKET_WEIGHT
+, PREF_FREC_THIRD_BUCKET_WEIGHT
+, PREF_FREC_FOURTH_BUCKET_WEIGHT
+, PREF_FREC_DEFAULT_BUCKET_WEIGHT
+, PREF_FREC_EMBED_VISIT_BONUS
+, PREF_FREC_FRAMED_LINK_VISIT_BONUS
+, PREF_FREC_LINK_VISIT_BONUS
+, PREF_FREC_TYPED_VISIT_BONUS
+, PREF_FREC_BOOKMARK_VISIT_BONUS
+, PREF_FREC_DOWNLOAD_VISIT_BONUS
+, PREF_FREC_PERM_REDIRECT_VISIT_BONUS
+, PREF_FREC_TEMP_REDIRECT_VISIT_BONUS
+, PREF_FREC_DEFAULT_VISIT_BONUS
+, PREF_FREC_UNVISITED_BOOKMARK_BONUS
+, PREF_FREC_UNVISITED_TYPED_BONUS
+, nsnull
+};
+
 NS_IMPL_THREADSAFE_ADDREF(nsNavHistory)
 NS_IMPL_THREADSAFE_RELEASE(nsNavHistory)
 
 NS_IMPL_CLASSINFO(nsNavHistory, NULL, nsIClassInfo::SINGLETON,
                   NS_NAVHISTORYSERVICE_CID)
 NS_INTERFACE_MAP_BEGIN(nsNavHistory)
   NS_INTERFACE_MAP_ENTRY(nsINavHistoryService)
   NS_INTERFACE_MAP_ENTRY(nsIGlobalHistory2)
@@ -252,122 +242,36 @@ NS_IMPL_CI_INTERFACE_GETTER4(
 namespace {
 
 static PRInt64 GetSimpleBookmarksQueryFolder(
     const nsCOMArray<nsNavHistoryQuery>& aQueries,
     nsNavHistoryQueryOptions* aOptions);
 static void ParseSearchTermsFromQueries(const nsCOMArray<nsNavHistoryQuery>& aQueries,
                                         nsTArray<nsTArray<nsString>*>* aTerms);
 
-} // anonymous namespace
-
-namespace mozilla {
-  namespace places {
-
-    bool hasRecentCorruptDB()
-    {
-      nsCOMPtr<nsIFile> profDir;
-      nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
-                                           getter_AddRefs(profDir));
-      NS_ENSURE_SUCCESS(rv, false);
-      nsCOMPtr<nsISimpleEnumerator> entries;
-      rv = profDir->GetDirectoryEntries(getter_AddRefs(entries));
-      NS_ENSURE_SUCCESS(rv, false);
-      bool hasMore;
-      while (NS_SUCCEEDED(entries->HasMoreElements(&hasMore)) && hasMore) {
-        nsCOMPtr<nsISupports> next;
-        rv = entries->GetNext(getter_AddRefs(next));
-        NS_ENSURE_SUCCESS(rv, false);
-        nsCOMPtr<nsIFile> currFile = do_QueryInterface(next, &rv);
-        NS_ENSURE_SUCCESS(rv, false);
-
-        nsAutoString leafName;
-        rv = currFile->GetLeafName(leafName);
-        NS_ENSURE_SUCCESS(rv, false);
-        if (leafName.Length() >= DATABASE_CORRUPT_FILENAME.Length() &&
-            leafName.Find(".corrupt", DATABASE_FILENAME.Length()) != -1) {
-          PRInt64 lastMod;
-          rv = currFile->GetLastModifiedTime(&lastMod);
-          NS_ENSURE_SUCCESS(rv, false);
-          if (PR_Now() - lastMod > (PRInt64)24 * 60 * 60 * 1000 * 1000)
-           return true;
-        }
-      }
-      return false;
-    }
-
-    void GetTagsSqlFragment(PRInt64 aTagsFolder,
-                            const nsACString& aRelation,
-                            bool aHasSearchTerms,
-                            nsACString& _sqlFragment) {
-      if (!aHasSearchTerms)
-        _sqlFragment.AssignLiteral("null");
-      else {
-        // This subquery DOES NOT order tags for performance reasons.
-        _sqlFragment.Assign(NS_LITERAL_CSTRING(
-             "(SELECT GROUP_CONCAT(t_t.title, ',') "
-               "FROM moz_bookmarks b_t "
-               "JOIN moz_bookmarks t_t ON t_t.id = b_t.parent  "
-               "WHERE b_t.fk = ") + aRelation + NS_LITERAL_CSTRING(" "
-               "AND t_t.parent = ") +
-               nsPrintfCString("%lld", aTagsFolder) + NS_LITERAL_CSTRING(" "
-             ")"));
-      }
-
-      _sqlFragment.AppendLiteral(" AS tags ");
-    }
-
-    /**
-     * Updates sqlite_stat1 table through ANALYZE.
-     * Since also nsPlacesExpiration.js executes ANALYZE, the analyzed tables
-     * must be the same in both components.  So ensure they are in sync.
-     */
-    nsresult updateSQLiteStatistics(mozIStorageConnection* aDBConn)
-    {
-      nsCOMPtr<mozIStorageAsyncStatement> analyzePlacesStmt;
-      nsresult rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
-        "ANALYZE moz_places"
-      ), getter_AddRefs(analyzePlacesStmt));
-      NS_ENSURE_SUCCESS(rv, rv);
-      nsCOMPtr<mozIStorageAsyncStatement> analyzeBookmarksStmt;
-      rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
-        "ANALYZE moz_bookmarks"
-      ), getter_AddRefs(analyzeBookmarksStmt));
-      NS_ENSURE_SUCCESS(rv, rv);
-      nsCOMPtr<mozIStorageAsyncStatement> analyzeVisitsStmt;
-      rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
-        "ANALYZE moz_historyvisits"
-      ), getter_AddRefs(analyzeVisitsStmt));
-      NS_ENSURE_SUCCESS(rv, rv);
-      nsCOMPtr<mozIStorageAsyncStatement> analyzeInputStmt;
-      rv = aDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
-        "ANALYZE moz_inputhistory"
-      ), getter_AddRefs(analyzeInputStmt));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      mozIStorageBaseStatement *stmts[] = {
-        analyzePlacesStmt,
-        analyzeBookmarksStmt,
-        analyzeVisitsStmt,
-        analyzeInputStmt
-      };
-
-      nsCOMPtr<mozIStoragePendingStatement> ps;
-      rv = aDBConn->ExecuteAsync(stmts, ArrayLength(stmts), nsnull,
-                                 getter_AddRefs(ps));
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      return NS_OK;
-    }
-
-  } // namespace places
-} // namespace mozilla
-
-
-namespace {
+void GetTagsSqlFragment(PRInt64 aTagsFolder,
+                        const nsACString& aRelation,
+                        bool aHasSearchTerms,
+                        nsACString& _sqlFragment) {
+  if (!aHasSearchTerms)
+    _sqlFragment.AssignLiteral("null");
+  else {
+    // This subquery DOES NOT order tags for performance reasons.
+    _sqlFragment.Assign(NS_LITERAL_CSTRING(
+         "(SELECT GROUP_CONCAT(t_t.title, ',') "
+           "FROM moz_bookmarks b_t "
+           "JOIN moz_bookmarks t_t ON t_t.id = b_t.parent  "
+           "WHERE b_t.fk = ") + aRelation + NS_LITERAL_CSTRING(" "
+           "AND t_t.parent = ") +
+           nsPrintfCString("%lld", aTagsFolder) + NS_LITERAL_CSTRING(" "
+         ")"));
+  }
+
+  _sqlFragment.AppendLiteral(" AS tags ");
+}
 
 /**
  * This class sets begin/end of batch updates to correspond to C++ scopes so
  * we can be sure end always gets called.
  */
 class UpdateBatchScoper
 {
 public:
@@ -434,28 +338,23 @@ const PRInt32 nsNavHistory::kGetInfoInde
 const PRInt32 nsNavHistory::kGetInfoIndex_Frecency = 13;
 
 PLACES_FACTORY_SINGLETON_IMPLEMENTATION(nsNavHistory, gHistoryService)
 
 
 nsNavHistory::nsNavHistory()
 : mBatchLevel(0)
 , mBatchDBTransaction(nsnull)
-, mAsyncThreadStatements(mDBConn)
-, mStatements(mDBConn)
-, mDBPageSize(0)
-, mCurrentJournalMode(JOURNAL_DELETE)
 , mCachedNow(0)
 , mExpireNowTimer(nsnull)
 , mLastSessionID(0)
 , mHistoryEnabled(true)
 , mNumVisitsForFrecency(10)
 , mTagsFolder(-1)
 , mInPrivateBrowsing(PRIVATEBROWSING_NOTINITED)
-, mDatabaseStatus(DATABASE_STATUS_OK)
 , mHasHistoryEntries(-1)
 , mCanNotify(true)
 , mCacheObservers("history-observers")
 {
   NS_ASSERTION(!gHistoryService,
                "Attempting to create two instances of the service!");
   gHistoryService = this;
 }
@@ -472,58 +371,20 @@ nsNavHistory::~nsNavHistory()
 }
 
 
 nsresult
 nsNavHistory::Init()
 {
   NS_TIME_FUNCTION;
 
-  nsCOMPtr<nsIPrefService> prefService =
-    do_GetService(NS_PREFSERVICE_CONTRACTID);
-  nsCOMPtr<nsIPrefBranch> placesBranch;
-  NS_ENSURE_TRUE(prefService, NS_ERROR_OUT_OF_MEMORY);
-  nsresult rv = prefService->GetBranch(PREF_PLACES_BRANCH_BASE,
-                                       getter_AddRefs(placesBranch));
-  NS_ENSURE_SUCCESS(rv, rv);
-  mPrefBranch = do_QueryInterface(placesBranch);
   LoadPrefs();
 
-  // Init the database file.  If we won't be able to connect to the database it
-  // is most likely corrupt, so we will backup it and create a new one.
-  rv = InitDBFile(false);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Init the database schema.  If this will fail there's an high possibility
-  // the schema is corrupt or incorrect, so we will force a new database
-  // initialization.
-  rv = InitDB();
-  if (NS_FAILED(rv)) {
-    // Forced InitDBFile will backup the old db and create a new one.
-    rv = InitDBFile(true);
-    NS_ENSURE_SUCCESS(rv, rv);
-    // Try to initialize the schema again on the new database.
-    rv = InitDB();
-  }
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Initialize all the items that are not part of the on-disk database, like
-  // views, temp tables, functions.  Do not initialize these in InitDBFile, or
-  // in case of failure we would mark the database as corrupt and try to
-  // replace it, even if it's sane.
-  rv = InitAdditionalDBItems();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Notify we have finished database initialization.
-  // Enqueue the notification, so if we init another service that requires
-  // nsNavHistoryService we don't recursive try to get it.
-  nsRefPtr<PlacesEvent> completeEvent =
-    new PlacesEvent(TOPIC_PLACES_INIT_COMPLETE);
-  rv = NS_DispatchToMainThread(completeEvent);
-  NS_ENSURE_SUCCESS(rv, rv);
+  mDB = Database::GetDatabase();
+  NS_ENSURE_STATE(mDB);
 
   // recent events hash tables
   NS_ENSURE_TRUE(mRecentTyped.Init(RECENT_EVENTS_INITIAL_CACHE_SIZE),
                  NS_ERROR_OUT_OF_MEMORY);
   NS_ENSURE_TRUE(mRecentLink.Init(RECENT_EVENTS_INITIAL_CACHE_SIZE),
                  NS_ERROR_OUT_OF_MEMORY);
   NS_ENSURE_TRUE(mRecentBookmark.Init(RECENT_EVENTS_INITIAL_CACHE_SIZE),
                  NS_ERROR_OUT_OF_MEMORY);
@@ -535,653 +396,43 @@ nsNavHistory::Init()
   /*****************************************************************************
    *** IMPORTANT NOTICE!
    ***
    *** Nothing after these add observer calls should return anything but NS_OK.
    *** If a failure code is returned, this nsNavHistory object will be held onto
    *** by the observer service and the preference service. 
    ****************************************************************************/
 
-  // Observe preferences branch for changes.
-  if (mPrefBranch)
-    mPrefBranch->AddObserver("", this, false);
-
-  nsCOMPtr<nsIObserverService> obsSvc =
-    do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
+  // Observe preferences changes.
+  Preferences::AddWeakObservers(this, kObservedPrefs);
+
+  nsCOMPtr<nsIObserverService> obsSvc = mozilla::services::GetObserverService();
   if (obsSvc) {
-    (void)obsSvc->AddObserver(this, TOPIC_PROFILE_TEARDOWN, false);
-    (void)obsSvc->AddObserver(this, TOPIC_PROFILE_CHANGE, false);
-    (void)obsSvc->AddObserver(this, TOPIC_IDLE_DAILY, false);
-    (void)obsSvc->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, false);
+    (void)obsSvc->AddObserver(this, TOPIC_PLACES_CONNECTION_CLOSED, true);
+    (void)obsSvc->AddObserver(this, TOPIC_IDLE_DAILY, true);
+    (void)obsSvc->AddObserver(this, NS_PRIVATE_BROWSING_SWITCH_TOPIC, true);
 #ifdef MOZ_XUL
-    (void)obsSvc->AddObserver(this, TOPIC_AUTOCOMPLETE_FEEDBACK_INCOMING, false);
+    (void)obsSvc->AddObserver(this, TOPIC_AUTOCOMPLETE_FEEDBACK_INCOMING, true);
 #endif
   }
 
   // Don't add code that can fail here! Do it up above, before we add our
   // observers.
 
   return NS_OK;
 }
 
-
-nsresult
-nsNavHistory::InitDBFile(bool aForceInit)
-{
-  if (!mDBService) {
-    mDBService = do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
-    NS_ENSURE_STATE(mDBService);
-  }
-
-  // Get database file handle.
-  nsCOMPtr<nsIFile> profDir;
-  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
-                                       getter_AddRefs(profDir));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = profDir->Clone(getter_AddRefs(mDBFile));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = mDBFile->Append(DATABASE_FILENAME);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (aForceInit) {
-    // If forcing initialization, backup and remove the old file.  If we have
-    // already failed in the last 24 hours avoid to create another corrupt file,
-    // since doing so, in some situation, could cause us to create a new corrupt
-    // file at every try to access any Places service.  That is bad because it
-    // would quickly fill the user's disk space without any notice.
-    if (!hasRecentCorruptDB()) {
-      // backup the database
-      nsCOMPtr<nsIFile> backup;
-      rv = mDBService->BackupDatabaseFile(mDBFile, DATABASE_CORRUPT_FILENAME,
-                                          profDir, getter_AddRefs(backup));
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-
-    // Close database connection if open.
-    if (mDBConn) {
-      // If there's any not finalized statement or this fails for any reason
-      // we won't be able to remove the database.
-      rv = mDBConn->Close();
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-
-    // Remove the broken database.
-    rv = mDBFile->Remove(false);
-    if (NS_FAILED(rv)) {
-      // If the file is still in use this will fail and we won't be able to
-      // start with a clean database.  The process of backing up a corrupt
-      // database will loop on the same database file at any next service
-      // request.
-      // We can't do much at this point, so fire a locked event so that user is
-      // notified that we can't ensure Places to work.
-      nsRefPtr<PlacesEvent> lockedEvent =
-        new PlacesEvent(TOPIC_DATABASE_LOCKED);
-      (void)NS_DispatchToMainThread(lockedEvent);
-    }
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // If aForceInit is true we were unable to initialize or upgrade the current
-    // database, so it was corrupt.
-    mDatabaseStatus = DATABASE_STATUS_CORRUPT;
-  }
-  else {
-    // Check if database file exists.
-    bool dbExists = true;
-    rv = mDBFile->Exists(&dbExists);
-    NS_ENSURE_SUCCESS(rv, rv);
-    // If the database didn't previously exist, we create it.
-    if (!dbExists) {
-      mDatabaseStatus = DATABASE_STATUS_CREATE;
-    }
-    else {
-      // Check if maintenance required a database replacement.
-      bool forceDatabaseReplacement;
-      if (NS_SUCCEEDED(mPrefBranch->GetBoolPref(PREF_FORCE_DATABASE_REPLACEMENT,
-                                                &forceDatabaseReplacement)) &&
-          forceDatabaseReplacement) {
-        // Be sure to clear the pref to avoid handling it more than once.
-        rv = mPrefBranch->ClearUserPref(PREF_FORCE_DATABASE_REPLACEMENT);
-        NS_ENSURE_SUCCESS(rv, rv);
-        // Re-enter this same method, forcing the replacement.
-        rv = InitDBFile(true);
-        NS_ENSURE_SUCCESS(rv, rv);
-        return NS_OK;
-      }
-    }
-  }
-
-  // Open the database file.  If it does not exist a new one will be created.
-  // Use a unshared connection, both for safety and performance.
-  rv = mDBService->OpenUnsharedDatabase(mDBFile, getter_AddRefs(mDBConn));
-  if (rv == NS_ERROR_FILE_CORRUPTED) {
-    // The database is corrupt, try to create a new one.
-    mDatabaseStatus = DATABASE_STATUS_CORRUPT;
-
-    // Backup and remove old corrupt database file.
-    nsCOMPtr<nsIFile> backup;
-    rv = mDBService->BackupDatabaseFile(mDBFile, DATABASE_CORRUPT_FILENAME,
-                                        profDir, getter_AddRefs(backup));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBFile->Remove(false);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Try again to initialize the database file.
-    rv = profDir->Clone(getter_AddRefs(mDBFile));
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBFile->Append(DATABASE_FILENAME);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBService->OpenUnsharedDatabase(mDBFile, getter_AddRefs(mDBConn));
-  }
- 
-  if (rv != NS_OK && rv != NS_ERROR_FILE_CORRUPTED) {
-    // If the database cannot be opened for any reason other than corruption,
-    // send out a notification and do not continue initialization.
-    // Note: We swallow errors here, since we want service init to fail anyway.
-    nsRefPtr<PlacesEvent> lockedEvent =
-      new PlacesEvent(TOPIC_DATABASE_LOCKED);
-    (void)NS_DispatchToMainThread(lockedEvent);
-  }
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-
-nsresult
-nsNavHistory::SetJournalMode(enum JournalMode aJournalMode)
-{
-  nsCAutoString journalMode;
-  switch (aJournalMode) {
-    default:
-      NS_NOTREACHED("Trying to set an unknown journal mode.");
-      // Fall through to the default mode of DELETE.
-    case JOURNAL_DELETE:
-      journalMode.AssignLiteral("delete");
-      break;
-    case JOURNAL_TRUNCATE:
-      journalMode.AssignLiteral("truncate");
-      break;
-    case JOURNAL_MEMORY:
-      journalMode.AssignLiteral("memory");
-      break;
-    case JOURNAL_WAL:
-      journalMode.AssignLiteral("wal");
-      break;
-  }
-
-  nsCOMPtr<mozIStorageStatement> statement;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "PRAGMA journal_mode = ") + journalMode,
-    getter_AddRefs(statement));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  mozStorageStatementScoper scoper(statement);
-  bool hasResult;
-  rv = statement->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, rv);
-  NS_ENSURE_TRUE(hasResult, NS_ERROR_FAILURE);
-
-  nsCAutoString currentJournalMode;
-  rv = statement->GetUTF8String(0, currentJournalMode);
-  NS_ENSURE_SUCCESS(rv, rv);
-  bool succeeded = currentJournalMode.Equals(journalMode);
-  if (succeeded) {
-    mCurrentJournalMode = aJournalMode;
-  }
-  else {
-    NS_WARNING(nsPrintfCString(128, "Setting journal mode failed: %s",
-                               journalMode.get()).get());
-    return NS_ERROR_FAILURE;
-  }
-
-  return NS_OK;
-}
-
-
-nsresult
-nsNavHistory::InitDB()
-{
-  // WARNING: any statement executed before setting the journal mode must be
-  // finalized, since SQLite doesn't allow changing the journal mode if there
-  // is any outstanding statement.
-
-  {
-    // Get the page size.  This may be different than the default if the
-    // database file already existed with a different page size.
-    nsCOMPtr<mozIStorageStatement> statement;
-    nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "PRAGMA page_size"
-    ), getter_AddRefs(statement));
-    NS_ENSURE_SUCCESS(rv, rv);
-    bool hasResult = false;
-    rv = statement->ExecuteStep(&hasResult);
-    NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && hasResult, NS_ERROR_FAILURE);
-    rv = statement->GetInt32(0, &mDBPageSize);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(mDBPageSize > 0, NS_ERROR_UNEXPECTED);
-  }
-
-  // Ensure that temp tables are held in memory, not on disk.
-  nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "PRAGMA temp_store = MEMORY"));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // We want to work with a cache that is at a maximum half of the database
-  // size.  We also want it to respect the available memory size.
-
-  // Calculate memory size, fallback to a meaningful value if it fails.
-  PRUint64 memSizeBytes = PR_GetPhysicalMemorySize();
-  if (memSizeBytes == 0) {
-    memSizeBytes = MEMSIZE_FALLBACK_BYTES;
-  }
-
-  PRUint64 cacheSize = memSizeBytes * DATABASE_CACHE_TO_MEMORY_PERC / 100;
-
-  // Calculate an optimal database size for expiration purposes.
-  // We usually want to work with a cache that is half the database size.
-  // Limit the size to avoid extreme values on high-end hardware.
-  PRInt64 optimalDatabaseSize = NS_MIN(static_cast<PRInt64>(cacheSize) * 2,
-                                       DATABASE_MAX_SIZE);
-
-  // Protect against a full disk or tiny quota.
-  PRInt64 diskAvailableBytes = 0;
-  nsCOMPtr<nsILocalFile> localDB = do_QueryInterface(mDBFile);
-  if (localDB &&
-      NS_SUCCEEDED(localDB->GetDiskSpaceAvailable(&diskAvailableBytes)) &&
-      diskAvailableBytes > 0) {
-    optimalDatabaseSize = NS_MIN(optimalDatabaseSize,
-                                 diskAvailableBytes * DATABASE_TO_DISK_PERC / 100);
-  }
-
-  // Share the calculated size if it's meaningful.
-  if (optimalDatabaseSize < PR_INT32_MAX) {
-    (void)mPrefBranch->SetIntPref(PREF_OPTIMAL_DATABASE_SIZE,
-                                  static_cast<PRInt32>(optimalDatabaseSize));
-  }
-
-  // Get the current database size. Due to chunked growth we have to use
-  // page_count to evaluate it.
-  PRUint64 databaseSizeBytes = 0;
-  {
-    nsCOMPtr<mozIStorageStatement> statement;
-    nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "PRAGMA page_count"
-    ), getter_AddRefs(statement));
-    NS_ENSURE_SUCCESS(rv, rv);
-    bool hasResult = false;
-    rv = statement->ExecuteStep(&hasResult);
-    NS_ENSURE_TRUE(NS_SUCCEEDED(rv) && hasResult, NS_ERROR_FAILURE);
-    PRInt32 pageCount = 0;
-    rv = statement->GetInt32(0, &pageCount);
-    NS_ENSURE_SUCCESS(rv, rv);
-    databaseSizeBytes = pageCount * mDBPageSize;
-  }
-
-  // Set cache to a maximum of half the database size.
-  cacheSize = NS_MIN(cacheSize, databaseSizeBytes / 2);
-  // Ensure we never work without a minimum cache.
-  cacheSize = NS_MAX(cacheSize, DATABASE_CACHE_MIN_BYTES);
-
-  // Set the number of cached pages.
-  // We don't use PRAGMA default_cache_size, since the database could be moved
-  // among different devices and the value would adapt accordingly.
-  nsCAutoString cacheSizePragma("PRAGMA cache_size = ");
-  cacheSizePragma.AppendInt(cacheSize / mDBPageSize);
-  rv = mDBConn->ExecuteSimpleSQL(cacheSizePragma);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Be sure to set journal mode after page_size.  WAL would prevent the change
-  // otherwise.
-  if (NS_SUCCEEDED(SetJournalMode(JOURNAL_WAL))) {
-    // Set the WAL journal size limit.  We want it to be small, since in
-    // synchronous = NORMAL mode a crash could cause loss of all the
-    // transactions in the journal.  For added safety we will also force
-    // checkpointing at strategic moments.
-    PRInt32 checkpointPages =
-      static_cast<PRInt32>(DATABASE_MAX_WAL_SIZE_IN_KIBIBYTES * 1024 / mDBPageSize);
-    nsCAutoString checkpointPragma("PRAGMA wal_autocheckpoint = ");
-    checkpointPragma.AppendInt(checkpointPages);
-    rv = mDBConn->ExecuteSimpleSQL(checkpointPragma);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-  else {
-    // Ignore errors, if we fail here the database could be considered corrupt
-    // and we won't be able to go on, even if it's just matter of a bogus file
-    // system.  The default mode (DELETE) will be fine in such a case.
-    (void)SetJournalMode(JOURNAL_TRUNCATE);
-
-    // Set synchronous to FULL to ensure maximum data integrity, even in
-    // case of crashes or unclean shutdowns.
-    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-        "PRAGMA synchronous = FULL"));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // Grow places in 10MiB increments
-  (void)mDBConn->SetGrowthIncrement(10 * BYTES_PER_MEBIBYTE, EmptyCString());
-
-  // We use our functions during migration, so initialize them now.
-  rv = InitFunctions();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Get the database schema version.
-  PRInt32 currentSchemaVersion;
-  rv = mDBConn->GetSchemaVersion(&currentSchemaVersion);
-  NS_ENSURE_SUCCESS(rv, rv);
-  bool databaseInitialized = currentSchemaVersion > 0;
-
-  if (databaseInitialized && currentSchemaVersion == DATABASE_SCHEMA_VERSION) {
-    // The database is up to date and ready to go.
-    return NS_OK;
-  }
-
-  // We are going to update the database, so everything from now on should be in
-  // a transaction for performances.
-  mozStorageTransaction transaction(mDBConn, false);
-
-  if (databaseInitialized) {
-    // Migration How-to:
-    //
-    // 1. increment PLACES_SCHEMA_VERSION.
-    // 2. implement a method that performs upgrade to your version from the
-    //    previous one.
-    //
-    // NOTE: The downgrade process is pretty much complicated by the fact old
-    //       versions cannot know what a new version is going to implement.
-    //       The only thing we will do for downgrades is setting back the schema
-    //       version, so that next upgrades will run again the migration step.
-
-    if (currentSchemaVersion < DATABASE_SCHEMA_VERSION) {
-      mDatabaseStatus = DATABASE_STATUS_UPGRADED;
-
-      // Firefox 3.0 uses schema version 6.
-
-      if (currentSchemaVersion < 7) {
-        rv = MigrateV7Up(mDBConn);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-
-      if (currentSchemaVersion < 8) {
-        rv = MigrateV8Up(mDBConn);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-
-      // Firefox 3.5 uses schema version 8.
-
-      if (currentSchemaVersion < 9) {
-        rv = MigrateV9Up(mDBConn);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-
-      if (currentSchemaVersion < 10) {
-        rv = MigrateV10Up(mDBConn);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-
-      // Firefox 3.6 uses schema version 10.
-
-      if (currentSchemaVersion < 11) {
-        rv = MigrateV11Up(mDBConn);
-        NS_ENSURE_SUCCESS(rv, rv);
-      }
-
-      // Firefox 4.0 uses schema version 11.
-
-      // Schema Upgrades must add migration code here.
-    }
-  }
-  else {
-    // This is a new database, so we have to create all the tables and indices.
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_MOZ_PLACES);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_URL);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_FAVICON);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_REVHOST);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_VISITCOUNT);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_FRECENCY);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_LASTVISITDATE);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_GUID);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_MOZ_HISTORYVISITS);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_PLACEDATE);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_FROMVISIT);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_VISITDATE);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_MOZ_INPUTHISTORY);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Initialize the other Places services' database tables, since some of our
-    // statements depend on them.
-    rv = nsNavBookmarks::InitTables(mDBConn);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = nsFaviconService::InitTables(mDBConn);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = nsAnnotationService::InitTables(mDBConn);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // Set the schema version to the current one.
-  rv = UpdateSchemaVersion();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = updateSQLiteStatistics(mDBConn);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = transaction.Commit();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  ForceWALCheckpoint(mDBConn);
-
-  // ANY FAILURE IN THIS METHOD WILL CAUSE US TO MARK THE DATABASE AS CORRUPT
-  // AND TRY TO REPLACE IT.
-  // DO NOT PUT HERE ANYTHING THAT IS NOT RELATED TO INITIALIZATION OR MODIFYING
-  // THE DISK DATABASE.
-
-  return NS_OK;
-}
-
-
-nsresult
-nsNavHistory::InitAdditionalDBItems()
-{
-  nsresult rv = InitTriggers();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-
-nsresult
-nsNavHistory::CheckAndUpdateGUIDs()
-{
-  // First, import any bookmark guids already set by Sync.
-  nsCOMPtr<mozIStorageStatement> updateStmt;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "UPDATE moz_bookmarks "
-    "SET guid = :guid "
-    "WHERE id = :item_id "
-  ), getter_AddRefs(updateStmt));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<mozIStorageStatement> stmt;
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT item_id, content "
-    "FROM moz_items_annos "
-    "JOIN moz_anno_attributes "
-    "WHERE name = :anno_name "
-  ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
-                                  SYNCGUID_ANNO);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  bool hasResult;
-  while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
-    PRInt64 itemId;
-    rv = stmt->GetInt64(0, &itemId);
-    NS_ENSURE_SUCCESS(rv, rv);
-    nsCAutoString guid;
-    rv = stmt->GetUTF8String(1, guid);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // If we have an invalid guid, we don't need to do any more work.
-    if (!IsValidGUID(guid)) {
-      continue;
-    }
-
-    mozStorageStatementScoper scoper(updateStmt);
-    rv = updateStmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), itemId);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = updateStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("guid"), guid);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = updateStmt->Execute();
-    if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
-      // We just tried to insert a duplicate guid.  Ignore this error, and we
-      // will generate a new one next.
-      continue;
-    }
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // Now, remove all the bookmark guid annotations that we just imported.
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "DELETE FROM moz_items_annos "
-    "WHERE anno_attribute_id = ( "
-      "SELECT id "
-      "FROM moz_anno_attributes "
-      "WHERE name = :anno_name "
-    ") "
-  ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
-                                  SYNCGUID_ANNO);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = stmt->Execute();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Next, generate guids for any bookmark that does not already have one.
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "UPDATE moz_bookmarks "
-    "SET guid = GENERATE_GUID() "
-    "WHERE guid IS NULL "
-  ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = stmt->Execute();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Now, import any history guids already set by Sync.
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "UPDATE moz_places "
-    "SET guid = :guid "
-    "WHERE id = :place_id "
-  ), getter_AddRefs(updateStmt));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT place_id, content "
-    "FROM moz_annos "
-    "JOIN moz_anno_attributes "
-    "WHERE name = :anno_name "
-  ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
-                                  SYNCGUID_ANNO);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
-    PRInt64 placeId;
-    rv = stmt->GetInt64(0, &placeId);
-    NS_ENSURE_SUCCESS(rv, rv);
-    nsCAutoString guid;
-    rv = stmt->GetUTF8String(1, guid);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // If we have an invalid guid, we don't need to do any more work.
-    if (!IsValidGUID(guid)) {
-      continue;
-    }
-
-    mozStorageStatementScoper scoper(updateStmt);
-    rv = updateStmt->BindInt64ByName(NS_LITERAL_CSTRING("place_id"), placeId);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = updateStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("guid"), guid);
-    NS_ENSURE_SUCCESS(rv, rv);
-    rv = updateStmt->Execute();
-    if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
-      // We just tried to insert a duplicate guid.  Ignore this error, and we
-      // will generate a new one next.
-      continue;
-    }
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // Now, remove all the place guid annotations that we just imported.
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "DELETE FROM moz_annos "
-    "WHERE anno_attribute_id = ( "
-      "SELECT id "
-      "FROM moz_anno_attributes "
-      "WHERE name = :anno_name "
-    ") "
-  ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
-                                  SYNCGUID_ANNO);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = stmt->Execute();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Finally, we need to generate guids for any places that do not already have
-  // one.
-  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
-    "UPDATE moz_places "
-    "SET guid = GENERATE_GUID() "
-    "WHERE guid IS NULL "
-  ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = stmt->Execute();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
 NS_IMETHODIMP
 nsNavHistory::GetDatabaseStatus(PRUint16 *aDatabaseStatus)
 {
   NS_ENSURE_ARG_POINTER(aDatabaseStatus);
-  *aDatabaseStatus = mDatabaseStatus;
+  *aDatabaseStatus = mDB->GetDatabaseStatus();
   return NS_OK;
 }
 
-
-/**
- * Called by the individual services' InitTables().
- */
-nsresult
-nsNavHistory::UpdateSchemaVersion()
-{
-  return mDBConn->SetSchemaVersion(DATABASE_SCHEMA_VERSION);
-}
-
-
 PRUint32
 nsNavHistory::GetRecentFlags(nsIURI *aURI)
 {
   PRUint32 result = 0;
   nsCAutoString spec;
   nsresult rv = aURI->GetSpec(spec);
   NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to get aURI's spec");
 
@@ -1192,619 +443,48 @@ nsNavHistory::GetRecentFlags(nsIURI *aUR
       result |= RECENT_ACTIVATED;
     if (CheckIsRecentEvent(&mRecentBookmark, spec))
       result |= RECENT_BOOKMARKED;
   }
 
   return result;
 }
 
-
-/**
- * Called after InitDB, this creates our own functions
- */
-class mozStorageFunctionGetUnreversedHost: public mozIStorageFunction
-{
-public:
-  NS_DECL_ISUPPORTS
-  NS_DECL_MOZISTORAGEFUNCTION
-};
-
-NS_IMPL_ISUPPORTS1(mozStorageFunctionGetUnreversedHost, mozIStorageFunction)
-
-NS_IMETHODIMP
-mozStorageFunctionGetUnreversedHost::OnFunctionCall(
-  mozIStorageValueArray* aFunctionArguments,
-  nsIVariant** _retval)
-{
-  NS_ASSERTION(aFunctionArguments, "Must have non-null function args");
-  NS_ASSERTION(_retval, "Must have non-null return pointer");
-
-  nsAutoString src;
-  aFunctionArguments->GetString(0, src);
-
-  nsresult rv;
-  nsCOMPtr<nsIWritableVariant> result(do_CreateInstance(
-      "@mozilla.org/variant;1", &rv));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (src.Length()>1) {
-    src.Truncate(src.Length() - 1);
-    nsAutoString dest;
-    ReverseString(src, dest);
-    result->SetAsAString(dest);
-  } else {
-    result->SetAsAString(EmptyString());
-  }
-  NS_ADDREF(*_retval = result);
-  return NS_OK;
-}
-
-nsresult
-nsNavHistory::InitFunctions()
-{
-  nsCOMPtr<mozIStorageFunction> func =
-    new mozStorageFunctionGetUnreversedHost;
-  NS_ENSURE_TRUE(func, NS_ERROR_OUT_OF_MEMORY);
-  nsresult rv = mDBConn->CreateFunction(
-    NS_LITERAL_CSTRING("get_unreversed_host"), 1, func
-  );
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = MatchAutoCompleteFunction::create(mDBConn);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = CalculateFrecencyFunction::create(mDBConn);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = GenerateGUIDFunction::create(mDBConn);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-nsresult
-nsNavHistory::InitTriggers()
-{
-  nsresult rv = mDBConn->ExecuteSimpleSQL(CREATE_HISTORYVISITS_AFTERINSERT_TRIGGER);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = mDBConn->ExecuteSimpleSQL(CREATE_HISTORYVISITS_AFTERDELETE_TRIGGER);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-mozIStorageStatement*
-nsNavHistory::GetStatement(const nsCOMPtr<mozIStorageStatement>& aStmt)
-{
-  // mCanNotify is set to false on shutdown.
-  if (!mCanNotify)
-    return nsnull;
-
-  // Note that this query violates the kGetInfoIndex_* convention in
-  // the last column.
-  RETURN_IF_STMT(mDBGetURLPageInfo, NS_LITERAL_CSTRING(
-    "SELECT id, url, title, rev_host, visit_count, guid "
-    "FROM moz_places "
-    "WHERE url = :page_url "
-  ));
-
-  RETURN_IF_STMT(mDBGetIdPageInfo, NS_LITERAL_CSTRING(
-    "SELECT id, url, title, rev_host, visit_count "
-    "FROM moz_places "
-    "WHERE id = :page_id "
-  ));
-
-  RETURN_IF_STMT(mDBRecentVisitOfURL, NS_LITERAL_CSTRING(
-    "SELECT id, session, visit_date "
-    "FROM moz_historyvisits "
-    "WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
-    "ORDER BY visit_date DESC "
-  ));
-
-  RETURN_IF_STMT(mDBRecentVisitOfPlace, NS_LITERAL_CSTRING(
-    "SELECT id FROM moz_historyvisits "
-    "WHERE place_id = :page_id "
-      "AND visit_date = :visit_date "
-      "AND session = :session "
-  ));
-
-  RETURN_IF_STMT(mDBInsertVisit, NS_LITERAL_CSTRING(
-    "INSERT INTO moz_historyvisits "
-      "(from_visit, place_id, visit_date, visit_type, session) "
-    "VALUES (:from_visit, :page_id, :visit_date, :visit_type, :session) "
-  ));
-
-  RETURN_IF_STMT(mDBGetPageVisitStats, NS_LITERAL_CSTRING(
-    "SELECT id, visit_count, typed, hidden, guid "
-    "FROM moz_places "
-    "WHERE url = :page_url "
-  ));
-
-  RETURN_IF_STMT(mDBIsPageVisited, NS_LITERAL_CSTRING(
-    "SELECT h.id "
-    "FROM moz_places h "
-    "WHERE url = ?1 "
-      "AND EXISTS(SELECT id FROM moz_historyvisits WHERE place_id = h.id LIMIT 1) "
-  ));
-
-  RETURN_IF_STMT(mDBUpdatePageVisitStats, NS_LITERAL_CSTRING(
-    "UPDATE moz_places "
-    "SET hidden = :hidden, typed = :typed "
-    "WHERE id = :page_id "
-  ));
-
-  // We have both sync and async users, so it could happen that an async
-  // statement tries to insert a page when a sync statement just added it.
-  // We should ignore the insertion in such a case, the async implementer
-  // will fetch the id of the existing entry.
-  RETURN_IF_STMT(mDBAddNewPage, NS_LITERAL_CSTRING(
-    "INSERT OR IGNORE INTO moz_places "
-      "(url, title, rev_host, hidden, typed, frecency, guid) "
-    "VALUES (:page_url, :page_title, :rev_host, :hidden, :typed, :frecency, "
-             "GENERATE_GUID()) "
-  ));
-
-  RETURN_IF_STMT(mDBGetTags, NS_LITERAL_CSTRING(
-    "/* do not warn (bug 487594) */ "
-    "SELECT GROUP_CONCAT(tag_title, ', ') "
-    "FROM ( "
-      "SELECT t.title AS tag_title "
-      "FROM moz_bookmarks b "
-      "JOIN moz_bookmarks t ON t.id = b.parent "
-      "WHERE b.fk = (SELECT id FROM moz_places WHERE url = :page_url) "
-        "AND t.parent = :tags_folder "
-      "ORDER BY t.title COLLATE NOCASE ASC "
-    ") "
-  ));
-
-  RETURN_IF_STMT(mDBGetItemsWithAnno, NS_LITERAL_CSTRING(
-    "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 = :anno_name "
-  ));
-
-  RETURN_IF_STMT(mDBSetPlaceTitle, NS_LITERAL_CSTRING(
-    "UPDATE moz_places "
-    "SET title = :page_title "
-    "WHERE url = :page_url "
-  ));
-
-  RETURN_IF_STMT(mDBUpdateFrecency, NS_LITERAL_CSTRING(
-      "UPDATE moz_places "
-      "SET frecency = CALCULATE_FRECENCY(:page_id) "
-      "WHERE id = :page_id"
-  ));
-
-  RETURN_IF_STMT(mDBUpdateHiddenOnFrecency, NS_LITERAL_CSTRING(
-      "UPDATE moz_places "
-      "SET hidden = 0 "
-      "WHERE id = :page_id AND frecency <> 0"
-  ));
-
-#ifdef MOZ_XUL
-  RETURN_IF_STMT(mDBFeedbackIncrease, 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, :input_text), 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 = :input_text "
-      "WHERE url = :page_url "));
-#endif
-
-  nsCAutoString tagsFragment;
-  GetTagsSqlFragment(GetTagsFolder(), NS_LITERAL_CSTRING("h.id"),
-                     true, tagsFragment);
-
-  // Should match kGetInfoIndex_* (see GetQueryResults)
-  RETURN_IF_STMT(mDBVisitToVisitResult, NS_LITERAL_CSTRING(
-    "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
-           "v.visit_date, f.url, v.session, null, null, null, null, "
-           ) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency "
-    "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 v.id = :visit_id "
-  ));
-
-  // Should match kGetInfoIndex_* (see GetQueryResults)
-  RETURN_IF_STMT(mDBVisitToURLResult, NS_LITERAL_CSTRING(
-    "SELECT h.id, h.url, h.title, h.rev_host, h.visit_count, "
-           "h.last_visit_date, f.url, null, null, null, null, null, "
-           ) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency "
-    "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 v.id = :visit_id "
-  ));
-
-  // mDBBookmarkToUrlResult, should match kGetInfoIndex_*
-  RETURN_IF_STMT(mDBBookmarkToUrlResult, NS_LITERAL_CSTRING(
-    "SELECT b.fk, h.url, COALESCE(b.title, h.title), "
-           "h.rev_host, h.visit_count, h.last_visit_date, f.url, null, b.id, "
-           "b.dateAdded, b.lastModified, b.parent, "
-           ) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency "
-    "FROM moz_bookmarks b "
-    "JOIN moz_places h ON b.fk = h.id "
-    "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
-    "WHERE b.id = :item_id "
-  ));
-
-  // mDBUrlToUrlResult, should match kGetInfoIndex_*
-  RETURN_IF_STMT(mDBUrlToUrlResult, NS_LITERAL_CSTRING(
-    "SELECT h.id, :page_url, h.title, h.rev_host, h.visit_count, "
-           "h.last_visit_date, f.url, null, null, null, null, null, "
-           ) + tagsFragment + NS_LITERAL_CSTRING(", h.frecency "
-    "FROM moz_places h "
-    "LEFT JOIN moz_favicons f ON h.favicon_id = f.id "
-    "WHERE h.url = :page_url "
-  ));
-
-  return nsnull;
-}
-
-
-nsresult
-nsNavHistory::MigrateV7Up(mozIStorageConnection* aDBConn) 
-{
-  mozStorageTransaction transaction(aDBConn, false);
-
-  // 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.
-  bool lastModIndexExists = false;
-  nsresult rv = aDBConn->IndexExists(
-    NS_LITERAL_CSTRING("moz_bookmarks_itemlastmodifiedindex"),
-    &lastModIndexExists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!lastModIndexExists) {
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_PLACELASTMODIFIED);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // We need to do a one-time change of the moz_historyvisits.pageindex
-  // to speed up finding last visit date when joinin with moz_places.
-  // See bug 392399 for more details.
-  bool pageIndexExists = false;
-  rv = aDBConn->IndexExists(
-    NS_LITERAL_CSTRING("moz_historyvisits_pageindex"), &pageIndexExists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (pageIndexExists) {
-    // drop old index
-    rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-        "DROP INDEX IF EXISTS moz_historyvisits_pageindex"));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // create the new multi-column index
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_HISTORYVISITS_PLACEDATE);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // for existing profiles, we may not have a frecency column
-  nsCOMPtr<mozIStorageStatement> hasFrecencyStatement;
-  rv = aDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT frecency FROM moz_places"),
-    getter_AddRefs(hasFrecencyStatement));
-
-  if (NS_FAILED(rv)) {
-    // Add frecency column to moz_places, default to -1 so that all the
-    // frecencies are invalid
-    rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-        "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(CREATE_IDX_MOZ_PLACES_FRECENCY);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Invalidate all frecencies, since they need recalculation.
-    rv = invalidateFrecencies(EmptyCString());
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // Temporary migration code for bug 396300
-  nsCOMPtr<mozIStorageStatement> moveUnfiledBookmarks;
-  rv = aDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "UPDATE moz_bookmarks "
-      "SET parent = ("
-        "SELECT folder_id "
-        "FROM moz_bookmarks_roots "
-        "WHERE root_name = :root_name "
-      ") "
-      "WHERE type = :item_type "
-      "AND parent = ("
-        "SELECT folder_id "
-        "FROM moz_bookmarks_roots "
-        "WHERE root_name = :parent_name "
-      ")"),
-    getter_AddRefs(moveUnfiledBookmarks));
-  rv = moveUnfiledBookmarks->BindUTF8StringByName(
-    NS_LITERAL_CSTRING("root_name"), NS_LITERAL_CSTRING("unfiled")
-  );
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = moveUnfiledBookmarks->BindInt32ByName(
-    NS_LITERAL_CSTRING("item_type"), nsINavBookmarksService::TYPE_BOOKMARK
-  );
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = moveUnfiledBookmarks->BindUTF8StringByName(
-    NS_LITERAL_CSTRING("parent_name"), NS_LITERAL_CSTRING("places")
-  );
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = moveUnfiledBookmarks->Execute();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Create a statement to test for trigger creation
-  nsCOMPtr<mozIStorageStatement> triggerDetection;
-  rv = aDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT name "
-      "FROM sqlite_master "
-      "WHERE type = 'trigger' "
-      "AND name = :trigger_name"),
-    getter_AddRefs(triggerDetection));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Check for existence
-  bool triggerExists;
-  rv = triggerDetection->BindUTF8StringByName(
-    NS_LITERAL_CSTRING("trigger_name"),
-    NS_LITERAL_CSTRING("moz_historyvisits_afterinsert_v1_trigger")
-  );
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = triggerDetection->ExecuteStep(&triggerExists);
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = triggerDetection->Reset();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // 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 ") +
-              nsPrintfCString("(0,%d,%d,%d) ",
-                              nsINavHistoryService::TRANSITION_EMBED,
-                              nsINavHistoryService::TRANSITION_FRAMED_LINK,
-                              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->BindUTF8StringByName(
-    NS_LITERAL_CSTRING("trigger_name"),
-    NS_LITERAL_CSTRING("moz_bookmarks_beforedelete_v1_trigger")
-  );
-  NS_ENSURE_SUCCESS(rv, rv);
-  rv = triggerDetection->ExecuteStep(&triggerExists);
-  NS_ENSURE_SUCCESS(rv, rv);
-  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"
-        ")"));
-    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, false);
-
-  nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "DROP TRIGGER IF EXISTS moz_historyvisits_afterinsert_v1_trigger"));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "DROP TRIGGER IF EXISTS moz_historyvisits_afterdelete_v1_trigger"));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-
-  // bug #381795 - remove unused indexes
-  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_annos_item_idindex"));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-
-  // Do a one-time re-creation of the moz_annos indexes (bug 415201)
-  bool oldIndexExists = false;
-  rv = mDBConn->IndexExists(NS_LITERAL_CSTRING("moz_annos_attributesindex"), &oldIndexExists);
-  NS_ENSURE_SUCCESS(rv, rv);
-  if (oldIndexExists) {
-    // drop old uri annos index
-    rv = mDBConn->ExecuteSimpleSQL(
-        NS_LITERAL_CSTRING("DROP INDEX moz_annos_attributesindex"));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // create new uri annos index
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_ANNOS_PLACEATTRIBUTE);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // drop old item annos index
-    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(CREATE_IDX_MOZ_ITEMSANNOS_PLACEATTRIBUTE);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return transaction.Commit();
-}
-
-
-nsresult
-nsNavHistory::MigrateV9Up(mozIStorageConnection *aDBConn)
-{
-  mozStorageTransaction transaction(aDBConn, false);
-  // Added in Bug 488966.  The last_visit_date column caches the last
-  // visit date, this enhances SELECT performances when we
-  // need to sort visits by visit date.
-  // The cached value is synced by triggers on every added or removed visit.
-  // See nsPlacesTriggers.h for details on the triggers.
-  bool oldIndexExists = false;
-  nsresult rv = mDBConn->IndexExists(
-    NS_LITERAL_CSTRING("moz_places_lastvisitdateindex"), &oldIndexExists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (!oldIndexExists) {
-    // Add last_visit_date column to moz_places.
-    rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-        "ALTER TABLE moz_places ADD last_visit_date INTEGER"));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = mDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_LASTVISITDATE);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // Now let's sync the column contents with real visit dates.
-    // This query can be really slow due to disk access, since it will basically
-    // dupe the table contents in the journal file, and then write them down
-    // in the database.
-    rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-        "UPDATE moz_places SET last_visit_date = "
-          "(SELECT MAX(visit_date) "
-           "FROM moz_historyvisits "
-           "WHERE place_id = moz_places.id)"));
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  return transaction.Commit();
-}
-
-
-nsresult
-nsNavHistory::MigrateV10Up(mozIStorageConnection *aDBConn)
-{
-  // LastModified is set to the same value as dateAdded on item creation.
-  // This way we can use lastModified index to sort.
-  nsresult rv = mDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "UPDATE moz_bookmarks SET lastModified = dateAdded "
-      "WHERE lastModified IS NULL"));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-
-nsresult
-nsNavHistory::MigrateV11Up(mozIStorageConnection *aDBConn)
-{
-  // Temp tables are going away.
-  // For triggers correctness, every time we pass through this migration
-  // step, we must ensure correctness of visit_count values.
-  nsresult 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 ") +
-          nsPrintfCString("(0,%d,%d,%d) ",
-                          nsINavHistoryService::TRANSITION_EMBED,
-                          nsINavHistoryService::TRANSITION_FRAMED_LINK,
-                          nsINavHistoryService::TRANSITION_DOWNLOAD) +
-      NS_LITERAL_CSTRING(")")
-  );
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // For existing profiles, we may not have a moz_bookmarks.guid column
-  nsCOMPtr<mozIStorageStatement> hasGuidStatement;
-  rv = aDBConn->CreateStatement(NS_LITERAL_CSTRING(
-      "SELECT guid FROM moz_bookmarks"),
-    getter_AddRefs(hasGuidStatement));
-
-  if (NS_FAILED(rv)) {
-    // moz_bookmarks grew a guid column.  Add the column, but do not populate it
-    // with anything just yet.  We will do that soon.
-    rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "ALTER TABLE moz_bookmarks "
-      "ADD COLUMN guid TEXT"
-    ));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_BOOKMARKS_GUID);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    // moz_placess grew a guid column.  Add the column, but do not populate it
-    // with anything just yet.  We will do that soon.
-    rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-      "ALTER TABLE moz_places "
-      "ADD COLUMN guid TEXT"
-    ));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = aDBConn->ExecuteSimpleSQL(CREATE_IDX_MOZ_PLACES_GUID);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // We need to update our guids before we do any real database work.
-  rv = CheckAndUpdateGUIDs();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
 nsresult
 nsNavHistory::GetIdForPage(nsIURI* aURI,
                            PRInt64* _pageId,
                            nsCString& _GUID)
 {
   *_pageId = 0;
 
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBGetURLPageInfo);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT id, url, title, rev_host, visit_count, guid "
+    "FROM moz_places "
+    "WHERE url = :page_url "
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasEntry = false;
   rv = stmt->ExecuteStep(&hasEntry);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (hasEntry) {
-    rv = stmt->GetInt64(kGetInfoIndex_PageID, _pageId);
+    rv = stmt->GetInt64(0, _pageId);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->GetUTF8String(5, _GUID);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
-  
+
 nsresult
 nsNavHistory::GetOrCreateIdForPage(nsIURI* aURI,
                                    PRInt64* _pageId,
                                    nsCString& _GUID)
 {
   nsresult rv = GetIdForPage(aURI, _pageId, _GUID);
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1836,17 +516,25 @@ nsNavHistory::InternalAddNewPage(nsIURI*
                                  const nsAString& aTitle,
                                  bool aHidden,
                                  bool aTyped,
                                  PRInt32 aVisitCount,
                                  bool aCalculateFrecency,
                                  PRInt64* aPageID,
                                  nsACString& guid)
 {
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBAddNewPage);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "INSERT OR IGNORE INTO moz_places "
+      "(url, title, rev_host, hidden, typed, frecency, guid) "
+    "VALUES (:page_url, :page_title, :rev_host, :hidden, :typed, :frecency, "
+             "GENERATE_GUID()) "
+  );
+  NS_ENSURE_STATE(stmt);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (aTitle.IsVoid()) {
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("page_title"));
   }
   else {
     rv = stmt->BindStringByName(
@@ -1877,17 +565,24 @@ nsNavHistory::InternalAddNewPage(nsIURI*
                              IsQueryURI(spec) ? 0 : -1);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
   PRInt64 pageId = 0;
   {
-    DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(getIdStmt, mDBGetURLPageInfo);
+    nsCOMPtr<mozIStorageStatement> getIdStmt = mDB->GetStatement(
+      "SELECT id, url, title, rev_host, visit_count, guid "
+      "FROM moz_places "
+      "WHERE url = :page_url "
+    );
+    NS_ENSURE_STATE(getIdStmt);
+    mozStorageStatementScoper getIdScoper(getIdStmt);
+
     rv = URIBinder::Bind(getIdStmt, NS_LITERAL_CSTRING("page_url"), aURI);
     NS_ENSURE_SUCCESS(rv, rv);
 
     bool hasResult = false;
     rv = getIdStmt->ExecuteStep(&hasResult);
     NS_ENSURE_SUCCESS(rv, rv);
     NS_ASSERTION(hasResult, "hasResult is false but the call succeeded?");
     pageId = getIdStmt->AsInt64(0);
@@ -1915,17 +610,23 @@ nsNavHistory::InternalAddNewPage(nsIURI*
 nsresult
 nsNavHistory::InternalAddVisit(PRInt64 aPageID, PRInt64 aReferringVisit,
                                PRInt64 aSessionID, PRTime aTime,
                                PRInt32 aTransitionType, PRInt64* visitID)
 {
   nsresult rv;
 
   {
-    DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBInsertVisit);
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+      "INSERT INTO moz_historyvisits "
+        "(from_visit, place_id, visit_date, visit_type, session) "
+      "VALUES (:from_visit, :page_id, :visit_date, :visit_type, :session) "
+    );
+    NS_ENSURE_STATE(stmt);
+    mozStorageStatementScoper scoper (stmt);
   
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("from_visit"), aReferringVisit);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), aPageID);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("visit_date"), aTime);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("visit_type"), aTransitionType);
@@ -1933,17 +634,24 @@ nsNavHistory::InternalAddVisit(PRInt64 a
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("session"), aSessionID);
     NS_ENSURE_SUCCESS(rv, rv);
   
     rv = stmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   {
-    DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT(stmt, mDBRecentVisitOfPlace);
+    nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+      "SELECT id FROM moz_historyvisits "
+      "WHERE place_id = :page_id "
+        "AND visit_date = :visit_date "
+        "AND session = :session "
+    );
+    NS_ENSURE_STATE(stmt);
+    mozStorageStatementScoper scoper(stmt);
 
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), aPageID);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("visit_date"), aTime);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("session"), aSessionID);
     NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1972,17 +680,24 @@ nsNavHistory::InternalAddVisit(PRInt64 a
 //    This is used to compute the referring visit.
 
 bool
 nsNavHistory::FindLastVisit(nsIURI* aURI,
                             PRInt64* aVisitID,
                             PRTime* aTime,
                             PRInt64* aSessionID)
 {
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT_RET(stmt, mDBRecentVisitOfURL, false);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT id, session, visit_date "
+    "FROM moz_historyvisits "
+    "WHERE place_id = (SELECT id FROM moz_places WHERE url = :page_url) "
+    "ORDER BY visit_date DESC "
+  );
+  NS_ENSURE_TRUE(stmt, false);
+  mozStorageStatementScoper scoper(stmt);
   nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), aURI);
   NS_ENSURE_SUCCESS(rv, false);
 
   bool hasMore;
   rv = stmt->ExecuteStep(&hasMore);
   NS_ENSURE_SUCCESS(rv, false);
   if (hasMore) {
     rv = stmt->GetInt64(0, aVisitID);
@@ -2000,108 +715,95 @@ nsNavHistory::FindLastVisit(nsIURI* aURI
 // nsNavHistory::IsURIStringVisited
 //
 //    Takes a URL as a string and returns true if we've visited it.
 //
 //    Be careful to always reset the statement since it will be reused.
 
 bool nsNavHistory::IsURIStringVisited(const nsACString& aURIString)
 {
-  DECLARE_AND_ASSIGN_SCOPED_LAZY_STMT_RET(stmt, mDBIsPageVisited, false);
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT h.id "
+    "FROM moz_places h "
+    "WHERE url = ?1 "
+      "AND EXISTS(SELECT id FROM moz_historyvisits WHERE place_id = h.id LIMIT 1) "
+  );
+  NS_ENSURE_TRUE(stmt, false);
+  mozStorageStatementScoper scoper(stmt);
+
   nsresult rv = URIBinder::Bind(stmt, 0, aURIString);
   NS_ENSURE_SUCCESS(rv, false);
 
   bool hasMore = false;
   rv = stmt->ExecuteStep(&hasMore);
   NS_ENSURE_SUCCESS(rv, false);
   return hasMore;
 }
 
 
 void
 nsNavHistory::LoadPrefs()
 {
-  if (!mPrefBranch)
-    return;
-
   // History preferences.
   // Check the old preference and migrate disabled state.
-  nsCOMPtr<nsIPrefBranch> prefSvc = do_GetService(NS_PREFSERVICE_CONTRACTID);
-  PRInt32 oldDaysPref = 0;
-  if (prefSvc &&
-      NS_SUCCEEDED(prefSvc->GetIntPref("browser.history_expire_days",
-                                       &oldDaysPref))) {
-    if (!oldDaysPref) {
+  PRInt32 oldDaysPref = Preferences::GetInt("browser.history_expire_days", -1);
+  if (oldDaysPref >= 0) {
+    if (oldDaysPref == 0) {
       // Preserve history disabled state, for privacy reasons.
-      mPrefBranch->SetBoolPref(PREF_HISTORY_ENABLED, false);
+      Preferences::SetBool(PREF_HISTORY_ENABLED, false);
       mHistoryEnabled = false;
     }
     // Clear the old pref, otherwise we will keep using it.
-    prefSvc->ClearUserPref("browser.history_expire_days");
+    Preferences::ClearUser("browser.history_expire_days");
   }
-  else
-    mPrefBranch->GetBoolPref(PREF_HISTORY_ENABLED, &mHistoryEnabled);
+  else {
+    mHistoryEnabled = Preferences::GetBool(PREF_HISTORY_ENABLED, true);
+  }
 
   // Frecency preferences.
-  mPrefBranch->GetIntPref(PREF_FRECENCY_NUM_VISITS,
-    &mNumVisitsForFrecency);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_FIRST_BUCKET_CUTOFF,
-    &mFirstBucketCutoffInDays);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_SECOND_BUCKET_CUTOFF,
-    &mSecondBucketCutoffInDays);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_THIRD_BUCKET_CUTOFF,
-    &mThirdBucketCutoffInDays);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_FOURTH_BUCKET_CUTOFF,
-    &mFourthBucketCutoffInDays);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_EMBED_VISIT_BONUS,
-    &mEmbedVisitBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_FRAMED_LINK_VISIT_BONUS,
-    &mFramedLinkVisitBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_LINK_VISIT_BONUS,
-    &mLinkVisitBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_TYPED_VISIT_BONUS,
-    &mTypedVisitBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_BOOKMARK_VISIT_BONUS,
-    &mBookmarkVisitBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_DOWNLOAD_VISIT_BONUS,
-    &mDownloadVisitBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_PERM_REDIRECT_VISIT_BONUS,
-    &mPermRedirectVisitBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_TEMP_REDIRECT_VISIT_BONUS,
-    &mTempRedirectVisitBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_DEFAULT_VISIT_BONUS,
-    &mDefaultVisitBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_UNVISITED_BOOKMARK_BONUS,
-    &mUnvisitedBookmarkBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_UNVISITED_TYPED_BONUS,
-    &mUnvisitedTypedBonus);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_FIRST_BUCKET_WEIGHT,
-    &mFirstBucketWeight);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_SECOND_BUCKET_WEIGHT,
-    &mSecondBucketWeight);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_THIRD_BUCKET_WEIGHT,
-    &mThirdBucketWeight);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_FOURTH_BUCKET_WEIGHT,
-    &mFourthBucketWeight);
-  mPrefBranch->GetIntPref(PREF_FRECENCY_DEFAULT_BUCKET_WEIGHT,
-    &mDefaultWeight);
+#define FRECENCY_PREF(_prop, _pref) \
+  _prop = Preferences::GetInt(_pref, _pref##_DEF)
+
+  FRECENCY_PREF(mNumVisitsForFrecency,     PREF_FREC_NUM_VISITS);
+  FRECENCY_PREF(mFirstBucketCutoffInDays,  PREF_FREC_FIRST_BUCKET_CUTOFF);
+  FRECENCY_PREF(mSecondBucketCutoffInDays, PREF_FREC_SECOND_BUCKET_CUTOFF);
+  FRECENCY_PREF(mThirdBucketCutoffInDays,  PREF_FREC_THIRD_BUCKET_CUTOFF);
+  FRECENCY_PREF(mFourthBucketCutoffInDays, PREF_FREC_FOURTH_BUCKET_CUTOFF);
+  FRECENCY_PREF(mEmbedVisitBonus,          PREF_FREC_EMBED_VISIT_BONUS);
+  FRECENCY_PREF(mFramedLinkVisitBonus,     PREF_FREC_FRAMED_LINK_VISIT_BONUS);
+  FRECENCY_PREF(mLinkVisitBonus,           PREF_FREC_LINK_VISIT_BONUS);
+  FRECENCY_PREF(mTypedVisitBonus,          PREF_FREC_TYPED_VISIT_BONUS);
+  FRECENCY_PREF(mBookmarkVisitBonus,       PREF_FREC_BOOKMARK_VISIT_BONUS);
+  FRECENCY_PREF(mDownloadVisitBonus,       PREF_FREC_DOWNLOAD_VISIT_BONUS);
+  FRECENCY_PREF(mPermRedirectVisitBonus,   PREF_FREC_PERM_REDIRECT_VISIT_BONUS);
+  FRECENCY_PREF(mTempRedirectVisitBonus,   PREF_FREC_TEMP_REDIRECT_VISIT_BONUS);
+  FRECENCY_PREF(mDefaultVisitBonus,        PREF_FREC_DEFAULT_VISIT_BONUS);
+  FRECENCY_PREF(mUnvisitedBookmarkBonus,   PREF_FREC_UNVISITED_BOOKMARK_BONUS);
+  FRECENCY_PREF(mUnvisitedTypedBonus,      PREF_FREC_UNVISITED_TYPED_BONUS);
+  FRECENCY_PREF(mFirstBucketWeight,        PREF_FREC_FIRST_BUCKET_WEIGHT);
+  FRECENCY_PREF(mSecondBucketWeight,       PREF_FREC_SECOND_BUCKET_WEIGHT);
+  FRECENCY_PREF(mThirdBucketWeight,        PREF_FREC_THIRD_BUCKET_WEIGHT);
+  FRECENCY_PREF(mFourthBucketWeight,       PREF_FREC_FOURTH_BUCKET_WEIGHT);
+  FRECENCY_PREF(mDefaultWeight,            PREF_FREC_DEFAULT_BUCKET_WEIGHT);
+
+#undef FRECENCY_PREF
 }
 
 
 PRInt64
 nsNavHistory::GetNewSessionID()
 {
   // Use cached value if already initialized.
   if (mLastSessionID)
     return ++mLastSessionID;
 
   // Extract the last session ID, so we know where to pick up. There is no
   // index over sessions so we use the visit_date index.
   nsCOMPtr<mozIStorageStatement> selectSession;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+  nsresult rv = mDB->MainConn()->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT session FROM moz_historyvisits "
     "ORDER BY visit_date DESC "
   ), getter_AddRefs(selectSession));
   NS_ENSURE_SUCCESS(rv, rv);
   bool hasSession;
   if (NS_SUCCEEDED(selectSession->ExecuteStep(&hasSession)) && hasSession)
     mLastSessionID = selectSession->AsInt64(0) + 1;
   else
@@ -2135,37 +837,37 @@ nsNavHistory::NotifyTitleChange(nsIURI* 
 {
   MOZ_ASSERT(!aGUID.IsEmpty());
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavHistoryObserver, OnTitleChanged(aURI, aTitle, aGUID));
 }
 
 PRInt32
 nsNavHistory::GetDaysOfHistory() {
+  nsCOMPtr<mozIStorageStatement> stmt = mDB->GetStatement(
+    "SELECT ROUND(( "
+      "strftime('%s','now','localtime','utc') - "
+      "( "