Bug 1458910 - Merge nsPIPlacesDatabase into nsINavHistoryService. r=standard8 draft
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 10 May 2018 10:39:12 +0200
changeset 793518 27f7d939ab9acab6eb4896e8fc1348e74aee35cf
parent 793510 4e57d4dc19fa464e86c25f8ff45c897c0d864b8e
child 793545 b096792719a74fcf15909ce93f0d9341754009f6
push id109415
push usermak77@bonardo.net
push dateThu, 10 May 2018 08:59:47 +0000
reviewersstandard8
bugs1458910
milestone62.0a1
Bug 1458910 - Merge nsPIPlacesDatabase into nsINavHistoryService. r=standard8 MozReview-Commit-ID: LacXKR32Jn3
browser/base/content/test/general/head.js
browser/base/content/test/sanitize/browser_sanitizeDialog.js
browser/components/places/tests/browser/head.js
browser/modules/Sanitizer.jsm
browser/modules/WindowsJumpLists.jsm
toolkit/components/places/PlacesUtils.jsm
toolkit/components/places/Shutdown.h
toolkit/components/places/moz.build
toolkit/components/places/nsINavHistoryService.idl
toolkit/components/places/nsNavHistory.cpp
toolkit/components/places/nsNavHistory.h
toolkit/components/places/nsPIPlacesDatabase.idl
toolkit/components/places/nsPlacesExpiration.js
toolkit/components/places/nsTaggingService.js
toolkit/components/places/tests/bookmarks/test_448584.js
toolkit/components/places/tests/browser/browser_settitle.js
toolkit/components/places/tests/browser/browser_visituri.js
toolkit/components/places/tests/browser/head.js
toolkit/components/places/tests/gtest/places_test_harness.h
toolkit/components/places/tests/head_common.js
toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js
toolkit/components/places/tests/unit/test_history.js
toolkit/components/places/tests/unit/test_preventive_maintenance.js
toolkit/modules/NewTabUtils.jsm
--- a/browser/base/content/test/general/head.js
+++ b/browser/base/content/test/general/head.js
@@ -237,53 +237,16 @@ function promiseOpenAndLoadWindow(aOptio
     } else {
       win.addEventListener("load", function() {
         resolve(win);
       }, {once: true});
     }
   });
 }
 
