Bug 628063 - 'IndexedDB: Indexes created after data are added are sometimes improperly populated'. r=sicking, a=blocking.
authorBen Turner <bent.mozilla@gmail.com>
Sun, 23 Jan 2011 10:16:00 -0800
changeset 61145 c30066b12743
parent 61144 5a20393b0ce0
child 61146 0e28cbfc91be
push id18245
push userbturner@mozilla.com
push dateSun, 23 Jan 2011 18:16:40 +0000
treeherdermozilla-central@0e28cbfc91be [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking, blocking
bugs628063
milestone2.0b10pre
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 628063 - 'IndexedDB: Indexes created after data are added are sometimes improperly populated'. r=sicking, a=blocking.
dom/indexedDB/IDBIndex.h
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/test/Makefile.in
dom/indexedDB/test/test_create_index_with_integer_keys.html
--- a/dom/indexedDB/IDBIndex.h
+++ b/dom/indexedDB/IDBIndex.h
@@ -89,17 +89,17 @@ public:
 
   bool IsAutoIncrement() const
   {
     return mAutoIncrement;
   }
 
   const nsString& KeyPath() const
   {
-    return mName;
+    return mKeyPath;
   }
 
 private:
   IDBIndex();
   ~IDBIndex();
 
   nsRefPtr<IDBObjectStore> mObjectStore;
 
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -246,19 +246,16 @@ public:
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
 private:
   nsresult InsertDataFromObjectStore(mozIStorageConnection* aConnection);
 
   // In-params.
   nsRefPtr<IDBIndex> mIndex;
-
-  // Out-params.
-  PRInt64 mId;
 };
 
 class DeleteIndexHelper : public AsyncConnectionHelper
 {
 public:
   DeleteIndexHelper(IDBTransaction* aTransaction,
                     const nsAString& aName,
                     IDBObjectStore* aObjectStore)
@@ -2124,36 +2121,39 @@ CreateIndexHelper::DoDatabaseWork(mozISt
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("os_auto_increment"),
                              mIndex->IsAutoIncrement() ? 1 : 0);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (NS_FAILED(stmt->Execute())) {
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
 
-  // Get the id of this object store, and store it for future use.
-  (void)aConnection->GetLastInsertRowID(&mId);
+#ifdef DEBUG
+  {
+    PRInt64 id;
+    aConnection->GetLastInsertRowID(&id);
+    NS_ASSERTION(mIndex->Id() == id, "Bad index id!");
+  }
+#endif
 
   // Now we need to populate the index with data from the object store.
   rv = InsertDataFromObjectStore(aConnection);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   return NS_OK;
 }
 
 nsresult
 CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
 {
-  bool autoIncrement = mIndex->IsAutoIncrement();
-
   nsCAutoString table;
   nsCAutoString columns;
-  if (autoIncrement) {
+  if (mIndex->IsAutoIncrement()) {
     table.AssignLiteral("ai_object_data");
     columns.AssignLiteral("id, data");
   }
   else {
     table.AssignLiteral("object_data");
     columns.AssignLiteral("id, data, key_value");
   }
 
@@ -2168,58 +2168,70 @@ CreateIndexHelper::InsertDataFromObjectS
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mIndex->ObjectStore()->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   PRBool hasResult;
   while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
     nsCOMPtr<mozIStorageStatement> insertStmt =
-      mTransaction->IndexUpdateStatement(autoIncrement, mIndex->IsUnique(),
-                                         false);
+      mTransaction->IndexUpdateStatement(mIndex->IsAutoIncrement(),
+                                         mIndex->IsUnique(), false);
     NS_ENSURE_TRUE(insertStmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     mozStorageStatementScoper scoper2(insertStmt);
 
-    rv = insertStmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), mId);
+    rv = insertStmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
+                                     mIndex->Id());
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     rv = insertStmt->BindInt64ByName(NS_LITERAL_CSTRING("object_data_id"),
                                      stmt->AsInt64(0));
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-    if (!autoIncrement) {
-      // XXX does this cause problems with the affinity?
-      nsString key;
-      rv = stmt->GetString(2, key);
+    if (!mIndex->IsAutoIncrement()) {
+      NS_NAMED_LITERAL_CSTRING(objectDataKey, "object_data_key");
+
+      PRInt32 keyType;
+      rv = stmt->GetTypeOfIndex(2, &keyType);
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-      rv = insertStmt->BindStringByName(NS_LITERAL_CSTRING("object_data_key"),
-                                        key);
+      if (keyType == mozIStorageStatement::VALUE_TYPE_INTEGER) {
+        rv = insertStmt->BindInt64ByName(objectDataKey, stmt->AsInt64(2));
+      }
+      else if (keyType == mozIStorageStatement::VALUE_TYPE_TEXT) {
+        nsString stringKey;
+        rv = stmt->GetString(2, stringKey);
+        NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+        rv = insertStmt->BindStringByName(objectDataKey, stringKey);
+      }
+      else {
+        NS_NOTREACHED("Bad SQLite type!");
+      }
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
 
     const PRUint8* data;
     PRUint32 dataLength;
     rv = stmt->GetSharedBlob(1, &dataLength, &data);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     Key key;
     JSContext* cx = nsnull;
     rv = IDBObjectStore::GetKeyPathValueFromStructuredData(data, dataLength,
                                                            mIndex->KeyPath(),
                                                            &cx, key);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    NS_NAMED_LITERAL_CSTRING(value, "value");
-
     if (key.IsUnset()) {
       continue;
     }
 
+    NS_NAMED_LITERAL_CSTRING(value, "value");
     if (key.IsInt()) {
       rv = insertStmt->BindInt64ByName(value, key.IntValue());
     }
     else if (key.IsString()) {
       rv = insertStmt->BindStringByName(value, key.StringValue());
     }
     else {
       return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -51,16 +51,17 @@ TEST_FILES = \
   event_propagation_iframe.html \
   exceptions_in_success_events_iframe.html \
   helpers.js \
   test_add_twice_failure.html \
   test_bad_keypath.html \
   test_bfcache.html \
   test_clear.html \
   test_create_index.html \
+  test_create_index_with_integer_keys.html \
   test_create_objectStore.html \
   test_cursors.html \
   test_cursor_mutation.html \
   test_cursor_update_updates_indexes.html \
   test_error_events_abort_transactions.html \
   test_event_propagation.html \
   test_event_source.html \
   test_exceptions_in_success_events.html \
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_create_index_with_integer_keys.html
@@ -0,0 +1,76 @@
+<!--
+  Any copyright is dedicated to the Public Domain.
+  http://creativecommons.org/publicdomain/zero/1.0/
+-->
+<html>
+<head>
+  <title>Indexed Database Test</title>
+
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+
+  <script type="text/javascript;version=1.7">
+    function testSteps()
+    {
+      const data = { id: new Date().getTime(),
+                     num: parseInt(Math.random() * 1000) };
+
+      let request = mozIndexedDB.open(window.location.pathname);
+      request.onerror = errorHandler;
+      request.onsuccess = grabEventAndContinueHandler;
+      let event = yield;
+
+      let db = event.target.result;
+      db.onerror = errorHandler;
+
+      db.setVersion("1").onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      event.target.transaction.oncomplete = continueToNextStep;
+
+      // Make object store, add data.
+      let objectStore = db.createObjectStore("foo", { keyPath: "id" });
+      objectStore.add(data);
+      yield;
+
+      db.setVersion("2").onsuccess = grabEventAndContinueHandler;
+      event = yield;
+
+      event.target.transaction.oncomplete = continueToNextStep;
+
+      // Create index.
+      event.target.transaction.objectStore("foo").createIndex("foo", "num");
+      yield;
+
+      // Make sure our object made it into the index.
+      let seenCount = 0;
+
+
+      db.transaction("foo").objectStore("foo").index("foo")
+        .openKeyCursor().onsuccess = function(event) {
+        let cursor = event.target.result;
+        if (cursor) {
+          is(cursor.key, data.num, "Good key");
+          is(cursor.value, data.id, "Good value");
+          seenCount++;
+          cursor.continue();
+        }
+        else {
+          continueToNextStep();
+        }
+      };
+      yield;
+
+      is(seenCount, 1, "Saw our entry");
+
+      finishTest();
+      yield;
+    }
+  </script>
+  <script type="text/javascript;version=1.7" src="helpers.js"></script>
+</head>
+
+<body onload="runTest();"></body>
+
+</html>