Bug 607112 - make GUID a column in moz_places and moz_bookmarks
authorShawn Wilsher <me@shawnwilsher.com>
Thu, 02 Dec 2010 09:40:49 -0800
changeset 59371 60e4b26536ff2eaf53073e308dfa9bb95e091890
parent 59370 325173c0f7e93841598c9c0dc86a4e93b38a4291
child 59372 fa66a8f0f02acacbeffa8099ed493bd71d756ef4
push id1
push usershaver@mozilla.com
push dateTue, 04 Jan 2011 17:58:04 +0000
bugs607112
milestone2.0b8pre
Bug 607112 - make GUID a column in moz_places and moz_bookmarks Part 2 - Import guids from the annotation table for bookmarks, and then delete the entries in the annotation table. r=mak
toolkit/components/places/src/Helpers.cpp
toolkit/components/places/src/Helpers.h
toolkit/components/places/src/nsNavHistory.cpp
toolkit/components/places/tests/migration/places_v10.sqlite
toolkit/components/places/tests/migration/test_v11_from_v10.js
--- a/toolkit/components/places/src/Helpers.cpp
+++ b/toolkit/components/places/src/Helpers.cpp
@@ -277,10 +277,31 @@ GenerateGUID(nsCString& _guid)
   rv = Base64urlEncode(buffer, kRequiredBytesLength, _guid);
   NS_Free(buffer);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NS_ASSERTION(_guid.Length() == GUID_LENGTH, "GUID is not the right size!");
   return NS_OK;
 }
 
+bool
+IsValidGUID(const nsCString& aGUID)
+{
+  nsCString::size_type len = aGUID.Length();
+  if (len != GUID_LENGTH) {
+    return false;
+  }
+
+  for (nsCString::size_type i = 0; i < len; i++ ) {
+    char c = aGUID[i];
+    if (c >= 'a' && c <= 'z' || // a-z
+        c >= 'A' && c <= 'Z' || // A-Z
+        c >= '0' && c <= '9' || // 0-9
+        c == '-' || c == '_') { // - or _
+      continue;
+    }
+    return false;
+  }
+  return true;
+}
+
 } // namespace places
 } // namespace mozilla
--- a/toolkit/components/places/src/Helpers.h
+++ b/toolkit/components/places/src/Helpers.h
@@ -10,17 +10,17 @@
  * 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 Places code.
  *
  * The Initial Developer of the Original Code is
- * Mozilla Foundation.
+ * the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2009
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Shawn Wilsher <me@shawnwilsher.com> (Original Author)
  *
  * 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
