Bug 616001 - Sync needs to check moz_places.guid and moz_bookmarks.guid if it exists. r=philikon
authorShawn Wilsher <me@shawnwilsher.com>
Tue, 14 Dec 2010 15:48:05 -0800
changeset 59277 63f426d891b7ae1260c14f9e4226696e64545301
parent 59276 a737306fde369a224f52d8b4935bed2fc810a1a0
child 59278 cddcf1e3cb80cca34e825b944b7589545975a45f
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
reviewersphilikon
bugs616001
Bug 616001 - Sync needs to check moz_places.guid and moz_bookmarks.guid if it exists. r=philikon Part 2 - Update bookmark engine.
services/sync/modules/engines/bookmarks.js
services/sync/modules/engines/history.js
--- a/services/sync/modules/engines/bookmarks.js
+++ b/services/sync/modules/engines/bookmarks.js
@@ -8,25 +8,26 @@
  *
  * 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 Bookmarks Sync.
  *
- * The Initial Developer of the Original Code is Mozilla.
+ * The Initial Developer of the Original Code is
+ * the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *  Dan Mills <thunder@mozilla.com>
- *  Jono DiCarlo <jdicarlo@mozilla.org>
- *  Anant Narayanan <anant@kix.in>
- *  Philipp von Weitershausen <philipp@weitershausen.de>
+ *   Dan Mills <thunder@mozilla.com>
+ *   Jono DiCarlo <jdicarlo@mozilla.org>
+ *   Anant Narayanan <anant@kix.in>
+ *   Philipp von Weitershausen <philipp@weitershausen.de>
  *
  * 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
