Bug 1392070 - Stop using the StopIteration object in Sqlite.jsm. r=mak
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Sat, 19 Aug 2017 22:10:44 +0900
changeset 376111 b9ae810f6a04a621e35cc06bd6b357560bf2f42f
parent 376110 7f1d159041a2736260fcb1c8fdd026e5506244b9
child 376114 50011d4e73fa704b42590bf9bcd6892a2fd35af0
push id49315
push userVYV03354@nifty.ne.jp
push dateTue, 22 Aug 2017 12:23:52 +0000
treeherderautoland@b9ae810f6a04 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak
bugs1392070
milestone57.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 1392070 - Stop using the StopIteration object in Sqlite.jsm. r=mak MozReview-Commit-ID: BP3RuM5EweE
toolkit/components/places/PlacesDBUtils.jsm
toolkit/components/places/UnifiedComplete.js
toolkit/modules/NewTabUtils.jsm
toolkit/modules/Sqlite.jsm
toolkit/modules/tests/xpcshell/test_sqlite.js
--- a/toolkit/components/places/PlacesDBUtils.jsm
+++ b/toolkit/components/places/PlacesDBUtils.jsm
@@ -166,19 +166,19 @@ this.PlacesDBUtils = {
 
     try {
       // Run a integrity check, but stop at the first error.
       await PlacesUtils.withConnectionWrapper("PlacesDBUtils: check the integrity", async (db) => {
         let row;
         await db.execute(
           "PRAGMA integrity_check",
           null,
-          r => {
+          (r, cancel) => {
             row = r;
-            throw StopIteration;
+            cancel();
           });
         if (row.getResultByIndex(0) === "ok") {
           logs.push("The database is sane");
         } else {
           // We stopped due to an integrity corruption, try to fix if possible.
           logs.push("The database is corrupt");
           if (skipReindex) {
             Services.prefs.setBoolPref("places.database.replaceOnStartup", true);
--- a/toolkit/components/places/UnifiedComplete.js
+++ b/toolkit/components/places/UnifiedComplete.js
@@ -1694,17 +1694,17 @@ Search.prototype = {
         (this._trimmedOriginalSearchString.endsWith("/") || uri.pathQueryRef.length > 1)) {
       match.icon = `page-icon:${uri.prePath}/`;
     }
 
     this._addMatch(match);
     return true;
   },
 
-  _onResultRow(row) {
+  _onResultRow(row, cancel) {
     if (this._counts[MATCHTYPE.GENERAL] == 0) {
       TelemetryStopwatch.finish(TELEMETRY_1ST_RESULT, this);
     }
     let queryType = row.getResultByIndex(QUERYINDEX_QUERYTYPE);
     let match;
     switch (queryType) {
       case QUERYTYPE_AUTOFILL_HOST:
         this._result.setDefaultIndex(0);
@@ -1717,17 +1717,17 @@ Search.prototype = {
       case QUERYTYPE_FILTERED:
         match = this._processRow(row);
         break;
     }
     this._addMatch(match);
     // If the search has been canceled by the user or by _addMatch, or we
     // fetched enough results, we can stop the underlying Sqlite query.
     if (!this.pending || this._counts[MATCHTYPE.GENERAL] == Prefs.get("maxRichResults"))
-      throw StopIteration;
+      cancel();
   },
 
   _maybeRestyleSearchMatch(match) {
     // Return if the URL does not represent a search result.
     let parseResult =
       PlacesSearchAutocompleteProvider.parseSubmissionURL(match.value);
     if (!parseResult) {
       return;
--- a/toolkit/modules/NewTabUtils.jsm
+++ b/toolkit/modules/NewTabUtils.jsm
@@ -1077,17 +1077,17 @@ var ActivityStreamProvider = {
    *
    * @returns {Promise} Returns a promise with the array of retrieved items
    */
   async executePlacesQuery(aQuery, aOptions = {}) {
     let {columns, params} = aOptions;
     let items = [];
     let queryError = null;
     let conn = await PlacesUtils.promiseDBConnection();
-    await conn.executeCached(aQuery, params, aRow => {
+    await conn.executeCached(aQuery, params, (aRow, aCancel) => {
       try {
         let item = null;
         // if columns array is given construct an object
         if (columns && Array.isArray(columns)) {
           item = {};
           columns.forEach(column => {
             item[column] = aRow.getResultByName(column);
           });
@@ -1096,17 +1096,17 @@ var ActivityStreamProvider = {
           item = [];
           for (let i = 0; i < aRow.numEntries; i++) {
             item.push(aRow.getResultByIndex(i));
           }
         }
         items.push(item);
       } catch (e) {
         queryError = e;
-        throw StopIteration;
+        aCancel();
       }
     });
     if (queryError) {
       throw new Error(queryError);
     }
     return items;
   }
 };
--- a/toolkit/modules/Sqlite.jsm
+++ b/toolkit/modules/Sqlite.jsm
@@ -766,24 +766,21 @@ ConnectionData.prototype = Object.freeze
           if (!onRow) {
             rows.push(row);
             continue;
           }
 
           handledRow = true;
 
           try {
-            onRow(row);
-          } catch (e) {
-            if (e instanceof StopIteration) {
+            onRow(row, () => {
               userCancelled = true;
               pending.cancel();
-              break;
-            }
-
+            });
+          } catch (e) {
             self._log.warn("Exception when calling onRow callback", e);
           }
         }
       },
 
       handleError(error) {
         self._log.info("Error when executing SQL (" +
                        error.result + "): " + error.message);
@@ -1278,24 +1275,24 @@ OpenedConnection.prototype = Object.free
    * no effect because no rows are returned from these. However, it has
    * implications for SELECT statements.
    *
    * If your SELECT statement could return many rows or rows with large amounts
    * of data, for performance reasons it is recommended to pass an `onRow`
    * handler. Otherwise, the buffering may consume unacceptable amounts of
    * resources.
    *
-   * If a `StopIteration` is thrown during execution of an `onRow` handler,
-   * the execution of the statement is immediately cancelled. Subsequent
-   * rows will not be processed and no more `onRow` invocations will be made.
-   * The promise is resolved immediately.
+   * If the second parameter of an `onRow` handler is called during execution
+   * of the `onRow` handler, the execution of the statement is immediately
+   * cancelled. Subsequent rows will not be processed and no more `onRow`
+   * invocations will be made. The promise is resolved immediately.
    *
-   * If a non-`StopIteration` exception is thrown by the `onRow` handler, the
-   * exception is logged and processing of subsequent rows occurs as if nothing
-   * happened. The promise is still resolved (not rejected).
+   * If an exception is thrown by the `onRow` handler, the exception is logged
+   * and processing of subsequent rows occurs as if nothing happened. The
+   * promise is still resolved (not rejected).
    *
    * The return value is a promise that will be resolved when the statement
    * has completed fully.
    *
    * The promise will be rejected with an `Error` instance if the statement
    * did not finish execution fully. The `Error` may have an `errors` property.
    * If defined, it will be an Array of objects describing individual errors.
    * Each object has the properties `result` and `message`. `result` is a
--- a/toolkit/modules/tests/xpcshell/test_sqlite.js
+++ b/toolkit/modules/tests/xpcshell/test_sqlite.js
@@ -306,21 +306,21 @@ add_task(async function test_on_row_stop
   let c = await getDummyDatabase("on_row_stop_iteration");
 
   let sql = "INSERT INTO dirs (path) VALUES (?)";
   for (let i = 0; i < 10; i++) {
     await c.executeCached(sql, ["dir" + i]);
   }
 
   let i = 0;
-  let hasResult = await c.execute("SELECT * FROM dirs", null, function onRow(row) {
+  let hasResult = await c.execute("SELECT * FROM dirs", null, function onRow(row, cancel) {
     i++;
 
     if (i == 5) {
-      throw StopIteration;
+      cancel();
     }
   });
 
   do_check_eq(hasResult, true);
   do_check_eq(i, 5);
 
   await c.close();
 });