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 c30066b127433e9bb3ca63497dea543fe96eea1f
parent 61144 5a20393b0ce0f755d3ca83cdd9884a5c235659e2
child 61146 0e28cbfc91bee69a3e7f47ea327c23c84504929e
push idunknown
push userunknown
push dateunknown
reviewerssicking, blocking
bugs628063
milestone2.0b10pre
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>