Bug 1458910 - Merge nsPIPlacesDatabase into nsINavHistoryService. r=standard8
authorMarco Bonardo <mbonardo@mozilla.com>
Thu, 10 May 2018 10:39:12 +0200
changeset 417872 95505a218c83a4d4a21c9b7aa460cbb392b3bc79
parent 417871 8e9a4a323f0cfce20c7fae76d15c252693a65536
child 417873 8e3a5591905b44021bd2d4ff28b8ce2e46b1ab97
push id63864
push usermak77@bonardo.net
push dateFri, 11 May 2018 07:56:40 +0000
treeherderautoland@95505a218c83 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersstandard8
bugs1458910
milestone62.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 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
@@ -396,18 +396,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
@@ -1846,18 +1846,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`