-/**
- * Waits for all pending async statements on the default connection, before
- * proceeding with aCallback.
- *
- * @param aCallback
- *        Function to be called when done.
- * @param aScope
- *        Scope for the callback.
- * @param aArguments
- *        Arguments array for the callback.
- *
- * @note The result is achieved by asynchronously executing a query requiring
- *       a write lock.  Since all statements on the same connection are
- *       serialized, the end of this write operation means that all writes are
- *       complete.  Note that WAL makes so that writers don't block readers, but
- *       this is a problem only across different connections.
- */
-function waitForAsyncUpdates(aCallback, aScope, aArguments) {
-  let scope = aScope || this;
-  let args = aArguments || [];
-  let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                              .DBConnection;
-  let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
-  begin.executeAsync();
-  begin.finalize();
-
-  let commit = db.createAsyncStatement("COMMIT");
-  commit.executeAsync({
-    handleResult() {},
-    handleError() {},
-    handleCompletion(aReason) {
-      aCallback.apply(scope, args);
-    }
-  });
-  commit.finalize();
-}
-
 function whenNewTabLoaded(aWindow, aCallback) {
   aWindow.BrowserOpenTab();
 
   let browser = aWindow.gBrowser.selectedBrowser;
   let doc = browser.contentDocumentAsCPOW;
   if (doc && doc.readyState === "complete") {
     aCallback();
     return;
--- a/browser/base/content/test/sanitize/browser_sanitizeDialog.js
+++ b/browser/base/content/test/sanitize/browser_sanitizeDialog.js
@@ -771,18 +771,18 @@ WindowHelper.prototype = {
     return !this.getWarningPanel().hidden;
   },
 
   /**
    * Opens the clear recent history dialog.  Before calling this, set
    * this.onload to a function to execute onload.  It should close the dialog
    * when done so that the tests may continue.  Set this.onunload to a function
    * to execute onunload.  this.onunload is optional. If it returns true, the
-   * caller is expected to call waitForAsyncUpdates at some point; if false is
-   * returned, waitForAsyncUpdates is called automatically.
+   * caller is expected to call promiseAsyncUpdates at some point; if false is
+   * returned, promiseAsyncUpdates is called automatically.
    */
   open() {
     let wh = this;
 
     function windowObserver(aSubject, aTopic, aData) {
       if (aTopic != "domwindowopened")
         return;
 
--- a/browser/components/places/tests/browser/head.js
+++ b/browser/components/places/tests/browser/head.js
@@ -60,53 +60,16 @@ function promiseLibraryClosed(organizer)
  *        Data flavor to expect.
  */
 function promiseClipboard(aPopulateClipboardFn, aFlavor) {
   return new Promise((resolve, reject) => {
     waitForClipboard(data => !!data, aPopulateClipboardFn, resolve, reject, aFlavor);
   });
 }
 
-/**
- * Waits for all pending async statements on the default connection, before
- * proceeding with aCallback.
- *
- * @param aCallback
- *        Function to be called when done.
- * @param aScope
- *        Scope for the callback.
- * @param aArguments
- *        Arguments array for the callback.
- *
- * @note The result is achieved by asynchronously executing a query requiring
- *       a write lock.  Since all statements on the same connection are
- *       serialized, the end of this write operation means that all writes are
- *       complete.  Note that WAL makes so that writers don't block readers, but
- *       this is a problem only across different connections.
- */
-function waitForAsyncUpdates(aCallback, aScope, aArguments) {
-  let scope = aScope || this;
-  let args = aArguments || [];
-  let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                              .DBConnection;
-  let begin = db.createAsyncStatement("BEGIN EXCLUSIVE");
-  begin.executeAsync();
-  begin.finalize();
-
-  let commit = db.createAsyncStatement("COMMIT");
-  commit.executeAsync({
-    handleResult() {},
-    handleError() {},
-    handleCompletion(aReason) {
-      aCallback.apply(scope, args);
-    }
-  });
-  commit.finalize();
-}
-
 function synthesizeClickOnSelectedTreeCell(aTree, aOptions) {
   let tbo = aTree.treeBoxObject;
   if (tbo.view.selection.count != 1)
      throw new Error("The test node should be successfully selected");
   // Get selection rowID.
   let min = {}, max = {};
   tbo.view.selection.getRangeAt(0, min, max);
   let rowID = min.value;
--- a/browser/modules/Sanitizer.jsm
+++ b/browser/modules/Sanitizer.jsm
@@ -235,20 +235,17 @@ var Sanitizer = {
     let promise = sanitizeInternal(this.items, itemsToClear, progress, options);
 
     // Depending on preferences, the sanitizer may perform asynchronous
     // work before it starts cleaning up the Places database (e.g. closing
     // windows). We need to make sure that the connection to that database
     // hasn't been closed by the time we use it.
     // Though, if this is a sanitize on shutdown, we already have a blocker.
     if (!progress.isShutdown) {
-      let shutdownClient = Cc["@mozilla.org/browser/nav-history-service;1"]
-                             .getService(Ci.nsPIPlacesDatabase)
-                             .shutdownClient
-                             .jsclient;
+      let shutdownClient = PlacesUtils.history.shutdownClient.jsclient;
       shutdownClient.addBlocker("sanitize.js: Sanitize",
         promise,
         {
           fetchState: () => ({ progress })
         }
       );
     }
 
--- a/browser/modules/WindowsJumpLists.jsm
+++ b/browser/modules/WindowsJumpLists.jsm
@@ -387,18 +387,17 @@ var WinTaskbarJumpList =
   _getHistoryResults:
   function WTBLJL__getHistoryResults(aSortingMode, aLimit, aCallback, aScope) {
     var options = PlacesUtils.history.getNewQueryOptions();
     options.maxResults = aLimit;
     options.sortingMode = aSortingMode;
     var query = PlacesUtils.history.getNewQuery();
 
     // Return the pending statement to the caller, to allow cancelation.
-    return PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                              .asyncExecuteLegacyQuery(query, options, {
+    return PlacesUtils.history.asyncExecuteLegacyQuery(query, options, {
       handleResult(aResultSet) {
         for (let row; (row = aResultSet.getNextRow());) {
           try {
             aCallback.call(aScope,
                            { uri: row.getResultByIndex(1),
                              title: row.getResultByIndex(2)
                            });
           } catch (e) {}
--- a/toolkit/components/places/PlacesUtils.jsm
+++ b/toolkit/components/places/PlacesUtils.jsm
@@ -1847,18 +1847,17 @@ var PlacesUtils = {
     }
 
     return rootItem;
   }
 };
 
 XPCOMUtils.defineLazyGetter(PlacesUtils, "history", function() {
   let hs = Cc["@mozilla.org/browser/nav-history-service;1"]
-             .getService(Ci.nsINavHistoryService)
-             .QueryInterface(Ci.nsPIPlacesDatabase);
+             .getService(Ci.nsINavHistoryService);
   return Object.freeze(new Proxy(hs, {
     get(target, name) {
       let property, object;
       if (name in target) {
         property = target[name];
         object = target;
       } else {
         property = History[name];
--- a/toolkit/components/places/Shutdown.h
+++ b/toolkit/components/places/Shutdown.h
@@ -23,23 +23,23 @@ class Database;
  * that forwards the notification to the Database instance).
  * Database::Observe first of all checks if initialization was completed
  * properly, to avoid race conditions, then it notifies "places-shutdown" to
  * legacy clients. Legacy clients are supposed to start and complete any
  * shutdown critical work in the same tick, since we won't wait for them.
 
  * PHASE 2 (Modern clients shutdown)
  * Modern clients should instead register as a blocker by passing a promise to
- * nsPIPlacesDatabase::shutdownClient (for example see Sanitizer.jsm), so they
+ * nsINavHistoryService::shutdownClient (for example see Sanitizer.jsm), so they
  * block Places shutdown until the promise is resolved.
  * When profile-change-teardown is observed by async shutdown, it calls
  * ClientsShutdownBlocker::BlockShutdown. This class is registered as a teardown
  * phase blocker in Database::Init (see Database::mClientsShutdown).
  * ClientsShutdownBlocker::BlockShudown waits for all the clients registered
- * through nsPIPlacesDatabase::shutdownClient. When all the clients are done,
+ * through nsINavHistoryService::shutdownClient. When all the clients are done,
  * its `Done` method is invoked, and it stops blocking the shutdown phase, so
  * that it can continue.
  *
  * PHASE 3 (Connection shutdown)
  * ConnectionBlocker is registered as a profile-before-change blocker in
  * Database::Init (see Database::mConnectionShutdown).
  * When profile-before-change is observer by async shutdown, it calls
  * ConnectionShutdownBlocker::BlockShutdown.
--- a/toolkit/components/places/moz.build
+++ b/toolkit/components/places/moz.build
@@ -20,17 +20,16 @@ if CONFIG['MOZ_PLACES']:
         'mozIAsyncLivemarks.idl',
         'mozIColorAnalyzer.idl',
         'mozIPlacesAutoComplete.idl',
         'mozIPlacesPendingOperation.idl',
         'nsIAnnotationService.idl',
         'nsIFaviconService.idl',
         'nsINavBookmarksService.idl',
         'nsITaggingService.idl',
-        'nsPIPlacesDatabase.idl',
     ]
 
     EXPORTS.mozilla.places = [
         'Database.h',
         'History.h',
         'Shutdown.h',
     ]
 
--- a/toolkit/components/places/nsINavHistoryService.idl
+++ b/toolkit/components/places/nsINavHistoryService.idl
@@ -11,16 +11,21 @@
 
 #include "nsISupports.idl"
 
 interface nsIArray;
 interface nsIURI;
 interface nsIVariant;
 interface nsIFile;
 
+interface mozIStorageConnection;
+interface mozIStorageStatementCallback;
+interface mozIStoragePendingStatement;
+interface nsIAsyncShutdownClient;
+
 interface nsINavHistoryContainerResultNode;
 interface nsINavHistoryQueryResultNode;
 interface nsINavHistoryQuery;
 interface nsINavHistoryQueryOptions;
 interface nsINavHistoryResult;
 interface nsINavHistoryBatchCallback;
 
 /**
@@ -619,19 +624,16 @@ interface nsINavHistoryResult : nsISuppo
    * observing changes, so it is good practice to close the root node when you
    * are done with a result, since that will avoid unwanted performance hits.
    */
   readonly attribute nsINavHistoryContainerResultNode root;
 };
 
 
 /**
- * Similar to nsIRDFObserver for history. Note that we don't pass the data
- * source since that is always the global history.
- *
  * DANGER! If you are in the middle of a batch transaction, there may be a
  * database transaction active. You can still access the DB, but be careful.
  */
 [scriptable, uuid(0f0f45b0-13a1-44ae-a0ab-c6046ec6d4da)]
 interface nsINavHistoryObserver : nsISupports
 {
   /**
    * Notifies you that a bunch of things are about to change, don't do any
@@ -1381,9 +1383,45 @@ interface nsINavHistoryService : nsISupp
    * Returns a 48-bit hash for a URI spec.
    *
    * @param aSpec
    *        The URI spec to hash.
    * @param aMode
    *        The hash mode: `""` (default), `"prefix_lo"`, or `"prefix_hi"`.
    */
   unsigned long long hashURL(in ACString aSpec, [optional] in ACString aMode);
+
+  /**
+   * The database connection used by Places.
+   */
+  readonly attribute mozIStorageConnection DBConnection;
+
+  /**
+   * Asynchronously executes the statement created from a query.
+   *
+   * @see nsINavHistoryService::executeQuery
+   * @note THIS IS A TEMPORARY API.  Don't rely on it, since it will be replaced
+   *       in future versions by a real async querying API.
+   * @note Results obtained from this method differ from results obtained from
+   *       executeQuery, because there is additional filtering and sorting
+   *       done by the latter.  Thus you should use executeQuery, unless you
+   *       are absolutely sure that the returned results are fine for
+   *       your use-case.
+   */
+  mozIStoragePendingStatement asyncExecuteLegacyQuery(
+    in nsINavHistoryQuery aQuery,
+    in nsINavHistoryQueryOptions aOptions,
+    in mozIStorageStatementCallback aCallback);
+
+  /**
+   * Hook for clients who need to perform actions during/by the end of
+   * the shutdown of the database.
+   * May be null if it's too late to get one.
+   */
+  readonly attribute nsIAsyncShutdownClient shutdownClient;
+
+  /**
+   * Hook for internal clients who need to perform actions just before the
+   * connection gets closed.
+   * May be null if it's too late to get one.
+   */
+  readonly attribute nsIAsyncShutdownClient connectionShutdownClient;
 };
--- a/toolkit/components/places/nsNavHistory.cpp
+++ b/toolkit/components/places/nsNavHistory.cpp
@@ -174,17 +174,16 @@ NS_IMPL_ADDREF(nsNavHistory)
 NS_IMPL_RELEASE(nsNavHistory)
 
 NS_IMPL_CLASSINFO(nsNavHistory, nullptr, nsIClassInfo::SINGLETON,
                   NS_NAVHISTORYSERVICE_CID)
 NS_INTERFACE_MAP_BEGIN(nsNavHistory)
   NS_INTERFACE_MAP_ENTRY(nsINavHistoryService)
   NS_INTERFACE_MAP_ENTRY(nsIObserver)
   NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
-  NS_INTERFACE_MAP_ENTRY(nsPIPlacesDatabase)
   NS_INTERFACE_MAP_ENTRY(mozIStorageVacuumParticipant)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsINavHistoryService)
   NS_IMPL_QUERY_CLASSINFO(nsNavHistory)
 NS_INTERFACE_MAP_END
 
 // We don't care about flattening everything
 NS_IMPL_CI_INTERFACE_GETTER(nsNavHistory,
                             nsINavHistoryService)
@@ -2264,20 +2263,16 @@ nsNavHistory::OnBeginVacuum(bool* _vacuu
 
 NS_IMETHODIMP
 nsNavHistory::OnEndVacuum(bool aSucceeded)
 {
   NS_WARNING_ASSERTION(aSucceeded, "Places.sqlite vacuum failed.");
   return NS_OK;
 }
 
-
-////////////////////////////////////////////////////////////////////////////////
-//// nsPIPlacesDatabase
-
 NS_IMETHODIMP
 nsNavHistory::GetDBConnection(mozIStorageConnection **_DBConnection)
 {
   NS_ENSURE_ARG_POINTER(_DBConnection);
   nsCOMPtr<mozIStorageConnection> connection = mDB->MainConn();
   connection.forget(_DBConnection);
 
   return NS_OK;
--- a/toolkit/components/places/nsNavHistory.h
+++ b/toolkit/components/places/nsNavHistory.h
@@ -2,17 +2,16 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef nsNavHistory_h_
 #define nsNavHistory_h_
 
 #include "nsINavHistoryService.h"
-#include "nsPIPlacesDatabase.h"
 #include "nsINavBookmarksService.h"
 #include "nsIFaviconService.h"
 #include "nsIGlobalHistory2.h"
 
 #include "nsIObserverService.h"
 #include "nsICollation.h"
 #include "nsIStringBundle.h"
 #include "nsITimer.h"
@@ -73,28 +72,26 @@ class nsIIDNService;
 class PlacesSQLQueryBuilder;
 class nsIAutoCompleteController;
 
 // nsNavHistory
 
 class nsNavHistory final : public nsSupportsWeakReference
                          , public nsINavHistoryService
                          , public nsIObserver
-                         , public nsPIPlacesDatabase
                          , public mozIStorageVacuumParticipant
 {
   friend class PlacesSQLQueryBuilder;
 
 public:
   nsNavHistory();
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSINAVHISTORYSERVICE
   NS_DECL_NSIOBSERVER
-  NS_DECL_NSPIPLACESDATABASE
   NS_DECL_MOZISTORAGEVACUUMPARTICIPANT
 
   /**
    * Obtains the nsNavHistory object.
    */
   static already_AddRefed<nsNavHistory> GetSingleton();
 
   /**
deleted file mode 100644
--- a/toolkit/components/places/nsPIPlacesDatabase.idl
+++ /dev/null
@@ -1,59 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
- * vim: sw=2 ts=2 sts=2
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
-
-#include "nsISupports.idl"
-
-interface mozIStorageConnection;
-interface nsINavHistoryQuery;
-interface nsINavHistoryQueryOptions;
-interface mozIStorageStatementCallback;
-interface mozIStoragePendingStatement;
-interface nsIAsyncShutdownClient;
-
-/**
- * This is a private interface used by Places components to get access to the
- * database.  If outside consumers wish to use this, they should only read from
- * the database so they do not break any internal invariants.
- */
-[scriptable, uuid(366ee63e-a413-477d-9ad6-8d6863e89401)]
-interface nsPIPlacesDatabase : nsISupports
-{
-  /**
-   * The database connection used by Places.
-   */
-  readonly attribute mozIStorageConnection DBConnection;
-
-  /**
-   * Asynchronously executes the statement created from a query.
-   *
-   * @see nsINavHistoryService::executeQuery
-   * @note THIS IS A TEMPORARY API.  Don't rely on it, since it will be replaced
-   *       in future versions by a real async querying API.
-   * @note Results obtained from this method differ from results obtained from
-   *       executeQuery, because there is additional filtering and sorting
-   *       done by the latter.  Thus you should use executeQuery, unless you
-   *       are absolutely sure that the returned results are fine for
-   *       your use-case.
-   */
-  mozIStoragePendingStatement asyncExecuteLegacyQuery(
-    in nsINavHistoryQuery aQuery,
-    in nsINavHistoryQueryOptions aOptions,
-    in mozIStorageStatementCallback aCallback);
-
-  /**
-   * Hook for clients who need to perform actions during/by the end of
-   * the shutdown of the database.
-   * May be null if it's too late to get one.
-   */
-  readonly attribute nsIAsyncShutdownClient shutdownClient;
-
-  /**
-   * Hook for internal clients who need to perform actions just before the
-   * connection gets closed.
-   * May be null if it's too late to get one.
-   */
-  readonly attribute nsIAsyncShutdownClient connectionShutdownClient;
-};
--- a/toolkit/components/places/nsPlacesExpiration.js
+++ b/toolkit/components/places/nsPlacesExpiration.js
@@ -385,19 +385,17 @@ function notify(observers, notification,
 }
 
 // nsPlacesExpiration definition
 
 function nsPlacesExpiration() {
   // Smart Getters
 
   XPCOMUtils.defineLazyGetter(this, "_db", function() {
-    let db = Cc["@mozilla.org/browser/nav-history-service;1"].
-             getService(Ci.nsPIPlacesDatabase).
-             DBConnection;
+    let db = PlacesUtils.history.DBConnection;
 
     // Create the temporary notifications table.
     let stmt = db.createAsyncStatement(
       `CREATE TEMP TABLE expiration_notify (
          id INTEGER PRIMARY KEY
        , v_id INTEGER
        , p_id INTEGER
        , url TEXT NOT NULL
--- a/toolkit/components/places/nsTaggingService.js
+++ b/toolkit/components/places/nsTaggingService.js
@@ -53,18 +53,17 @@ TaggingService.prototype = {
    *          otherwise.
    */
   _getItemIdForTaggedURI: function TS__getItemIdForTaggedURI(aURI, aTagName) {
     var tagId = this._getItemIdForTag(aTagName);
     if (tagId == -1)
       return -1;
     // Using bookmarks service API for this would be a pain.
     // Until tags implementation becomes sane, go the query way.
-    let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                                .DBConnection;
+    let db = PlacesUtils.history.DBConnection;
     let stmt = db.createStatement(
       `SELECT id FROM moz_bookmarks
        WHERE parent = :tag_id
        AND fk = (SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url)`
     );
     stmt.params.tag_id = tagId;
     stmt.params.page_url = aURI.spec;
     try {
@@ -173,18 +172,17 @@ TaggingService.prototype = {
    *
    * @param aTagId
    *        the itemId of the tag element under the tags root
    * @param aSource
    *        a change source constant from nsINavBookmarksService::SOURCE_*
    */
   _removeTagIfEmpty: function TS__removeTagIfEmpty(aTagId, aSource) {
     let count = 0;
-    let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                                .DBConnection;
+    let db = PlacesUtils.history.DBConnection;
     let stmt = db.createStatement(
       `SELECT count(*) AS count FROM moz_bookmarks
        WHERE parent = :tag_id`
     );
     stmt.params.tag_id = aTagId;
     try {
       if (stmt.executeStep()) {
         count = stmt.row.count;
@@ -242,18 +240,17 @@ TaggingService.prototype = {
                                  Cr.NS_ERROR_INVALID_ARG);
     }
 
     let uris = [];
     let tagId = this._getItemIdForTag(aTagName);
     if (tagId == -1)
       return uris;
 
-    let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                                .DBConnection;
+    let db = PlacesUtils.history.DBConnection;
     let stmt = db.createStatement(
       `SELECT h.url FROM moz_places h
        JOIN moz_bookmarks b ON b.fk = h.id
        WHERE b.parent = :tag_id`
     );
     stmt.params.tag_id = tagId;
     try {
       while (stmt.executeStep()) {
@@ -306,18 +303,17 @@ TaggingService.prototype = {
     return tags;
   },
 
   __tagFolders: null,
   get _tagFolders() {
     if (!this.__tagFolders) {
       this.__tagFolders = [];
 
-      let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                                  .DBConnection;
+      let db = PlacesUtils.history.DBConnection;
       let stmt = db.createStatement(
         "SELECT id, title FROM moz_bookmarks WHERE parent = :tags_root "
       );
       stmt.params.tags_root = PlacesUtils.tagsFolderId;
       try {
         while (stmt.executeStep()) {
           this.__tagFolders[stmt.row.id] = stmt.row.title;
         }
@@ -367,18 +363,17 @@ TaggingService.prototype = {
    */
   _getTaggedItemIdsIfUnbookmarkedURI:
   function TS__getTaggedItemIdsIfUnbookmarkedURI(aURI) {
     var itemIds = [];
     var isBookmarked = false;
 
     // Using bookmarks service API for this would be a pain.
     // Until tags implementation becomes sane, go the query way.
-    let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                                .DBConnection;
+    let db = PlacesUtils.history.DBConnection;
     let stmt = db.createStatement(
       `SELECT id, parent
        FROM moz_bookmarks
        WHERE fk = (SELECT id FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url)`
     );
     stmt.params.page_url = aURI.spec;
     try {
       while (stmt.executeStep() && !isBookmarked) {
--- a/toolkit/components/places/tests/bookmarks/test_448584.js
+++ b/toolkit/components/places/tests/bookmarks/test_448584.js
@@ -1,18 +1,17 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
 /* vim:set ts=2 sw=2 sts=2 et: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 // Get database connection
 try {
-  var mDBConn = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                                   .DBConnection;
+  var mDBConn = PlacesUtils.history.DBConnection;
 } catch (ex) {
   do_throw("Could not get database connection\n");
 }
 
 /*
   This test is:
     - don't try to add invalid uri nodes to a JSON backup
 */
--- a/toolkit/components/places/tests/browser/browser_settitle.js
+++ b/toolkit/components/places/tests/browser/browser_settitle.js
@@ -1,9 +1,9 @@
-var conn = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
+var conn = PlacesUtils.history.DBConnection;
 
 /**
  * Gets a single column value from either the places or historyvisits table.
  */
 function getColumn(table, column, url) {
   var stmt = conn.createStatement(
     `SELECT ${column} FROM ${table} WHERE url_hash = hash(:val) AND url = :val`);
   try {
--- a/toolkit/components/places/tests/browser/browser_visituri.js
+++ b/toolkit/components/places/tests/browser/browser_visituri.js
@@ -7,17 +7,17 @@ function promiseObserve(name, checkFn) {
       if (checkFn(subject)) {
         Services.obs.removeObserver(observer, name);
         resolve();
       }
     }, name);
   });
 }
 
-var conn = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
+var conn = PlacesUtils.history.DBConnection;
 
 /**
  * Gets a single column value from either the places or historyvisits table.
  */
 function getColumn(table, column, fromColumnName, fromColumnValue) {
   let sql = `SELECT ${column}
              FROM ${table}
              WHERE ${fromColumnName} = :val
--- a/toolkit/components/places/tests/browser/head.js
+++ b/toolkit/components/places/tests/browser/head.js
@@ -22,18 +22,17 @@ const TRANSITION_DOWNLOAD = PlacesUtils.
  *        The URI or spec to get field for.
  * @param {String} aFieldName
  *        The field name to get the value of.
  * @param {Function} aCallback
  *        Callback function that will get the property value.
  */
 function fieldForUrl(aURI, aFieldName, aCallback) {
   let url = aURI instanceof Ci.nsIURI ? aURI.spec : aURI;
-  let stmt = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                                .DBConnection.createAsyncStatement(
+  let stmt = PlacesUtils.history.DBConnection.createAsyncStatement(
     `SELECT ${aFieldName} FROM moz_places WHERE url_hash = hash(:page_url) AND url = :page_url`
   );
   stmt.params.page_url = url;
   stmt.executeAsync({
     _value: -1,
     handleResult(aResultSet) {
       let row = aResultSet.getNextRow();
       if (!row)
--- a/toolkit/components/places/tests/gtest/places_test_harness.h
+++ b/toolkit/components/places/tests/gtest/places_test_harness.h
@@ -15,17 +15,16 @@
 #include "nsIObserverService.h"
 #include "nsIURI.h"
 #include "mozilla/IHistory.h"
 #include "mozIStorageConnection.h"
 #include "mozIStorageStatement.h"
 #include "mozIStorageAsyncStatement.h"
 #include "mozIStorageStatementCallback.h"
 #include "mozIStoragePendingStatement.h"
-#include "nsPIPlacesDatabase.h"
 #include "nsIObserver.h"
 #include "prinrval.h"
 #include "prtime.h"
 #include "mozilla/Attributes.h"
 
 #define WAITFORTOPIC_TIMEOUT_SECONDS 5
 
 
@@ -213,21 +212,20 @@ do_get_NavHistory()
   do_check_true(serv);
   return serv.forget();
 }
 
 already_AddRefed<mozIStorageConnection>
 do_get_db()
 {
   nsCOMPtr<nsINavHistoryService> history = do_get_NavHistory();
-  nsCOMPtr<nsPIPlacesDatabase> database = do_QueryInterface(history);
-  do_check_true(database);
+  do_check_true(history);
 
   nsCOMPtr<mozIStorageConnection> dbConn;
-  nsresult rv = database->GetDBConnection(getter_AddRefs(dbConn));
+  nsresult rv = history->GetDBConnection(getter_AddRefs(dbConn));
   do_check_success(rv);
   return dbConn.forget();
 }
 
 /**
  * Get the place record from the database.
  *
  * @param aURI The unique URI of the place we are looking up
--- a/toolkit/components/places/tests/head_common.js
+++ b/toolkit/components/places/tests/head_common.js
@@ -92,18 +92,17 @@ function uri(aSpec) {
  *        connection is asyncClosed it cannot anymore schedule async statements,
  *        though connectionReady will keep returning true (Bug 726990).
  *
  * @return The database connection or null if unable to get one.
  */
 var gDBConn;
 function DBConn(aForceNewConnection) {
   if (!aForceNewConnection) {
-    let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                                .DBConnection;
+    let db = PlacesUtils.history.DBConnection;
     if (db.connectionReady)
       return db;
   }
 
   // If the Places database connection has been closed, create a new connection.
   if (!gDBConn || aForceNewConnection) {
     let file = Services.dirsvc.get("ProfD", Ci.nsIFile);
     file.append("places.sqlite");
--- a/toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js
+++ b/toolkit/components/places/tests/unit/test_asyncExecuteLegacyQueries.js
@@ -9,18 +9,17 @@ add_task(async function test_history_que
   let title = "Test visit";
   await PlacesTestUtils.addVisits({ uri, title });
 
   let options = PlacesUtils.history.getNewQueryOptions();
   options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_DATE_DESCENDING;
   let query = PlacesUtils.history.getNewQuery();
 
   return new Promise(resolve => {
-    PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                       .asyncExecuteLegacyQuery(query, options, {
+    PlacesUtils.history.asyncExecuteLegacyQuery(query, options, {
       handleResult(aResultSet) {
         for (let row; (row = aResultSet.getNextRow());) {
           try {
             Assert.equal(row.getResultByIndex(1), uri);
             Assert.equal(row.getResultByIndex(2), title);
           } catch (e) {
             do_throw("Error while fetching page data.");
           }
@@ -46,18 +45,17 @@ add_task(async function test_bookmarks_q
   });
 
   let options = PlacesUtils.history.getNewQueryOptions();
   options.sortingMode = Ci.nsINavHistoryQueryOptions.SORT_BY_LASMODIFIED_DESCENDING;
   options.queryType = options.QUERY_TYPE_BOOKMARKS;
   let query = PlacesUtils.history.getNewQuery();
 
   return new Promise(resolve => {
-    PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase)
-                       .asyncExecuteLegacyQuery(query, options, {
+    PlacesUtils.history.asyncExecuteLegacyQuery(query, options, {
       handleResult(aResultSet) {
         for (let row; (row = aResultSet.getNextRow());) {
           try {
             Assert.equal(row.getResultByIndex(1), url);
             Assert.equal(row.getResultByIndex(2), title);
           } catch (e) {
             do_throw("Error while fetching page data.");
           }
--- a/toolkit/components/places/tests/unit/test_history.js
+++ b/toolkit/components/places/tests/unit/test_history.js
@@ -144,17 +144,17 @@ add_task(async function test_execute() {
   let placeInfo = await PlacesUtils.history.fetch("http://example.com");
   Assert.equal(placeInfo.title, "title");
 
   // query for the visit
   Assert.ok(uri_in_db(testURI));
 
   // test for schema changes in bug 373239
   // get direct db connection
-  var db = histsvc.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
+  var db = histsvc.DBConnection;
   var q = "SELECT id FROM moz_bookmarks";
   var statement;
   try {
      statement = db.createStatement(q);
   } catch (ex) {
     do_throw("bookmarks table does not have id field, schema is too old!");
   } finally {
     statement.finalize();
--- a/toolkit/components/places/tests/unit/test_preventive_maintenance.js
+++ b/toolkit/components/places/tests/unit/test_preventive_maintenance.js
@@ -15,17 +15,17 @@ ChromeUtils.import("resource://gre/modul
 
 // Get services and database connection
 var hs = PlacesUtils.history;
 var bs = PlacesUtils.bookmarks;
 var ts = PlacesUtils.tagging;
 var as = PlacesUtils.annotations;
 var fs = PlacesUtils.favicons;
 
-var mDBConn = hs.QueryInterface(Ci.nsPIPlacesDatabase).DBConnection;
+var mDBConn = hs.DBConnection;
 
 // ------------------------------------------------------------------------------
 // Helpers
 
 var defaultBookmarksMaxId = 0;
 async function cleanDatabase() {
   // First clear any bookmarks the "proper way" to ensure caches like GuidHelper
   // are properly cleared.
--- a/toolkit/modules/NewTabUtils.jsm
+++ b/toolkit/modules/NewTabUtils.jsm
@@ -611,18 +611,17 @@ var PlacesProvider = {
         }
 
         aCallback(links);
       }
     };
 
     // Execute the query.
     let query = PlacesUtils.history.getNewQuery();
-    let db = PlacesUtils.history.QueryInterface(Ci.nsPIPlacesDatabase);
-    db.asyncExecuteLegacyQuery(query, options, callback);
+    PlacesUtils.history.asyncExecuteLegacyQuery(query, options, callback);
   },
 
   /**
    * Registers an object that will be notified when the provider's links change.
    * @param aObserver An object with the following optional properties:
    *        * onLinkChanged: A function that's called when a single link
    *          changes.  It's passed the provider and the link object.  Only the
    *          link's `url` property is guaranteed to be present.  If its `title`