Bug 1310525 - don't exceed sqlite's max variable limit when many changed bookmarks exist. r?kitcambridge draft
authorMark Hammond <mhammond@skippinet.com.au>
Mon, 17 Oct 2016 12:54:05 +1100
changeset 426172 d4d637d189ea1decddac3b9a3cd302a56074c433
parent 425707 ae1647268be172630ca5af36c469323c14fc98c4
child 534117 308fd8cb911862a7736c0207d727a550b8b48fd0
push id32642
push userbmo:markh@mozilla.com
push dateTue, 18 Oct 2016 01:15:12 +0000
reviewerskitcambridge
bugs1310525
milestone52.0a1
Bug 1310525 - don't exceed sqlite's max variable limit when many changed bookmarks exist. r?kitcambridge MozReview-Commit-ID: H2l2L9fZm9t
services/sync/modules/engines/bookmarks.js
services/sync/tests/unit/test_bookmark_tracker.js
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -544,18 +544,18 @@ BookmarksEngine.prototype = {
 
     // Filter out tags, organizer queries, and other descendants that we're
     // not tracking. We chunk `modifiedGUIDs` because SQLite limits the number
     // of bound parameters per query.
     for (let startIndex = 0;
          startIndex < modifiedGUIDs.length;
          startIndex += SQLITE_MAX_VARIABLE_NUMBER) {
 
-      let chunkLength = Math.min(startIndex + SQLITE_MAX_VARIABLE_NUMBER,
-                                 modifiedGUIDs.length);
+      let chunkLength = Math.min(SQLITE_MAX_VARIABLE_NUMBER,
+                                 modifiedGUIDs.length - startIndex);
 
       let query = `
         WITH RECURSIVE
         modifiedGuids(guid) AS (
           VALUES ${new Array(chunkLength).fill("(?)").join(", ")}
         ),
         syncedItems(id) AS (
           VALUES ${getChangeRootIds().map(id => `(${id})`).join(", ")}
--- a/services/sync/tests/unit/test_bookmark_tracker.js
+++ b/services/sync/tests/unit/test_bookmark_tracker.js
@@ -176,16 +176,43 @@ add_task(function* test_nested_batch_tra
   }, null);
 
   // Out of both batches - tracker should be the same, but score should be up.
   yield verifyTrackedCount(2);
   do_check_eq(tracker.score, SCORE_INCREMENT_XLARGE);
   yield cleanup();
 });
 
+add_task(function* test_tracker_sql_batching() {
+  _("Test tracker does the correct thing when it is forced to batch SQL queries");
+
+  const SQLITE_MAX_VARIABLE_NUMBER = 999;
+  let numItems = SQLITE_MAX_VARIABLE_NUMBER * 2 + 10;
+  let createdIDs = [];
+
+  yield startTracking();
+
+  PlacesUtils.bookmarks.runInBatchMode({
+    runBatched: function() {
+      for (let i = 0; i < numItems; i++) {
+        let syncBmkID = PlacesUtils.bookmarks.insertBookmark(
+                          PlacesUtils.bookmarks.unfiledBookmarksFolder,
+                          Utils.makeURI("https://example.org/" + i),
+                          PlacesUtils.bookmarks.DEFAULT_INDEX,
+                          "Sync Bookmark " + i);
+        createdIDs.push(syncBmkID);
+      }
+    }
+  }, null);
+
+  do_check_eq(createdIDs.length, numItems);
+  yield verifyTrackedCount(numItems + 1); // the folder is also tracked.
+  yield cleanup();
+});
+
 add_task(function* test_onItemAdded() {
   _("Items inserted via the synchronous bookmarks API should be tracked");
 
   try {
     yield startTracking();
 
     _("Insert a folder using the sync API");
     let syncFolderID = PlacesUtils.bookmarks.createFolder(