@@ -831,16 +832,17 @@ BookmarksStore.prototype = {
   get _addGUIDAnnotationNameStm() {
     let stmt = this._getStmt(
       "INSERT OR IGNORE INTO moz_anno_attributes (name) VALUES (:anno_name)");
     stmt.params.anno_name = GUID_ANNO;
     return stmt;
   },
 
   get _checkGUIDItemAnnotationStm() {
+    // Gecko <2.0 only
     let stmt = this._getStmt(
       "SELECT b.id AS item_id, " +
         "(SELECT id FROM moz_anno_attributes WHERE name = :anno_name) AS name_id, " +
         "a.id AS anno_id, a.dateAdded AS anno_date " +
       "FROM moz_bookmarks b " +
       "LEFT JOIN moz_items_annos a ON a.item_id = b.id " +
                                  "AND a.anno_attribute_id = name_id " +
       "WHERE b.id = :item_id");
@@ -852,21 +854,51 @@ BookmarksStore.prototype = {
     return this._getStmt(
     "INSERT OR REPLACE INTO moz_items_annos " +
       "(id, item_id, anno_attribute_id, mime_type, content, flags, " +
        "expiration, type, dateAdded, lastModified) " +
     "VALUES (:id, :item_id, :name_id, :mime_type, :content, :flags, " +
             ":expiration, :type, :date_added, :last_modified)");
   },
 
+  __setGUIDStm: null,
+  get _setGUIDStm() {
+    if (this.__setGUIDStm !== null) {
+      return this.__setGUIDStm;
+    }
+
+    // Obtains a statement to set the guid iff the guid column exists.
+    let stmt;
+    try {
+      stmt = this._getStmt(
+        "UPDATE moz_bookmarks " +
+        "SET guid = :guid " +
+        "WHERE id = :item_id");
+    }
+    catch (e) {
+      stmt = false;
+    }
+    return this.__setGUIDStm = stmt;
+  },
+
   // Some helper functions to handle GUIDs
   _setGUID: function _setGUID(id, guid) {
     if (arguments.length == 1)
       guid = Utils.makeGUID();
 
+    // If we can, set the GUID on moz_bookmarks and do not do any other work.
+    let (stmt = this._setGUIDStm) {
+      if (stmt) {
+        stmt.params.guid = guid;
+        stmt.params.item_id = id;
+        Utils.queryAsync(stmt);
+        return guid;
+      }
+    }
+
     // Ensure annotation name exists
     Utils.queryAsync(this._addGUIDAnnotationNameStm);
 
     let stmt = this._checkGUIDItemAnnotationStm;
     stmt.params.item_id = id;
     let result = Utils.queryAsync(stmt, ["item_id", "name_id", "anno_id",
                                          "anno_date"])[0];
     if (!result) {
@@ -889,52 +921,89 @@ BookmarksStore.prototype = {
     stmt.params.expiration = Ci.nsIAnnotationService.EXPIRE_NEVER;
     stmt.params.type = Ci.nsIAnnotationService.TYPE_STRING;
     stmt.params.last_modified = Date.now() * 1000;
     Utils.queryAsync(stmt);
 
     return guid;
   },
 
+  __guidForIdStm: null,
   get _guidForIdStm() {
-    let stmt = this._getStmt(
-      "SELECT a.content AS guid " +
-      "FROM moz_items_annos a " +
-      "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " +
-      "JOIN moz_bookmarks b ON b.id = a.item_id " +
-      "WHERE n.name = :anno_name AND b.id = :item_id");
-    stmt.params.anno_name = GUID_ANNO;
-    return stmt;
+    if (this.__guidForIdStm) {
+      return this.__guidForIdStm;
+    }
+
+    // Try to first read from moz_bookmarks.  Creating the statement will
+    // fail, however, if the guid column does not exist.  We fallback to just
+    // reading the annotation table in this case.
+    let stmt;
+    try {
+      stmt = this._getStmt(
+        "SELECT guid " +
+        "FROM moz_bookmarks " +
+        "WHERE id = :item_id");
+    }
+    catch (e) {
+      stmt = this._getStmt(
+        "SELECT a.content AS guid " +
+        "FROM moz_items_annos a " +
+        "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " +
+        "JOIN moz_bookmarks b ON b.id = a.item_id " +
+        "WHERE n.name = '" + GUID_ANNO + "' " +
+        "AND b.id = :item_id");
+    }
+
+    return this.__guidForIdStm = stmt;
   },
 
   GUIDForId: function GUIDForId(id) {
     for (let [guid, specialId] in Iterator(kSpecialIds))
       if (id == specialId)
          return guid;
 
     let stmt = this._guidForIdStm;
     stmt.params.item_id = id;
 
     // Use the existing GUID if it exists
     let result = Utils.queryAsync(stmt, ["guid"])[0];
-    if (result)
+    if (result && result.guid)
       return result.guid;
 
     // Give the uri a GUID if it doesn't have one
     return this._setGUID(id);
   },
 
+  __idForGUIDStm: null,
   get _idForGUIDStm() {
-    let stmt = this._getStmt(
-      "SELECT a.item_id AS item_id " +
-      "FROM moz_items_annos a " +
-      "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " +
-      "WHERE n.name = :anno_name AND a.content = :guid");
-    stmt.params.anno_name = GUID_ANNO;
-    return stmt;
+    if (this.__idForGUIDStm) {
+      return this.__idForGUIDStm;
+    }
+
+
+    // Try to first read from moz_bookmarks.  Creating the statement will
+    // fail, however, if the guid column does not exist.  We fallback to just
+    // reading the annotation table in this case.
+    let stmt;
+    try {
+      stmt = this._getStmt(
+        "SELECT id AS item_id " +
+        "FROM moz_bookmarks " +
+        "WHERE guid = :guid");
+    }
+    catch (e) {
+      stmt = this._getStmt(
+        "SELECT a.item_id AS item_id " +
+        "FROM moz_items_annos a " +
+        "JOIN moz_anno_attributes n ON n.id = a.anno_attribute_id " +
+        "WHERE n.name = '" + GUID_ANNO + "' " +
+        "AND a.content = :guid");
+    }
+
+    return this.__idForGUIDStm = stmt;
   },
 
   idForGUID: function idForGUID(guid) {
     if (guid in kSpecialIds)
       return kSpecialIds[guid];
 
     let stmt = this._idForGUIDStm;
     // guid might be a String object rather than a string.
--- a/services/sync/modules/engines/history.js
+++ b/services/sync/modules/engines/history.js
@@ -155,16 +155,17 @@ HistoryStore.prototype = {
   },
 
   __setGUIDStm: null,
   get _setGUIDStm() {
     if (this.__setGUIDStm !== null) {
       return this.__setGUIDStm;
     }
 
+    // Obtains a statement to set the guid iff the guid column exists.
     let stmt;
     try {
       stmt = this._getStmt(
         "UPDATE moz_places " +
         "SET guid = :guid " +
         "WHERE url = :page_url");
     }
     catch (e) {