@@ -203,16 +203,25 @@ void ReverseString(const nsString& aInpu
 /**
  * Generates an 12 character guid to be used by bookmark and history entries.
  *
  * @note This guid uses the characters a-z, A-Z, 0-9, '-', and '_'.
  */
 nsresult GenerateGUID(nsCString& _guid);
 
 /**
+ * Determines if the string is a valid guid or not.
+ *
+ * @param aGUID
+ *        The guid to test.
+ * @return true if it is a valid guid, false otherwise.
+ */
+bool IsValidGUID(const nsCString& aGUID);
+
+/**
  * Used to finalize a statementCache on a specified thread.
  */
 template<typename StatementType>
 class FinalizeStatementCacheProxy : public nsRunnable
 {
 public:
   /**
    * Constructor.
--- a/toolkit/components/places/src/nsNavHistory.cpp
+++ b/toolkit/components/places/src/nsNavHistory.cpp
@@ -153,16 +153,19 @@ using namespace mozilla::places;
 #define RENEW_CACHED_NOW_TIMEOUT ((PRInt32)3 * PR_MSEC_PER_SEC)
 
 // USECS_PER_DAY == PR_USEC_PER_SEC * 60 * 60 * 24;
 static const PRInt64 USECS_PER_DAY = LL_INIT(20, 500654080);
 
 // character-set annotation
 #define CHARSET_ANNO NS_LITERAL_CSTRING("URIProperties/characterSet")
 
+// Sync guid annotation
+#define SYNCGUID_ANNO NS_LITERAL_CSTRING("sync/guid")
+
 // These macros are used when splitting history by date.
 // These are the day containers and catch-all final container.
 #define HISTORY_ADDITIONAL_DATE_CONT_NUM 3
 // We use a guess of the number of months considering all of them 30 days
 // long, but we split only the last 6 months.
 #define HISTORY_DATE_CONT_NUM(_daysFromOldestVisit) \
   (HISTORY_ADDITIONAL_DATE_CONT_NUM + \
    NS_MIN(6, (PRInt32)NS_ceilf((float)_daysFromOldestVisit/30)))
@@ -1009,18 +1012,84 @@ nsNavHistory::InitAdditionalDBItems()
 
   return NS_OK;
 }
 
 
 nsresult
 nsNavHistory::CheckAndUpdateGUIDs()
 {
+  // First, import any bookmark guids already set by Sync.
+  nsCOMPtr<mozIStorageStatement> updateStmt;
+  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+    "UPDATE moz_bookmarks "
+    "SET guid = :guid "
+    "WHERE id = :item_id "
+  ), getter_AddRefs(updateStmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+
   nsCOMPtr<mozIStorageStatement> stmt;
-  nsresult rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT item_id, content "
+    "FROM moz_items_annos "
+    "JOIN moz_anno_attributes "
+    "WHERE name = :anno_name "
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
+                                  SYNCGUID_ANNO);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRBool hasResult;
+  while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
+    PRInt64 itemId;
+    rv = stmt->GetInt64(0, &itemId);
+    NS_ENSURE_SUCCESS(rv, rv);
+    nsCAutoString guid;
+    rv = stmt->GetUTF8String(1, guid);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    // If we have an invalid guid, we don't need to do any more work.
+    if (!IsValidGUID(guid)) {
+      continue;
+    }
+
+    mozStorageStatementScoper scoper(updateStmt);
+    rv = updateStmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), itemId);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = updateStmt->BindUTF8StringByName(NS_LITERAL_CSTRING("guid"), guid);
+    NS_ENSURE_SUCCESS(rv, rv);
+    rv = updateStmt->Execute();
+    if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
+      // We just tried to insert a duplicate guid.  Ignore this error, and we
+      // will generate a new one next.
+      continue;
+    }
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  // Now, remove all the bookmark guid annotations that we just imported.
+  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
+    "DELETE FROM moz_items_annos "
+    "WHERE anno_attribute_id = ( "
+      "SELECT id "
+      "FROM moz_anno_attributes "
+      "WHERE name = :anno_name "
+    ") "
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+  rv = stmt->BindUTF8StringByName(NS_LITERAL_CSTRING("anno_name"),
+                                  SYNCGUID_ANNO);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = stmt->Execute();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Next, generate guids for any bookmark that does not already have one.
+  rv = mDBConn->CreateStatement(NS_LITERAL_CSTRING(
     "UPDATE moz_bookmarks "
     "SET guid = GENERATE_GUID() "
     "WHERE guid IS NULL "
   ), getter_AddRefs(stmt));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
index 2f7c53f1da7666b520e55ebe6b50e744318eebf5..4a546a6d533487e6ce2f683497fbb5c9fe3e5bd4
GIT binary patch
literal 172032
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
K+W=AR>Hh&WFcgje
--- a/toolkit/components/places/tests/migration/test_v11_from_v10.js
+++ b/toolkit/components/places/tests/migration/test_v11_from_v10.js
@@ -1,16 +1,42 @@
 /* Any copyright is dedicated to the Public Domain.
    http://creativecommons.org/publicdomain/zero/1.0/ */
 
 /**
  * This file tests migration invariants from schema version 10 to schema version
  * 11.
  */
 
+////////////////////////////////////////////////////////////////////////////////
+//// Constants
+
+const kGuidAnnotationName = "sync/guid";
+const kExpectedAnnotations = 5;
+const kExpectedValidGuids = 2;
+
+////////////////////////////////////////////////////////////////////////////////
+//// Globals
+
+// Set in test_initial_state to the value in the database.
+var gItemGuid = [];
+var gItemId = [];
+
+////////////////////////////////////////////////////////////////////////////////
+//// Helpers
+
+/**
+ * Determines if a guid is valid or not.
+ *
+ * @return true if it is a valid guid, false otherwise.
+ */
+function isValidGuid(aGuid)
+{
+  return /^[a-zA-Z0-9\-_]{12}$/.test(aGuid);
+}
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Test Functions
 
 function test_initial_state()
 {
   // Mostly sanity checks our starting DB to make sure it's setup as we expect
   // it to be.
@@ -21,16 +47,36 @@ function test_initial_state()
   let stmt = db.createStatement("PRAGMA journal_mode");
   do_check_true(stmt.executeStep());
   // WAL journal mode should not be set on this database.
   do_check_neq(stmt.getString(0).toLowerCase(), "wal");
   stmt.finalize();
 
   do_check_false(db.indexExists("moz_bookmarks_guid_uniqueindex"));
 
+  // There should be five item annotations for a bookmark guid.
+  stmt = db.createStatement(
+    "SELECT content AS guid, item_id "
+  + "FROM moz_items_annos "
+  + "WHERE anno_attribute_id = ( "
+  +   "SELECT id "
+  +   "FROM moz_anno_attributes "
+  +   "WHERE name = :attr_name "
+  + ") "
+  );
+  stmt.params.attr_name = kGuidAnnotationName;
+  while (stmt.executeStep()) {
+    gItemGuid.push(stmt.row.guid);
+    gItemId.push(stmt.row.item_id)
+  }
+  do_check_eq(gItemGuid.length, gItemId.length);
+  do_check_eq(gItemGuid.length, kExpectedAnnotations);
+  stmt.finalize();
+
+  // Check our schema version to make sure it is actually at 10.
   do_check_eq(db.schemaVersion, 10);
 
   db.close();
   run_next_test();
 }
 
 function test_moz_bookmarks_guid_exists()
 {
@@ -61,16 +107,71 @@ function test_bookmark_guids_non_null()
   + "FROM moz_bookmarks "
   + "WHERE guid IS NULL "
   );
   do_check_false(stmt.executeStep());
   stmt.finalize();
   run_next_test();
 }
 
+function test_bookmark_guid_annotation_imported()
+{
+  // Make sure we have the imported guid; not a newly generated one.
+  let stmt = DBConn().createStatement(
+    "SELECT id "
+  + "FROM moz_bookmarks "
+  + "WHERE guid = :guid "
+  + "AND id = :item_id "
+  );
+  let validGuids = 0;
+  let seenGuids = [];
+  for (let i = 0; i < gItemGuid.length; i++) {
+    let guid = gItemGuid[i];
+    stmt.params.guid = guid;
+    stmt.params.item_id = gItemId[i];
+
+    // Check that it is a valid guid that we expect, and that it is not a
+    // duplicate (which would violate the unique constraint).
+    let valid = isValidGuid(guid) && seenGuids.indexOf(guid) == -1;
+    seenGuids.push(guid);
+
+    if (valid) {
+      validGuids++;
+      do_check_true(stmt.executeStep());
+    }
+    else {
+      do_check_false(stmt.executeStep());
+    }
+    stmt.reset();
+  }
+  do_check_eq(validGuids, kExpectedValidGuids);
+  stmt.finalize();
+
+  run_next_test();
+}
+
+function test_bookmark_guid_annotation_removed()
+{
+  let stmt = DBConn().createStatement(
+    "SELECT COUNT(1) "
+  + "FROM moz_items_annos "
+  + "WHERE anno_attribute_id = ( "
+  +   "SELECT id "
+  +   "FROM moz_anno_attributes "
+  +   "WHERE name = :attr_name "
+  + ") "
+  );
+  stmt.params.attr_name = kGuidAnnotationName;
+  do_check_true(stmt.executeStep());
+  do_check_eq(stmt.getInt32(0), 0);
+  stmt.finalize();
+
+  run_next_test();
+}
+
 function test_final_state()
 {
   // We open a new database mostly so that we can check that the settings were
   // actually saved.
   let dbFile = gProfD.clone();
   dbFile.append(kDBName);
   let db = Services.storage.openUnsharedDatabase(dbFile);
 
@@ -91,16 +192,18 @@ function test_final_state()
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Test Runner
 
 let tests = [
   test_initial_state,
   test_moz_bookmarks_guid_exists,
   test_bookmark_guids_non_null,
+  test_bookmark_guid_annotation_imported,
+  test_bookmark_guid_annotation_removed,
   test_final_state,
 ];
 let index = 0;
 
 function run_next_test()
 {
   function _run_next_test() {
     if (index < tests.length) {