Back out patches due to test failures. rev 1b9ca56d4aab and a few more.
authorJonas Sicking <jonas@sicking.cc>
Fri, 02 Dec 2011 19:46:25 -0800
changeset 83201 8a2106940402c51702de6dda5107926396fcfb70
parent 83200 d7a9e843e573035b0e6f42d68423c85cd9851126
child 83202 a9f3b58b334e0b06848be58f16e27886297dd78b
push id114
push userffxbld
push dateFri, 09 Mar 2012 01:01:18 +0000
treeherdermozilla-release@c081ebf13261 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone11.0a1
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
Back out patches due to test failures. rev 1b9ca56d4aab and a few more.
dom/base/nsDOMClassInfo.cpp
dom/base/nsDOMClassInfo.h
dom/indexedDB/DatabaseInfo.cpp
dom/indexedDB/DatabaseInfo.h
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBIndex.cpp
dom/indexedDB/IDBIndex.h
dom/indexedDB/IDBObjectStore.cpp
dom/indexedDB/IDBObjectStore.h
dom/indexedDB/IDBTransaction.cpp
dom/indexedDB/IDBTransaction.h
dom/indexedDB/IndexedDatabase.h
dom/indexedDB/OpenDatabaseHelper.cpp
dom/indexedDB/OpenDatabaseHelper.h
dom/indexedDB/nsIIDBIndex.idl
dom/indexedDB/test/Makefile.in
dom/indexedDB/test/test_complex_keyPaths.html
dom/indexedDB/test/test_create_objectStore.html
dom/indexedDB/test/test_multientry.html
dom/indexedDB/test/test_remove_index.html
dom/indexedDB/test/test_remove_objectStore.html
dom/indexedDB/test/test_transaction_abort.html
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1636,17 +1636,16 @@ jsid nsDOMClassInfo::sNodePrincipal_id  
 jsid nsDOMClassInfo::sDocumentURIObject_id=JSID_VOID;
 jsid nsDOMClassInfo::sJava_id            = JSID_VOID;
 jsid nsDOMClassInfo::sPackages_id        = JSID_VOID;
 jsid nsDOMClassInfo::sWrappedJSObject_id = JSID_VOID;
 jsid nsDOMClassInfo::sURL_id             = JSID_VOID;
 jsid nsDOMClassInfo::sKeyPath_id         = JSID_VOID;
 jsid nsDOMClassInfo::sAutoIncrement_id   = JSID_VOID;
 jsid nsDOMClassInfo::sUnique_id          = JSID_VOID;
-jsid nsDOMClassInfo::sMultiEntry_id      = JSID_VOID;
 jsid nsDOMClassInfo::sOnload_id          = JSID_VOID;
 jsid nsDOMClassInfo::sOnerror_id         = JSID_VOID;
 
 static const JSClass *sObjectClass = nsnull;
 
 /**
  * Set our JSClass pointer for the Object class
  */
@@ -1900,17 +1899,16 @@ nsDOMClassInfo::DefineStaticJSVals(JSCon
   SET_JSID_TO_STRING(sDocumentURIObject_id,cx,"documentURIObject");
   SET_JSID_TO_STRING(sJava_id,            cx, "java");
   SET_JSID_TO_STRING(sPackages_id,        cx, "Packages");
   SET_JSID_TO_STRING(sWrappedJSObject_id, cx, "wrappedJSObject");
   SET_JSID_TO_STRING(sURL_id,             cx, "URL");
   SET_JSID_TO_STRING(sKeyPath_id,         cx, "keyPath");
   SET_JSID_TO_STRING(sAutoIncrement_id,   cx, "autoIncrement");
   SET_JSID_TO_STRING(sUnique_id,          cx, "unique");
-  SET_JSID_TO_STRING(sMultiEntry_id,      cx, "multiEntry");
   SET_JSID_TO_STRING(sOnload_id,          cx, "onload");
   SET_JSID_TO_STRING(sOnerror_id,         cx, "onerror");
 
   return NS_OK;
 }
 
 static nsresult
 CreateExceptionFromResult(JSContext *cx, nsresult aResult)
@@ -4899,17 +4897,16 @@ nsDOMClassInfo::ShutDown()
   sNodePrincipal_id   = JSID_VOID;
   sDocumentURIObject_id=JSID_VOID;
   sJava_id            = JSID_VOID;
   sPackages_id        = JSID_VOID;
   sWrappedJSObject_id = JSID_VOID;
   sKeyPath_id         = JSID_VOID;
   sAutoIncrement_id   = JSID_VOID;
   sUnique_id          = JSID_VOID;
-  sMultiEntry_id      = JSID_VOID;
   sOnload_id          = JSID_VOID;
   sOnerror_id         = JSID_VOID;
 
   NS_IF_RELEASE(sXPConnect);
   NS_IF_RELEASE(sSecMan);
   sIsInitialized = false;
 }
 
--- a/dom/base/nsDOMClassInfo.h
+++ b/dom/base/nsDOMClassInfo.h
@@ -290,17 +290,16 @@ public:
   static jsid sDocumentURIObject_id;
   static jsid sJava_id;
   static jsid sPackages_id;
   static jsid sWrappedJSObject_id;
   static jsid sURL_id;
   static jsid sKeyPath_id;
   static jsid sAutoIncrement_id;
   static jsid sUnique_id;
-  static jsid sMultiEntry_id;
   static jsid sOnload_id;
   static jsid sOnerror_id;
 
 protected:
   static JSPropertyOp sXPCNativeWrapperGetPropertyOp;
   static JSPropertyOp sXrayWrapperPropertyHolderGetPropertyOp;
 };
 
--- a/dom/indexedDB/DatabaseInfo.cpp
+++ b/dom/indexedDB/DatabaseInfo.cpp
@@ -92,29 +92,27 @@ DatabaseInfo::~DatabaseInfo()
   }
 }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
 
 IndexInfo::IndexInfo()
 : id(LL_MININT),
   unique(false),
-  autoIncrement(false),
-  multiEntry(false)
+  autoIncrement(false)
 {
   MOZ_COUNT_CTOR(IndexInfo);
 }
 
 IndexInfo::IndexInfo(const IndexInfo& aOther)
 : id(aOther.id),
   name(aOther.name),
   keyPath(aOther.keyPath),
   unique(aOther.unique),
-  autoIncrement(aOther.autoIncrement),
-  multiEntry(aOther.multiEntry)
+  autoIncrement(aOther.autoIncrement)
 {
   MOZ_COUNT_CTOR(IndexInfo);
 }
 
 IndexInfo::~IndexInfo()
 {
   MOZ_COUNT_DTOR(IndexInfo);
 }
--- a/dom/indexedDB/DatabaseInfo.h
+++ b/dom/indexedDB/DatabaseInfo.h
@@ -116,17 +116,16 @@ struct IndexInfo
   : id(LL_MININT), unique(false), autoIncrement(false) { }
 #endif
 
   PRInt64 id;
   nsString name;
   nsString keyPath;
   bool unique;
   bool autoIncrement;
-  bool multiEntry;
 };
 
 struct ObjectStoreInfo
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   ObjectStoreInfo();
   ObjectStoreInfo(ObjectStoreInfo& aOther);
   ~ObjectStoreInfo();
@@ -145,16 +144,15 @@ struct ObjectStoreInfo
 
 struct IndexUpdateInfo
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   IndexUpdateInfo();
   ~IndexUpdateInfo();
 #endif
 
-  PRInt64 indexId;
-  bool indexUnique;
+  IndexInfo info;
   Key value;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_databaseinfo_h__
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -459,18 +459,21 @@ IDBDatabase::CreateObjectStore(const nsA
 
   if (!transaction ||
       transaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   DatabaseInfo* databaseInfo = Info();
 
+  if (databaseInfo->ContainsStoreName(aName)) {
+    return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
+  }
+
   nsString keyPath;
-  keyPath.SetIsVoid(true);
   bool autoIncrement = false;
 
   if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
     if (JSVAL_IS_PRIMITIVE(aOptions)) {
       // XXX This isn't the right error
       return NS_ERROR_DOM_TYPE_ERR;
     }
 
@@ -506,27 +509,18 @@ IDBDatabase::CreateObjectStore(const nsA
     JSBool boolVal;
     if (!JS_ValueToBoolean(aCx, val, &boolVal)) {
       NS_WARNING("JS_ValueToBoolean failed!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
     autoIncrement = !!boolVal;
   }
 
-  if (databaseInfo->ContainsStoreName(aName)) {
-    return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
-  }
-
-  if (!keyPath.IsVoid()) {
-    if (keyPath.IsEmpty() && autoIncrement) {
-      return NS_ERROR_DOM_INVALID_ACCESS_ERR;
-    }
-    if (!IDBObjectStore::IsValidKeyPath(aCx, keyPath)) {
-      return NS_ERROR_DOM_SYNTAX_ERR;
-    }
+  if (!IDBObjectStore::IsValidKeyPath(aCx, keyPath)) {
+    return NS_ERROR_DOM_SYNTAX_ERR;
   }
 
   nsAutoPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
 
   newInfo->name = aName;
   newInfo->id = databaseInfo->nextObjectStoreId++;
   newInfo->keyPath = keyPath;
   newInfo->autoIncrement = autoIncrement;
@@ -576,19 +570,16 @@ IDBDatabase::DeleteObjectStore(const nsA
   }
 
   nsRefPtr<DeleteObjectStoreHelper> helper =
     new DeleteObjectStoreHelper(transaction, objectStoreInfo->id);
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   info->RemoveObjectStore(aName);
-
-  transaction->ReleaseCachedObjectStore(aName);
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBDatabase::Transaction(const jsval& aStoreNames,
                          PRUint16 aMode,
                          JSContext* aCx,
                          PRUint8 aOptionalArgCount,
@@ -804,38 +795,36 @@ IDBDatabase::PostHandleEvent(nsEventChai
   return NS_OK;
 }
 
 nsresult
 CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
-    "INSERT INTO object_store (id, auto_increment, name, key_path) "
-    "VALUES (:id, :auto_increment, :name, :key_path)"
+    "INSERT INTO object_store (id, name, key_path, auto_increment) "
+    "VALUES (:id, :name, :key_path, :auto_increment)"
   ));
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
                                        mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
-                             mObjectStore->IsAutoIncrement() ? 1 : 0);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mObjectStore->Name());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  rv = mObjectStore->HasKeyPath() ?
-    stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
-                           mObjectStore->KeyPath()) :
-    stmt->BindNullByName(NS_LITERAL_CSTRING("key_path"));
+  rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
+                              mObjectStore->KeyPath());
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("auto_increment"),
+                             mObjectStore->IsAutoIncrement() ? 1 : 0);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -242,43 +242,33 @@ IDBFactory::LoadDatabaseInformation(mozI
 
     ObjectStoreInfo* info = element->get();
 
     rv = stmt->GetString(0, info->name);
     NS_ENSURE_SUCCESS(rv, rv);
 
     info->id = stmt->AsInt64(1);
 
-    PRInt32 columnType;
-    nsresult rv = stmt->GetTypeOfIndex(2, &columnType);
+    rv = stmt->GetString(2, info->keyPath);
     NS_ENSURE_SUCCESS(rv, rv);
-    if (columnType == mozIStorageStatement::VALUE_TYPE_NULL) {
-      info->keyPath.SetIsVoid(true);
-    }
-    else {
-      NS_ASSERTION(columnType == mozIStorageStatement::VALUE_TYPE_TEXT,
-                   "Should be a string");
-      rv = stmt->GetString(2, info->keyPath);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
 
     info->autoIncrement = !!stmt->AsInt32(3);
     info->databaseId = aDatabaseId;
 
     ObjectStoreInfoMap* mapEntry = infoMap.AppendElement();
     NS_ENSURE_TRUE(mapEntry, NS_ERROR_OUT_OF_MEMORY);
 
     mapEntry->id = info->id;
     mapEntry->info = info;
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Load index information
   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT object_store_id, id, name, key_path, unique_index, multientry, "
+    "SELECT object_store_id, id, name, key_path, unique_index, "
            "object_store_autoincrement "
     "FROM object_store_index"
   ), getter_AddRefs(stmt));
   NS_ENSURE_SUCCESS(rv, rv);
 
   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
     PRInt64 objectStoreId = stmt->AsInt64(0);
 
@@ -302,18 +292,17 @@ IDBFactory::LoadDatabaseInformation(mozI
 
     rv = stmt->GetString(2, indexInfo->name);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = stmt->GetString(3, indexInfo->keyPath);
     NS_ENSURE_SUCCESS(rv, rv);
 
     indexInfo->unique = !!stmt->AsInt32(4);
-    indexInfo->multiEntry = !!stmt->AsInt32(5);
-    indexInfo->autoIncrement = !!stmt->AsInt32(6);
+    indexInfo->autoIncrement = !!stmt->AsInt32(5);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Load version information.
   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT version "
     "FROM database"
   ), getter_AddRefs(stmt));
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -313,17 +313,16 @@ IDBIndex::Create(IDBObjectStore* aObject
   index->mScriptContext = database->ScriptContext();
   index->mOwner = database->Owner();
 
   index->mObjectStore = aObjectStore;
   index->mId = aIndexInfo->id;
   index->mName = aIndexInfo->name;
   index->mKeyPath = aIndexInfo->keyPath;
   index->mUnique = aIndexInfo->unique;
-  index->mMultiEntry = aIndexInfo->multiEntry;
   index->mAutoIncrement = aIndexInfo->autoIncrement;
 
   return index.forget();
 }
 
 IDBIndex::IDBIndex()
 : mId(LL_MININT),
   mUnique(false),
@@ -393,25 +392,16 @@ IDBIndex::GetUnique(bool* aUnique)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   *aUnique = mUnique;
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBIndex::GetMultiEntry(bool* aMultiEntry)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  *aMultiEntry = mMultiEntry;
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 IDBIndex::GetObjectStore(nsIIDBObjectStore** aObjectStore)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsCOMPtr<nsIIDBObjectStore> objectStore(mObjectStore);
   objectStore.forget(aObjectStore);
   return NS_OK;
 }
--- a/dom/indexedDB/IDBIndex.h
+++ b/dom/indexedDB/IDBIndex.h
@@ -82,21 +82,16 @@ public:
     return mName;
   }
 
   bool IsUnique() const
   {
     return mUnique;
   }
 
-  bool IsMultiEntry() const
-  {
-    return mMultiEntry;
-  }
-
   bool IsAutoIncrement() const
   {
     return mAutoIncrement;
   }
 
   const nsString& KeyPath() const
   {
     return mKeyPath;
@@ -110,15 +105,14 @@ private:
 
   nsCOMPtr<nsIScriptContext> mScriptContext;
   nsCOMPtr<nsPIDOMWindow> mOwner;
 
   PRInt64 mId;
   nsString mName;
   nsString mKeyPath;
   bool mUnique;
-  bool mMultiEntry;
   bool mAutoIncrement;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbindex_h__
--- a/dom/indexedDB/IDBObjectStore.cpp
+++ b/dom/indexedDB/IDBObjectStore.cpp
@@ -92,16 +92,19 @@ public:
 
   void ReleaseMainThreadObjects()
   {
     mObjectStore = nsnull;
     IDBObjectStore::ClearStructuredCloneBuffer(mCloneBuffer);
     AsyncConnectionHelper::ReleaseMainThreadObjects();
   }
 
+  nsresult UpdateIndexes(mozIStorageConnection* aConnection,
+                         PRInt64 aObjectDataId);
+
 private:
   // In-params.
   nsRefPtr<IDBObjectStore> mObjectStore;
 
   // These may change in the autoincrement case.
   JSAutoStructuredCloneBuffer mCloneBuffer;
   Key mKey;
   const bool mOverwrite;
@@ -414,63 +417,51 @@ IgnoreWhitespace(PRUnichar c)
 {
   return false;
 }
 
 typedef nsCharSeparatedTokenizerTemplate<IgnoreWhitespace> KeyPathTokenizer;
 
 inline
 nsresult
-GetJSValFromKeyPath(JSContext* aCx,
-                    jsval aVal,
-                    const nsAString& aKeyPath,
-                    jsval& aKey)
+GetKeyFromValue(JSContext* aCx,
+                jsval aVal,
+                const nsAString& aKeyPath,
+                Key& aKey)
 {
   NS_ASSERTION(aCx, "Null pointer!");
   // aVal can be primitive iff the key path is empty.
+  NS_ASSERTION(!JSVAL_IS_PRIMITIVE(aVal) || aKeyPath.IsEmpty(),
+               "Why are we here!?");
   NS_ASSERTION(IDBObjectStore::IsValidKeyPath(aCx, aKeyPath),
                "This will explode!");
 
   KeyPathTokenizer tokenizer(aKeyPath, '.');
 
   jsval intermediate = aVal;
   while (tokenizer.hasMoreTokens()) {
-    const nsDependentSubstring& token = tokenizer.nextToken();
-
-    NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
-
-    const jschar* keyPathChars = token.BeginReading();
+    nsString token(tokenizer.nextToken());
+
+    if (!token.Length()) {
+      return NS_ERROR_DOM_SYNTAX_ERR;
+    }
+
+    const jschar* keyPathChars = token.get();
     const size_t keyPathLen = token.Length();
 
     if (JSVAL_IS_PRIMITIVE(intermediate)) {
-      intermediate = JSVAL_VOID;
-      break;
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     JSBool ok = JS_GetUCProperty(aCx, JSVAL_TO_OBJECT(intermediate),
                                  keyPathChars, keyPathLen, &intermediate);
     NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
-  
-  aKey = intermediate;
-  return NS_OK;
-}
-
-inline
-nsresult
-GetKeyFromValue(JSContext* aCx,
-                jsval aVal,
-                const nsAString& aKeyPath,
-                Key& aKey)
-{
-  jsval key;
-  nsresult rv = GetJSValFromKeyPath(aCx, aVal, aKeyPath, key);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (NS_FAILED(aKey.SetFromJSVal(aCx, key))) {
+
+  if (NS_FAILED(aKey.SetFromJSVal(aCx, intermediate))) {
     aKey.Unset();
   }
 
   return NS_OK;
 }
 
 inline
 already_AddRefed<IDBRequest>
@@ -578,89 +569,116 @@ IDBObjectStore::IsValidKeyPath(JSContext
     return false;
   }
 
   return true;
 }
 
 // static
 nsresult
-IDBObjectStore::AppendIndexUpdateInfo(PRInt64 aIndexID,
-                                      const nsAString& aKeyPath,
-                                      bool aUnique,
-                                      bool aMultiEntry,
-                                      JSContext* aCx,
-                                      jsval aObject,
-                                      nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
+IDBObjectStore::GetKeyPathValueFromStructuredData(const PRUint8* aData,
+                                                  PRUint32 aDataLength,
+                                                  const nsAString& aKeyPath,
+                                                  JSContext* aCx,
+                                                  Key& aValue)
 {
-  jsval key;
-  nsresult rv = GetJSValFromKeyPath(aCx, aObject, aKeyPath, key);
+  NS_ASSERTION(aData, "Null pointer!");
+  NS_ASSERTION(aDataLength, "Empty data!");
+  NS_ASSERTION(aCx, "Null pointer!");
+
+  JSAutoRequest ar(aCx);
+
+  jsval clone;
+  if (!JS_ReadStructuredClone(aCx, reinterpret_cast<const uint64*>(aData),
+                              aDataLength, JS_STRUCTURED_CLONE_VERSION,
+                              &clone, NULL, NULL)) {
+    return NS_ERROR_DOM_DATA_CLONE_ERR;
+  }
+
+  if (JSVAL_IS_PRIMITIVE(clone) && !aKeyPath.IsEmpty()) {
+    // This isn't an object, so just leave the key unset.
+    aValue.Unset();
+    return NS_OK;
+  }
+
+  nsresult rv = GetKeyFromValue(aCx, clone, aKeyPath, aValue);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  if (aMultiEntry && !JSVAL_IS_PRIMITIVE(key) &&
-      JS_IsArrayObject(aCx, JSVAL_TO_OBJECT(key))) {
-    JSObject* array = JSVAL_TO_OBJECT(key);
-    jsuint arrayLength;
-    if (!JS_GetArrayLength(aCx, array, &arrayLength)) {
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  return NS_OK;
+}
+
+/* static */
+nsresult
+IDBObjectStore::GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
+                                   JSContext* aCx,
+                                   jsval aObject,
+                                   nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
+{
+  JSObject* cloneObj = nsnull;
+
+  PRUint32 count = aObjectStoreInfo->indexes.Length();
+  if (count) {
+    if (!aUpdateInfoArray.SetCapacity(count)) {
+      NS_ERROR("Out of memory!");
+      return NS_ERROR_OUT_OF_MEMORY;
     }
 
-    for (jsuint arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
-      jsval arrayItem;
-      if (!JS_GetElement(aCx, array, arrayIndex, &arrayItem)) {
-        return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) {
+      const IndexInfo& indexInfo = aObjectStoreInfo->indexes[indexesIndex];
+
+      if (JSVAL_IS_PRIMITIVE(aObject) && !indexInfo.keyPath.IsEmpty()) {
+        continue;
       }
 
       Key value;
-      if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
-          value.IsUnset()) {
+      nsresult rv = GetKeyFromValue(aCx, aObject, indexInfo.keyPath, value);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      if (value.IsUnset()) {
         // Not a value we can do anything with, ignore it.
         continue;
       }
 
       IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
-      updateInfo->indexId = aIndexID;
-      updateInfo->indexUnique = aUnique;
+      updateInfo->info = indexInfo;
       updateInfo->value = value;
     }
   }
   else {
-    Key value;
-    if (NS_FAILED(value.SetFromJSVal(aCx, key)) ||
-        value.IsUnset()) {
-      // Not a value we can do anything with, ignore it.
-      return NS_OK;
-    }
-
-    IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
-    updateInfo->indexId = aIndexID;
-    updateInfo->indexUnique = aUnique;
-    updateInfo->value = value;
+    aUpdateInfoArray.Clear();
   }
 
   return NS_OK;
 }
 
-// static
+/* static */
 nsresult
 IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
                               PRInt64 aObjectStoreId,
                               const Key& aObjectStoreKey,
                               bool aAutoIncrement,
                               bool aOverwrite,
                               PRInt64 aObjectDataId,
                               const nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
 {
-  NS_ASSERTION(!aAutoIncrement || aObjectDataId != LL_MININT,
-               "Bad objectData id!");
+#ifdef DEBUG
+  if (aAutoIncrement) {
+    NS_ASSERTION(aObjectDataId != LL_MININT, "Bad objectData id!");
+  }
+  else {
+    NS_ASSERTION(aObjectDataId == LL_MININT, "Bad objectData id!");
+  }
+#endif
+
+  PRUint32 indexCount = aUpdateInfoArray.Length();
 
   nsCOMPtr<mozIStorageStatement> stmt;
   nsresult rv;
 
-  if (aObjectDataId == LL_MININT) {
+  if (!aAutoIncrement) {
     stmt = aTransaction->GetCachedStatement(
       "SELECT id "
       "FROM object_data "
       "WHERE object_store_id = :osid "
       "AND key_value = :key_value"
     );
     NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE);
 
@@ -712,59 +730,43 @@ IDBObjectStore::UpdateIndexes(IDBTransac
 
     rv = stmt->BindInt64ByName(objectDataId, aObjectDataId);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = stmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  PRUint32 infoCount = aUpdateInfoArray.Length();
-  for (PRUint32 i = 0; i < infoCount; i++) {
-    const IndexUpdateInfo& updateInfo = aUpdateInfoArray[i];
+  for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) {
+    const IndexUpdateInfo& updateInfo = aUpdateInfoArray[indexIndex];
+
+    NS_ASSERTION(updateInfo.info.autoIncrement == aAutoIncrement, "Huh?!");
 
     // Insert new values.
     stmt = aTransaction->IndexDataInsertStatement(aAutoIncrement,
-                                                  updateInfo.indexUnique);
+                                                  updateInfo.info.unique);
     NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE);
 
     mozStorageStatementScoper scoper4(stmt);
 
-    rv = stmt->BindInt64ByName(indexId, updateInfo.indexId);
+    rv = stmt->BindInt64ByName(indexId, updateInfo.info.id);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = stmt->BindInt64ByName(objectDataId, aObjectDataId);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    if (!aAutoIncrement) {
+    if (!updateInfo.info.autoIncrement) {
       rv = aObjectStoreKey.BindToStatement(stmt, objectDataKey);
       NS_ENSURE_SUCCESS(rv, rv);
     }
 
     rv = updateInfo.value.BindToStatement(stmt, value);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = stmt->Execute();
-    if (rv == NS_ERROR_STORAGE_CONSTRAINT && updateInfo.indexUnique) {
-      // If we're inserting multiple entries for the same unique index, then
-      // we might have failed to insert due to colliding with another entry for
-      // the same index in which case we should ignore it.
-      
-      for (PRInt32 j = (PRInt32)i - 1;
-           j >= 0 && aUpdateInfoArray[j].indexId == updateInfo.indexId;
-           --j) {
-        if (updateInfo.value == aUpdateInfoArray[j].value) {
-          // We found a key with the same value for the same index. So we
-          // must have had a collision with a value we just inserted.
-          rv = NS_OK;
-          break;
-        }
-      }
-    }
-
     if (NS_FAILED(rv)) {
       return rv;
     }
   }
 
   return NS_OK;
 }
 
@@ -899,154 +901,72 @@ IDBObjectStore::GetAddInfo(JSContext* aC
                            Key& aKey,
                            nsTArray<IndexUpdateInfo>& aUpdateInfoArray,
                            PRUint64* aOffsetToKeyProp)
 {
   nsresult rv;
 
   // Return DATA_ERR if a key was passed in and this objectStore uses inline
   // keys.
-  if (!JSVAL_IS_VOID(aKeyVal) && HasKeyPath()) {
+  if (!JSVAL_IS_VOID(aKeyVal) && !mKeyPath.IsEmpty()) {
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   JSAutoRequest ar(aCx);
 
-  if (!HasKeyPath()) {
+  if (mKeyPath.IsEmpty()) {
     // Out-of-line keys must be passed in.
     rv = aKey.SetFromJSVal(aCx, aKeyVal);
     NS_ENSURE_SUCCESS(rv, rv);
   }
-  else if (!mAutoIncrement) {
+  else {
     // Inline keys live on the object. Make sure that the value passed in is an
     // object.
+    if (JSVAL_IS_PRIMITIVE(aValue)) {
+      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
+    }
+
     rv = GetKeyFromValue(aCx, aValue, mKeyPath, aKey);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Return DATA_ERR if no key was specified this isn't an autoIncrement
   // objectStore.
   if (aKey.IsUnset() && !mAutoIncrement) {
     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
   }
 
   // Figure out indexes and the index values to update here.
   ObjectStoreInfo* info;
   if (!mTransaction->Database()->Info()->GetObjectStore(mName, &info)) {
     NS_ERROR("This should never fail!");
   }
 
-  PRUint32 count = info->indexes.Length();
-  aUpdateInfoArray.SetCapacity(count); // Pretty good estimate
-  for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) {
-    const IndexInfo& indexInfo = info->indexes[indexesIndex];
-
-    rv = AppendIndexUpdateInfo(indexInfo.id, indexInfo.keyPath,
-                               indexInfo.unique, indexInfo.multiEntry,
-                               aCx, aValue, aUpdateInfoArray);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  nsString targetObjectPropName;
-  JSObject* targetObject = nsnull;
-
-  if (mAutoIncrement && HasKeyPath()) {
-    NS_ASSERTION(aKey.IsUnset(), "Shouldn't have gotten the key yet!");
-
-    if (JSVAL_IS_PRIMITIVE(aValue)) {
-      return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
-    }
-
-    KeyPathTokenizer tokenizer(mKeyPath, '.');
-    NS_ASSERTION(tokenizer.hasMoreTokens(),
-                 "Shouldn't have empty keypath and autoincrement");
-
-    JSObject* obj = JSVAL_TO_OBJECT(aValue);
-    while (tokenizer.hasMoreTokens()) {
-      const nsDependentSubstring& token = tokenizer.nextToken();
-  
-      NS_ASSERTION(!token.IsEmpty(), "Should be a valid keypath");
-  
-      const jschar* keyPathChars = token.BeginReading();
-      const size_t keyPathLen = token.Length();
-  
-      JSBool hasProp;
-      if (!targetObject) {
-        // We're still walking the chain of existing objects
-
-        JSBool ok = JS_HasUCProperty(aCx, obj, keyPathChars, keyPathLen,
-                                     &hasProp);
-        NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-        if (hasProp) {
-          // Get if the property exists...
-          jsval intermediate;
-          JSBool ok = JS_GetUCProperty(aCx, obj, keyPathChars, keyPathLen,
-                                       &intermediate);
-          NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-          if (tokenizer.hasMoreTokens()) {
-            // ...and walk to it if there are more steps...
-            if (JSVAL_IS_PRIMITIVE(intermediate)) {
-              return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
-            }
-            obj = JSVAL_TO_OBJECT(intermediate);
-          }
-          else {
-            // ...otherwise use it as key
-            aKey.SetFromJSVal(aCx, intermediate);
-            if (aKey.IsUnset()) {
-              return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
-            }
-          }
-        }
-        else {
-          // If the property doesn't exist, fall into below path of starting
-          // to define properties
-          targetObject = obj;
-          targetObjectPropName = token;
-        }
-      }
-
-      if (targetObject) {
-        // We have started inserting new objects or are about to just insert
-        // the first one.
-        if (tokenizer.hasMoreTokens()) {
-          // If we're not at the end, we need to add a dummy object to the chain.
-          JSObject* dummy = JS_NewObject(aCx, nsnull, nsnull, nsnull);
-          if (!dummy) {
-            rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-            break;
-          }
-  
-          if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
-                                   token.Length(),
-                                   OBJECT_TO_JSVAL(dummy), nsnull, nsnull,
-                                   JSPROP_ENUMERATE)) {
-            rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-            break;
-          }
-  
-          obj = dummy;
-        }
-        else {
-          JSObject* dummy = JS_NewObject(aCx, &gDummyPropClass, nsnull, nsnull);
-          if (!dummy) {
-            rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-            break;
-          }
-  
-          if (!JS_DefineUCProperty(aCx, obj, token.BeginReading(),
-                                   token.Length(), OBJECT_TO_JSVAL(dummy),
-                                   nsnull, nsnull, JSPROP_ENUMERATE)) {
-            rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-          }
-        }
-      }
-    }
+  rv = GetIndexUpdateInfo(info, aCx, aValue, aUpdateInfoArray);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  const jschar* keyPathChars =
+    reinterpret_cast<const jschar*>(mKeyPath.get());
+  const size_t keyPathLen = mKeyPath.Length();
+  JSBool ok = JS_FALSE;
+
+  if (!mKeyPath.IsEmpty() && aKey.IsUnset()) {
+    NS_ASSERTION(mAutoIncrement, "Should have bailed earlier!");
+
+    JSObject* obj = JS_NewObject(aCx, &gDummyPropClass, nsnull, nsnull);
+    NS_ENSURE_TRUE(obj, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    jsval key = OBJECT_TO_JSVAL(obj);
+ 
+    ok = JS_DefineUCProperty(aCx, JSVAL_TO_OBJECT(aValue), keyPathChars,
+                             keyPathLen, key, nsnull, nsnull,
+                             JSPROP_ENUMERATE);
+    NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    // From this point on we have to try to remove the property.
   }
 
   JSStructuredCloneCallbacks callbacks = {
     nsnull,
     StructuredCloneWriteDummyProp,
     nsnull
   };
   *aOffsetToKeyProp = 0;
@@ -1054,25 +974,23 @@ IDBObjectStore::GetAddInfo(JSContext* aC
   // We guard on rv being a success because we need to run the property
   // deletion code below even if we should not be serializing the value
   if (NS_SUCCEEDED(rv) && 
       !IDBObjectStore::SerializeValue(aCx, aCloneBuffer, aValue, &callbacks,
                                       aOffsetToKeyProp)) {
     rv = NS_ERROR_DOM_DATA_CLONE_ERR;
   }
 
-  if (targetObject) {
+  if (ok) {
     // If this fails, we lose, and the web page sees a magical property
     // appear on the object :-(
     jsval succeeded;
-    if (!JS_DeleteUCProperty2(aCx, targetObject,
-                              targetObjectPropName.get(),
-                              targetObjectPropName.Length(), &succeeded)) {
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
+    ok = JS_DeleteUCProperty2(aCx, JSVAL_TO_OBJECT(aValue), keyPathChars,
+                              keyPathLen, &succeeded);
+    NS_ENSURE_TRUE(ok, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     NS_ASSERTION(JSVAL_IS_BOOLEAN(succeeded), "Wtf?");
     NS_ENSURE_TRUE(JSVAL_TO_BOOLEAN(succeeded),
                    NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   return rv;
 }
 
@@ -1449,17 +1367,16 @@ IDBObjectStore::CreateIndex(const nsAStr
 
   if (found) {
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
 
   NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
 
   bool unique = false;
-  bool multiEntry = false;
 
   // Get optional arguments.
   if (!JSVAL_IS_VOID(aOptions) && !JSVAL_IS_NULL(aOptions)) {
     if (JSVAL_IS_PRIMITIVE(aOptions)) {
       // XXX Update spec for a real code here
       return NS_ERROR_DOM_TYPE_ERR;
     }
 
@@ -1473,42 +1390,30 @@ IDBObjectStore::CreateIndex(const nsAStr
     }
 
     JSBool boolVal;
     if (!JS_ValueToBoolean(aCx, val, &boolVal)) {
       NS_WARNING("JS_ValueToBoolean failed!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
     unique = !!boolVal;
-
-    if (!JS_GetPropertyById(aCx, options, nsDOMClassInfo::sMultiEntry_id, &val)) {
-      NS_WARNING("JS_GetPropertyById failed!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-
-    if (!JS_ValueToBoolean(aCx, val, &boolVal)) {
-      NS_WARNING("JS_ValueToBoolean failed!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-    multiEntry = !!boolVal;
   }
 
   DatabaseInfo* databaseInfo = mTransaction->Database()->Info();
 
   IndexInfo* indexInfo = info->indexes.AppendElement();
   if (!indexInfo) {
     NS_WARNING("Out of memory!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   indexInfo->id = databaseInfo->nextIndexId++;
   indexInfo->name = aName;
   indexInfo->keyPath = aKeyPath;
   indexInfo->unique = unique;
-  indexInfo->multiEntry = multiEntry;
   indexInfo->autoIncrement = mAutoIncrement;
 
   // Don't leave this in the list if we fail below!
   AutoRemoveIndex autoRemove(mTransaction->Database(), mName, aName);
 
 #ifdef DEBUG
   for (PRUint32 index = 0; index < mCreatedIndexes.Length(); index++) {
     if (mCreatedIndexes[index]->Name() == aName) {
@@ -1620,24 +1525,16 @@ IDBObjectStore::DeleteIndex(const nsAStr
 
   nsRefPtr<DeleteIndexHelper> helper =
     new DeleteIndexHelper(mTransaction, aName, this);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   info->indexes.RemoveElementAt(index);
-
-  for (PRUint32 i = 0; i < mCreatedIndexes.Length(); i++) {
-    if (mCreatedIndexes[i]->Name() == aName) {
-      mCreatedIndexes.RemoveElementAt(i);
-      break;
-    }
-  }
-
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBObjectStore::Count(const jsval& aKey,
                       JSContext* aCx,
                       PRUint8 aOptionalArgCount,
                       nsIIDBRequest** _retval)
@@ -2258,19 +2155,18 @@ CreateIndexHelper::DestroyTLSEntry(void*
 
 nsresult
 CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   // Insert the data into the database.
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(
     "INSERT INTO object_store_index (id, name, key_path, unique_index, "
-      "multientry, object_store_id, object_store_autoincrement) "
-    "VALUES (:id, :name, :key_path, :unique, :multientry, :osid, "
-      ":os_auto_increment)"
+      "object_store_id, object_store_autoincrement) "
+    "VALUES (:id, :name, :key_path, :unique, :osid, :os_auto_increment)"
   );
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
                                       mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -2281,20 +2177,16 @@ CreateIndexHelper::DoDatabaseWork(mozISt
   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
                               mIndex->KeyPath());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("unique"),
                              mIndex->IsUnique() ? 1 : 0);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("multientry"),
-                             mIndex->IsMultiEntry() ? 1 : 0);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                              mIndex->ObjectStore()->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("os_auto_increment"),
                              mIndex->IsAutoIncrement() ? 1 : 0);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
@@ -2341,79 +2233,79 @@ CreateIndexHelper::InsertDataFromObjectS
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mIndex->ObjectStore()->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-  NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
   bool hasResult;
-  rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  if (!hasResult) {
-    // Bail early if we have no data to avoid creating the below runtime
-    return NS_OK;
-  }
-
-  ThreadLocalJSRuntime* tlsEntry =
-    reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
-
-  if (!tlsEntry) {
-    tlsEntry = ThreadLocalJSRuntime::Create();
-    NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    PR_SetThreadPrivate(sTLSIndex, tlsEntry);
-  }
-
-  JSContext* cx = tlsEntry->Context();
-  JSAutoRequest ar(cx);
-
-  do {
+  while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
+    nsCOMPtr<mozIStorageStatement> insertStmt =
+      mTransaction->IndexDataInsertStatement(mIndex->IsAutoIncrement(),
+                                             mIndex->IsUnique());
+    NS_ENSURE_TRUE(insertStmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    mozStorageStatementScoper scoper2(insertStmt);
+
+    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 (!mIndex->IsAutoIncrement()) {
+      NS_NAMED_LITERAL_CSTRING(objectDataKey, "object_data_key");
+
+      Key key;
+      rv = key.SetFromStatement(stmt, 2);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv =
+        key.BindToStatement(insertStmt, NS_LITERAL_CSTRING("object_data_key"));
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
     const PRUint8* data;
     PRUint32 dataLength;
     rv = stmt->GetSharedBlob(1, &dataLength, &data);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
-    jsval clone;
-    if (!JS_ReadStructuredClone(cx, reinterpret_cast<const uint64*>(data),
-                                dataLength, JS_STRUCTURED_CLONE_VERSION,
-                                &clone, NULL, NULL)) {
-      return NS_ERROR_DOM_DATA_CLONE_ERR;
+    NS_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+    ThreadLocalJSRuntime* tlsEntry =
+      reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
+
+    if (!tlsEntry) {
+      tlsEntry = ThreadLocalJSRuntime::Create();
+      NS_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+      PR_SetThreadPrivate(sTLSIndex, tlsEntry);
     }
 
-    nsTArray<IndexUpdateInfo> updateInfo;
-    rv = IDBObjectStore::AppendIndexUpdateInfo(mIndex->Id(),
-                                               mIndex->KeyPath(),
-                                               mIndex->IsUnique(),
-                                               mIndex->IsMultiEntry(),
-                                               tlsEntry->Context(),
-                                               clone, updateInfo);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    PRInt64 objectDataID = stmt->AsInt64(0);
-
     Key key;
-    if (!mIndex->IsAutoIncrement()) {
-      rv = key.SetFromStatement(stmt, 2);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    else {
-      key.SetFromInteger(objectDataID);
+    rv = IDBObjectStore::GetKeyPathValueFromStructuredData(data, dataLength,
+                                                           mIndex->KeyPath(),
+                                                           tlsEntry->Context(),
+                                                           key);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (key.IsUnset()) {
+      continue;
     }
 
-    rv = IDBObjectStore::UpdateIndexes(mTransaction, mIndex->Id(),
-                                       key, mIndex->IsAutoIncrement(),
-                                       false, objectDataID, updateInfo);
+    rv = key.BindToStatement(insertStmt, NS_LITERAL_CSTRING("value"));
     NS_ENSURE_SUCCESS(rv, rv);
 
-  } while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    rv = insertStmt->Execute();
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
 
   return NS_OK;
 }
 
 nsresult
 DeleteIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -71,23 +71,27 @@ public:
   static already_AddRefed<IDBObjectStore>
   Create(IDBTransaction* aTransaction,
          const ObjectStoreInfo* aInfo);
 
   static bool
   IsValidKeyPath(JSContext* aCx, const nsAString& aKeyPath);
 
   static nsresult
-  AppendIndexUpdateInfo(PRInt64 aIndexID,
-                        const nsAString& aKeyPath,
-                        bool aUnique,
-                        bool aMultiEntry,
-                        JSContext* aCx,
-                        jsval aObject,
-                        nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
+  GetKeyPathValueFromStructuredData(const PRUint8* aData,
+                                    PRUint32 aDataLength,
+                                    const nsAString& aKeyPath,
+                                    JSContext* aCx,
+                                    Key& aValue);
+
+  static nsresult
+  GetIndexUpdateInfo(ObjectStoreInfo* aObjectStoreInfo,
+                     JSContext* aCx,
+                     jsval aObject,
+                     nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
 
   static nsresult
   UpdateIndexes(IDBTransaction* aTransaction,
                 PRInt64 aObjectStoreId,
                 const Key& aObjectStoreKey,
                 bool aAutoIncrement,
                 bool aOverwrite,
                 PRInt64 aObjectDataId,
@@ -136,21 +140,16 @@ public:
     return mId;
   }
 
   const nsString& KeyPath() const
   {
     return mKeyPath;
   }
 
-  const bool HasKeyPath() const
-  {
-    return !mKeyPath.IsVoid();
-  }
-
   IDBTransaction* Transaction()
   {
     return mTransaction;
   }
 
   nsresult ModifyValueForNewKey(JSAutoStructuredCloneBuffer& aBuffer,
                                 Key& aKey,
                                 PRUint64 aOffsetToKeyProp);
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -209,27 +209,16 @@ IDBTransaction::OnRequestFinished()
     NS_ASSERTION(mAborted || mReadyState == nsIIDBTransaction::LOADING,
                  "Bad state!");
     mReadyState = IDBTransaction::COMMITTING;
     CommitOrRollback();
   }
 }
 
 void
-IDBTransaction::ReleaseCachedObjectStore(const nsAString& aName)
-{
-  for (PRUint32 i = 0; i < mCreatedObjectStores.Length(); i++) {
-    if (mCreatedObjectStores[i]->Name() == aName) {
-      mCreatedObjectStores.RemoveElementAt(i);
-      break;
-    }
-  }
-}
-
-void
 IDBTransaction::SetTransactionListener(IDBTransactionListener* aListener)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!mListener, "Shouldn't already have a listener!");
   mListener = aListener;
 }
 
 nsresult
@@ -412,30 +401,30 @@ IDBTransaction::IndexDataInsertStatement
     if (aUnique) {
       return GetCachedStatement(
         "INSERT INTO ai_unique_index_data "
           "(index_id, ai_object_data_id, value) "
         "VALUES (:index_id, :object_data_id, :value)"
       );
     }
     return GetCachedStatement(
-      "INSERT OR IGNORE INTO ai_index_data "
+      "INSERT INTO ai_index_data "
         "(index_id, ai_object_data_id, value) "
       "VALUES (:index_id, :object_data_id, :value)"
     );
   }
   if (aUnique) {
     return GetCachedStatement(
       "INSERT INTO unique_index_data "
         "(index_id, object_data_id, object_data_key, value) "
       "VALUES (:index_id, :object_data_id, :object_data_key, :value)"
     );
   }
   return GetCachedStatement(
-    "INSERT OR IGNORE INTO index_data ("
+    "INSERT INTO index_data ("
       "index_id, object_data_id, object_data_key, value) "
     "VALUES (:index_id, :object_data_id, :object_data_key, :value)"
   );
 }
 
 already_AddRefed<mozIStorageStatement>
 IDBTransaction::IndexDataDeleteStatement(bool aAutoIncrement,
                                          bool aUnique)
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -98,18 +98,16 @@ public:
          bool aDispatchDelayed);
 
   // nsIDOMEventTarget
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   void OnNewRequest();
   void OnRequestFinished();
 
-  void ReleaseCachedObjectStore(const nsAString& aName);
-
   void SetTransactionListener(IDBTransactionListener* aListener);
 
   bool StartSavepoint();
   nsresult ReleaseSavepoint();
   void RollbackSavepoint();
 
   // Only meant to be called on mStorageThread!
   nsresult GetOrCreateConnection(mozIStorageConnection** aConnection);
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -46,17 +46,17 @@
 #include "jsapi.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsDOMError.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
-#define DB_SCHEMA_VERSION 8
+#define DB_SCHEMA_VERSION 6
 
 #define BEGIN_INDEXEDDB_NAMESPACE \
   namespace mozilla { namespace dom { namespace indexedDB {
 
 #define END_INDEXEDDB_NAMESPACE \
   } /* namespace indexedDB */ } /* namepsace dom */ } /* namespace mozilla */
 
 #define USING_INDEXEDDB_NAMESPACE \
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -117,19 +117,19 @@ CreateTables(mozIStorageConnection* aDBC
     ");"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Table `object_store`
   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE object_store ("
       "id INTEGER PRIMARY KEY, "
+      "name TEXT NOT NULL, "
+      "key_path TEXT NOT NULL, "
       "auto_increment INTEGER NOT NULL DEFAULT 0, "
-      "name TEXT NOT NULL, "
-      "key_path TEXT, "
       "UNIQUE (name)"
     ");"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Table `object_data`
   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE object_data ("
@@ -160,17 +160,16 @@ CreateTables(mozIStorageConnection* aDBC
   // Table `index`
   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE object_store_index ("
       "id INTEGER, "
       "object_store_id INTEGER NOT NULL, "
       "name TEXT NOT NULL, "
       "key_path TEXT NOT NULL, "
       "unique_index INTEGER NOT NULL, "
-      "multientry INTEGER NOT NULL DEFAULT 0, "
       "object_store_autoincrement INTERGER NOT NULL, "
       "PRIMARY KEY (id), "
       "UNIQUE (object_store_id, name), "
       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
         "CASCADE"
     ");"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -750,159 +749,16 @@ UpgradeSchemaFrom5To6(mozIStorageConnect
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
-UpgradeSchemaFrom6To7(mozIStorageConnection* aConnection)
-{
-  mozStorageTransaction transaction(aConnection, false,
-                                 mozIStorageConnection::TRANSACTION_IMMEDIATE);
-
-  // Turn off foreign key constraints before we do anything here.
-  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "PRAGMA foreign_keys = OFF;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TEMPORARY TABLE temp_upgrade ("
-      "id, "
-      "name, "
-      "key_path, "
-      "auto_increment, "
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "INSERT INTO temp_upgrade "
-      "SELECT id, name, key_path, auto_increment "
-      "FROM object_store;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "DROP TABLE object_store;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE object_store ("
-      "id INTEGER PRIMARY KEY, "
-      "auto_increment INTEGER NOT NULL DEFAULT 0, "
-      "name TEXT NOT NULL, "
-      "key_path TEXT, "
-      "UNIQUE (name)"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "INSERT INTO object_store "
-      "SELECT id, auto_increment, name, nullif(key_path, '') "
-      "FROM temp_upgrade;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "DROP TABLE temp_upgrade;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->SetSchemaVersion(7);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = transaction.Commit();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-
-nsresult
-UpgradeSchemaFrom7To8(mozIStorageConnection* aConnection)
-{
-  mozStorageTransaction transaction(aConnection, false,
-                                 mozIStorageConnection::TRANSACTION_IMMEDIATE);
-
-  // Turn off foreign key constraints before we do anything here.
-  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "PRAGMA foreign_keys = OFF;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TEMPORARY TABLE temp_upgrade ("
-      "id, "
-      "object_store_id, "
-      "name, "
-      "key_path, "
-      "unique_index, "
-      "object_store_autoincrement, "
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "INSERT INTO temp_upgrade "
-      "SELECT id, object_store_id, name, key_path, "
-      "unique_index, object_store_autoincrement, "
-      "FROM object_store_index;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "DROP TABLE object_store_index;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE object_store_index ("
-      "id INTEGER, "
-      "object_store_id INTEGER NOT NULL, "
-      "name TEXT NOT NULL, "
-      "key_path TEXT NOT NULL, "
-      "unique_index INTEGER NOT NULL, "
-      "multientry INTEGER NOT NULL, "
-      "object_store_autoincrement INTERGER NOT NULL, "
-      "PRIMARY KEY (id), "
-      "UNIQUE (object_store_id, name), "
-      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
-        "CASCADE"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "INSERT INTO object_store_index "
-      "SELECT id, object_store_id, name, key_path, "
-      "unique_index, 0, object_store_autoincrement, "
-      "FROM temp_upgrade;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "DROP TABLE temp_upgrade;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aConnection->SetSchemaVersion(8);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = transaction.Commit();
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-nsresult
 CreateDatabaseConnection(const nsAString& aName,
                          nsIFile* aDBFile,
                          mozIStorageConnection** aConnection)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
   NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota");
 
@@ -943,33 +799,31 @@ CreateDatabaseConnection(const nsAString
     NS_ENSURE_SUCCESS(rv, rv);
 
     NS_ASSERTION(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)) &&
                  schemaVersion == DB_SCHEMA_VERSION,
                  "CreateTables set a bad schema version!");
   }
   else if (schemaVersion != DB_SCHEMA_VERSION) {
     // This logic needs to change next time we change the schema!
-    PR_STATIC_ASSERT(DB_SCHEMA_VERSION == 8);
+    PR_STATIC_ASSERT(DB_SCHEMA_VERSION == 6);
 
 #define UPGRADE_SCHEMA_CASE(_from, _to)                                        \
   if (schemaVersion == _from) {                                                \
     rv = UpgradeSchemaFrom##_from##To##_to (connection);                       \
     NS_ENSURE_SUCCESS(rv, rv);                                                 \
                                                                                \
     rv = connection->GetSchemaVersion(&schemaVersion);                         \
     NS_ENSURE_SUCCESS(rv, rv);                                                 \
                                                                                \
     NS_ASSERTION(schemaVersion == _to, "Bad upgrade function!");               \
   }
 
     UPGRADE_SCHEMA_CASE(4, 5)
     UPGRADE_SCHEMA_CASE(5, 6)
-    UPGRADE_SCHEMA_CASE(6, 7)
-    UPGRADE_SCHEMA_CASE(7, 8)
 
 #undef UPGRADE_SCHEMA_CASE
 
     if (schemaVersion != DB_SCHEMA_VERSION) {
       NS_WARNING("Unable to open IndexedDB database, schema doesn't match");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
--- a/dom/indexedDB/OpenDatabaseHelper.h
+++ b/dom/indexedDB/OpenDatabaseHelper.h
@@ -55,18 +55,18 @@ class OpenDatabaseHelper : public Helper
 public:
   OpenDatabaseHelper(IDBOpenDBRequest* aRequest,
                      const nsAString& aName,
                      const nsACString& aASCIIOrigin,
                      PRUint64 aRequestedVersion,
                      bool aForDeletion)
     : HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
       mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
-      mForDeletion(aForDeletion), mDatabaseId(nsnull), mCurrentVersion(0),
-      mDataVersion(DB_SCHEMA_VERSION), mLastObjectStoreId(0),
+      mForDeletion(aForDeletion), mCurrentVersion(0),
+      mDataVersion(DB_SCHEMA_VERSION), mDatabaseId(0), mLastObjectStoreId(0),
       mLastIndexId(0), mState(eCreated), mResultCode(NS_OK)
   {
     NS_ASSERTION(!aForDeletion || !aRequestedVersion,
                  "Can't be for deletion and request a version!");
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
--- a/dom/indexedDB/nsIIDBIndex.idl
+++ b/dom/indexedDB/nsIIDBIndex.idl
@@ -42,29 +42,27 @@
 interface nsIIDBObjectStore;
 interface nsIIDBRequest;
 
 /**
  * IDBIndex interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBIndex for more
  * information.
  */
-[scriptable, builtinclass, uuid(fcb9a158-833e-4aa9-ab19-ab90cbb50afc)]
+[scriptable, builtinclass, uuid(1da60889-3db4-4f66-9fd7-b78c1e7969b7)]
 interface nsIIDBIndex : nsISupports
 {
   readonly attribute DOMString name;
 
   readonly attribute DOMString storeName;
 
   readonly attribute DOMString keyPath;
 
   readonly attribute boolean unique;
 
-  readonly attribute boolean multiEntry;
-
   readonly attribute nsIIDBObjectStore objectStore;
 
   [implicit_jscontext]
   nsIIDBRequest
   get(in jsval key);
 
   [implicit_jscontext]
   nsIIDBRequest
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -79,17 +79,16 @@ TEST_FILES = \
   test_index_getAll.html \
   test_index_getAllObjects.html \
   test_index_object_cursors.html \
   test_index_update_delete.html \
   test_indexes.html \
   test_indexes_bad_values.html \
   test_key_requirements.html \
   test_leaving_page.html \
-  test_multientry.html \
   test_objectCursors.html \
   test_objectStore_inline_autoincrement_key_added_on_put.html \
   test_objectStore_remove_values.html \
   test_object_identity.html \
   test_odd_result_order.html \
   test_open_empty_db.html \
   test_open_objectStore.html \
   test_optionalArguments.html \
--- a/dom/indexedDB/test/test_complex_keyPaths.html
+++ b/dom/indexedDB/test/test_complex_keyPaths.html
@@ -13,197 +13,160 @@
     function testSteps()
     {
       const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
       const nsIIDBTransaction = Components.interfaces.nsIIDBTransaction;
 
       // Test object stores
 
       const name = window.location.pathname;
-      const keyPaths = [
-        { keyPath: "id",      value: { id: 5 },                      key: 5 },
-        { keyPath: "id",      value: { id: "14", iid: 12 },          key: "14" },
-        { keyPath: "id",      value: { iid: "14", id: 12 },          key: 12 },
-        { keyPath: "id",      value: {} },
-        { keyPath: "id",      value: { id: {} } },
-        { keyPath: "id",      value: { id: /x/ } },
-        { keyPath: "id",      value: 2 },
-        { keyPath: "id",      value: undefined },
-        { keyPath: "foo.id",  value: { foo: { id: 7 } },             key: 7 },
-        { keyPath: "foo.id",  value: { id: 7, foo: { id: "asdf" } }, key: "asdf" },
-        { keyPath: "foo.id",  value: { foo: { id: undefined } } },
-        { keyPath: "foo.id",  value: { foo: 47 } },
-        { keyPath: "foo.id",  value: {} },
-        { keyPath: "",        value: "foopy",                        key: "foopy" },
-        { keyPath: "",        value: 2,                              key: 2 },
-        { keyPath: "",        value: undefined },
-        { keyPath: "",        value: { id: 12 } },
-        { keyPath: "",        value: /x/ },
-        { keyPath: "foo.bar", value: { baz: 1, foo: { baz2: 2, bar: "xo" } },     key: "xo" },
-        { keyPath: "foo.bar.baz", value: { foo: { bar: { bazz: 16, baz: 17 } } }, key: 17 },
-        { keyPath: "foo..id", exception: true },
-        { keyPath: "foo.",    exception: true },
-        { keyPath: "fo o",    exception: true },
-        { keyPath: "foo ",    exception: true },
-        { keyPath: "foo[bar]",exception: true },
-        { keyPath: "$('id').stuff", exception: true },
-        { keyPath: "foo.2.bar", exception: true },
-        { keyPath: "foo. .bar", exception: true },
-        { keyPath: ".bar",    exception: true },
+      const objectStoreInfo = [
+        { name: "a", options: { keyPath: "id"} },
+        { name: "b", options: { keyPath: "foo.id"} },
+        { name: "c", options: { keyPath: ""} },
+        { name: "d", options: { keyPath: "foo..id"}, exception: true },
+        { name: "e", options: { keyPath: "foo."}, exception: true },
+        { name: "f", options: { keyPath: "foo.bar" } },
+        { name: "g", options: { keyPath: "fo o" }, exception: true},
+        { name: "h", options: { keyPath: "foo " }, exception: true},
+        { name: "i", options: { keyPath: "foo[bar]" }, exception: true },
+        { name: "j", options: { keyPath: "$('id').stuff" }, exception: true },
+        { name: "k", options: { keyPath: "foo.2.bar" }, exception: true }
       ];
 
-      let openRequest = mozIndexedDB.open(name, 1);
-      openRequest.onerror = errorHandler;
-      openRequest.onupgradeneeded = grabEventAndContinueHandler;
-      openRequest.onsuccess = unexpectedSuccessHandler;
+      const indexInfo = [
+        { name: "1", keyPath: "id" },
+        { name: "2", keyPath: "foo..id", exception: true },
+        { name: "3", keyPath: "foo.", exception: true },
+        { name: "4", keyPath: "foo.baz" },
+        { name: "5", keyPath: "fo o", exception: true },
+        { name: "6", keyPath: "foo ", exception: true },
+        { name: "7", keyPath: "foo[bar]", exception: true },
+        { name: "8", keyPath: "$('id').stuff", exception: true },
+        { name: "9", keyPath: "foo.2.bar", exception: true },
+        { name: "10", keyPath: "foo.bork" },
+      ];
+
+      let request = mozIndexedDB.open(name, 1);
+      request.onerror = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      request.onsuccess = unexpectedSuccessHandler;
       let event = yield;
       let db = event.target.result;
 
-      let stores = {};
-
-      // Test creating object stores and inserting data
-      for (let i = 0; i < keyPaths.length; i++) {
-        let info = keyPaths[i];
-        test = " for " + JSON.stringify(info);
-        if (!stores[info.keyPath]) {
-          try {
-            let objectStore = db.createObjectStore(info.keyPath, { keyPath: info.keyPath });
-            ok(!("exception" in info), "expected exception behavior observed" + test);
-            is(objectStore.keyPath, info.keyPath, "objectStore has correct keyPath property" + test);
-            stores[info.keyPath] = objectStore;
-          } catch (e) {
-            ok("exception" in info, "expected exception behavior observed" + test);
-            ok(e instanceof DOMException, "Got a DOM Exception" + test);
-            is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error" + test);
-            continue;
-          }
+      for (let i = 0; i < objectStoreInfo.length; i++) {
+        let info = objectStoreInfo[i];
+        try {
+          let objectStore = info.hasOwnProperty("options") ?
+                            db.createObjectStore(info.name, info.options) :
+                            db.createObjectStore(info.name);
+          ok(!info.hasOwnProperty("exception"), "expected exception behavior observed");
+        } catch (e) {
+          ok(info.hasOwnProperty("exception"), "expected exception behavior observed");
+          ok(e instanceof DOMException, "Got a DOM Exception");
+          is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error");
         }
+      }
 
-        let store = stores[info.keyPath];
+      request.onsuccess = grabEventAndContinueHandler;
+      yield;
+
+      let trans = db.transaction(["f"], IDBTransaction.READ_WRITE);
+      let objectStore = trans.objectStore("f");
 
-        try {
-          request = store.add(info.value);
-          ok("key" in info, "successfully created request to insert value" + test);
-        } catch (e) {
-          ok(!("key" in info), "threw when attempted to insert" + test);
-          ok(e instanceof IDBDatabaseException, "Got a IDBDatabaseException" + test);
-          is(e.code, IDBDatabaseException.DATA_ERR, "expect a DATA_ERR error" + test);
-          continue;
-        }
+      objectStore.put({foo: {baz: -1, bar: 72, bork: true}});
+      objectStore.put({foo: {baz: 2, bar: 1, bork: false}});
 
-        request.onerror = errorHandler;
-        request.onsuccess = grabEventAndContinueHandler;
-
-        let e = yield;
-        is(e.type, "success", "inserted successfully" + test);
-        is(e.target, request, "expected target" + test);
-        is(request.result, info.key, "found correct key" + test);
-
-        store.clear().onsuccess = grabEventAndContinueHandler;
-        yield;
+      try {
+        objectStore.put({foo: {}});
+        ok(false, "Should have thrown!");
+      } catch (e) {
+        ok(true, "Putting an object without the key should throw");
       }
 
-      // Attempt to create indexes and insert data
-      let store = db.createObjectStore("indexStore");
-      let indexes = {};
-      for (let i = 0; i < keyPaths.length; i++) {
-        let info = keyPaths[i];
-        if (!indexes[info.keyPath]) {
-          try {
-            let index = store.createIndex(info.keyPath, info.keyPath);
-            ok(!("exception" in info), "expected exception behavior observed");
-            is(index.keyPath, info.keyPath, "index has correct keyPath property");
-            indexes[info.keyPath] = index;
-          } catch (e) {
-            ok("exception" in info, "expected exception behavior observed");
-            ok(e instanceof DOMException, "Got a DOM Exception");
-            is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error");
-            continue;
-          }
-        }
-        
-        let index = indexes[info.keyPath];
+      trans.onerror = errorHandler;
+      trans.oncomplete = grabEventAndContinueHandler;
+
+      yield;
+
+      let trans = db.transaction(["f"], IDBTransaction.READ);
+      let objectStore = trans.objectStore("f");
+      let request = objectStore.openCursor();
+
+      request.onerror = errorHandler;
+      request.onsuccess = grabEventAndContinueHandler;
+
+      let event = yield;
+
+      let cursor = event.target.result;
+      is(cursor.value.foo.baz, 2, "got things in the right order");
+
+      cursor.continue();
 
-        request = store.add(info.value, 1);
-        if ("key" in info) {
-          index.getKey(info.key).onsuccess = grabEventAndContinueHandler;
-          e = yield;
-          is(e.target.result, 1, "found value when reading from index");
-        }
-        else {
-          index.count().onsuccess = grabEventAndContinueHandler;
-          e = yield;
-          is(e.target.result, 0, "index should be empty");
-        }
+      let event = yield
+
+      let cursor = event.target.result;
+      is(cursor.value.foo.baz, -1, "got things in the right order");
+
+      db.close();
+
+      // Test indexes
 
-        store.clear().onsuccess = grabEventAndContinueHandler;
-        yield;
-      }
+      let request = mozIndexedDB.open(name, 2);
+      request.onerror = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+
+      let event = yield;
+      let db = event.target.result;
+
+      let trans = event.target.transaction;
+      let objectStore = trans.objectStore("f");
 
-      // Autoincrement and complex key paths
-      let aitests = [{ v: {},                           k: 1, res: { foo: { id: 1 }} },
-                     { v: { value: "x" },               k: 2, res: { value: "x", foo: { id: 2 }} },
-                     { v: { value: "x", foo: {} },      k: 3, res: { value: "x", foo: { id: 3 }} },
-                     { v: { v: "x", foo: { x: "y" } },  k: 4, res: { v: "x", foo: { x: "y", id: 4 }} },
-                     { v: { value: 2, foo: { id: 10 }}, k: 10 },
-                     { v: { value: 2 },                 k: 11, res: { value: 2, foo: { id: 11 }} },
-                     { v: true,                         },
-                     { v: { value: 2, foo: 12 },        },
-                     { v: { foo: { id: true }},         },
-                     { v: { foo: { x: 5, id: {} }},     },
-                     { v: undefined,                    },
-                     { v: { foo: undefined },           },
-                     { v: { foo: { id: undefined }},    },
-                     { v: null,                         },
-                     { v: { foo: null },                },
-                     { v: { foo: { id: null }},         },
-                     ];
-
-      store = db.createObjectStore("gen", { keyPath: "foo.id", autoIncrement: true });
-      for (let i = 0; i < aitests.length; ++i) {
-        let test = aitests[i];
-
-        let preValue = JSON.stringify(test.v);
+      let indexes = [];
+      for (let i = 0; i < indexInfo.length; i++) {
+        let info = indexInfo[i];
         try {
-          store.add(test.v).onsuccess = grabEventAndContinueHandler;
-          ok("k" in test, "shouldn't have thrown");
-          is(JSON.stringify(test.v), preValue, "put didn't modify value");
+          indexes[i] = info.hasOwnProperty("options") ?
+                       objectStore.createIndex(info.name, info.keyPath, info.options) :
+                       objectStore.createIndex(info.name, info.keyPath);
+          ok(!info.hasOwnProperty("exception"), "expected exception behavior observed");
+        } catch (e) {
+          ok(info.hasOwnProperty("exception"), "expected exception behavior observed");
+          ok(e instanceof DOMException, "Got a DOM Exception");
+          is(e.code, DOMException.SYNTAX_ERR, "expect a syntax error");
         }
-        catch(e) {
-          ok(!("k" in test), "expected exception behavior observed");
-          ok(e instanceof IDBDatabaseException, "Got a IDBDatabaseException");
-          is(e.code, IDBDatabaseException.DATA_ERR, "expect a DATA_ERR");
+      }
+      request.onsuccess = grabEventAndContinueHandler;
+
+      yield;
 
-          is(JSON.stringify(test.v), preValue, "put didn't modify value");
+      let trans = db.transaction(["f"], IDBTransaction.READ);
+      let objectStore = trans.objectStore("f");
 
-          continue;
-        }
+      let request = objectStore.index("4").openCursor();
+      request.onsuccess = grabEventAndContinueHandler;
 
-        let e = yield;
-        is(e.target.result, test.k, "got correct return key");
+      let event = yield;
+
+      let cursor = event.target.result;
 
-        store.get(test.k).onsuccess = grabEventAndContinueHandler;
-        e = yield;
-        is(JSON.stringify(e.target.result), JSON.stringify(test.res || test.v),
-           "expected value stored");
-      }
+      is(cursor.value.foo.bar, 72, "got things in the right order");
+
+      cursor.continue();
+      yield;
+
+      is(cursor.value.foo.bar, 1, "got things in the right order");
 
-      // Can't handle autoincrement and empty keypath
-      try {
-        store = db.createObjectStore("storefail", { keyPath: "", autoIncrement: true });
-        ok(false, "Should have thrown");
-      }
-      catch(e) {
-        ok(true, "Did throw");
-        ok(e instanceof DOMException, "Got a DOMException");
-        is(e.code, DOMException.INVALID_ACCESS_ERR, "expect a INVALID_ACCESS_ERR");
-      }
+      let request = objectStore.index("10").openCursor();
+      request.onerror = errorHandler;
+      request.onsuccess = grabEventAndContinueHandler;
 
-      openRequest.onsuccess = grabEventAndContinueHandler;
-      yield;
+      let event = yield;
+
+      is(event.target.result, null, "should have no results");
 
       finishTest();
       yield;
     }
   </script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 </head>
 
--- a/dom/indexedDB/test/test_create_objectStore.html
+++ b/dom/indexedDB/test/test_create_objectStore.html
@@ -81,17 +81,17 @@
             found = true;
             break;
           }
         }
         is(found, true, "objectStoreNames contains name");
 
         is(objectStore.name, name, "Bad name");
         is(objectStore.keyPath, info.options && info.options.keyPath ?
-                                info.options.keyPath : null,
+                                info.options.keyPath : "",
            "Bad keyPath");
         if(objectStore.indexNames.length, 0, "Bad indexNames");
 
         ok(event.target.transaction, "event has a transaction");
         ok(event.target.transaction.db === db, "transaction has the right db");
         is(event.target.transaction.readyState, nsIIDBTransaction.LOADING,
            "transaction has the correct readyState");
         is(event.target.transaction.mode, nsIIDBTransaction.VERSION_CHANGE,
deleted file mode 100644
--- a/dom/indexedDB/test/test_multientry.html
+++ /dev/null
@@ -1,230 +0,0 @@
-<!--
-  Any copyright is dedicated to the Public Domain.
-  http://creativecommons.org/publicdomain/zero/1.0/
--->
-<html>
-<head>
-  <title>Indexed Database Property Test</title>
-
-  <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()
-    {
-      // Test object stores
-
-      let openRequest = mozIndexedDB.open(window.location.pathname, 1);
-      openRequest.onerror = errorHandler;
-      openRequest.onupgradeneeded = grabEventAndContinueHandler;
-      openRequest.onsuccess = unexpectedSuccessHandler;
-      let event = yield;
-      let db = event.target.result;
-      db.onerror = errorHandler;
-      let tests =
-        [{ add:     { x: 1, id: 1 },
-           indexes:[{ v: 1, k: 1 }] },
-         { add:     { x: [2, 3], id: 2 },
-           indexes:[{ v: 1, k: 1 },
-                    { v: 2, k: 2 },
-                    { v: 3, k: 2 }] },
-         { put:     { x: [2, 4], id: 1 },
-           indexes:[{ v: 2, k: 1 },
-                    { v: 2, k: 2 },
-                    { v: 3, k: 2 },
-                    { v: 4, k: 1 }] },
-         { add:     { x: [5, 6, 5, -2, 3], id: 3 },
-           indexes:[{ v:-2, k: 3 },
-                    { v: 2, k: 1 },
-                    { v: 2, k: 2 },
-                    { v: 3, k: 2 },
-                    { v: 3, k: 3 },
-                    { v: 4, k: 1 },
-                    { v: 5, k: 3 },
-                    { v: 6, k: 3 }] },
-         { delete:  IDBKeyRange.bound(1, 3),
-           indexes:[] },
-         { put:     { x: ["food", {}, false, undefined, /x/, [73, false]], id: 2 },
-           indexes:[{ v: "food", k: 2 }] },
-         { add:     { x: [{}, /x/, -12, "food", null, [false], undefined], id: 3 },
-           indexes:[{ v: -12, k: 3 },
-                    { v: "food", k: 2 },
-                    { v: "food", k: 3 }] },
-         { put:     { x: [], id: 2 },
-           indexes:[{ v: -12, k: 3 },
-                    { v: "food", k: 3 }] },
-         { put:     { x: { y: 3 }, id: 3 },
-           indexes:[] },
-         { add:     { x: false, id: 7 },
-           indexes:[] },
-         { delete:  IDBKeyRange.lowerBound(0),
-           indexes:[] },
-        ];
-
-      let store = db.createObjectStore("mystore", { keyPath: "id" });
-      let index = store.createIndex("myindex", "x", { multiEntry: true });
-      is(index.multiEntry, true, "index created with multiEntry");
-
-      let i;
-      for (i = 0; i < tests.length; ++i) {
-        let test = tests[i];
-        let testName = " for " + JSON.stringify(test);
-        let req;
-        if (test.add) {
-          req = store.add(test.add);
-        }
-        else if (test.put) {
-          req = store.put(test.put);
-        }
-        else if (test.delete) {
-          req = store.delete(test.delete);
-        }
-        else {
-          ok(false, "borked test");
-        }
-        req.onsuccess = grabEventAndContinueHandler;
-        let e = yield;
-        
-        req = index.openKeyCursor();
-        req.onsuccess = grabEventAndContinueHandler;
-        for (let j = 0; j < test.indexes.length; ++j) {
-          e = yield;
-          is(req.result.key, test.indexes[j].v, "found expected index key at index " + j + testName);
-          is(req.result.primaryKey, test.indexes[j].k, "found expected index primary key at index " + j + testName);
-          req.result.continue();
-        }
-        e = yield;
-        is(req.result, undefined, "exhausted indexes");
-
-        let tempIndex = store.createIndex("temp index", "x", { multiEntry: true });
-        req = tempIndex.openKeyCursor();
-        req.onsuccess = grabEventAndContinueHandler;
-        for (let j = 0; j < test.indexes.length; ++j) {
-          e = yield;
-          is(req.result.key, test.indexes[j].v, "found expected temp index key at index " + j + testName);
-          is(req.result.primaryKey, test.indexes[j].k, "found expected temp index primary key at index " + j + testName);
-          req.result.continue();
-        }
-        e = yield;
-        is(req.result, undefined, "exhausted temp index");
-        store.deleteIndex("temp index");
-      }
-
-      // Unique indexes
-      tests =
-        [{ add:     { x: 1, id: 1 },
-           indexes:[{ v: 1, k: 1 }] },
-         { add:     { x: [2, 3], id: 2 },
-           indexes:[{ v: 1, k: 1 },
-                    { v: 2, k: 2 },
-                    { v: 3, k: 2 }] },
-         { put:     { x: [2, 4], id: 3 },
-           fail:    true },
-         { put:     { x: [1, 4], id: 1 },
-           indexes:[{ v: 1, k: 1 },
-                    { v: 2, k: 2 },
-                    { v: 3, k: 2 },
-                    { v: 4, k: 1 }] },
-         { add:     { x: [5, 0, 5, 5, 5], id: 3 },
-           indexes:[{ v: 0, k: 3 },
-                    { v: 1, k: 1 },
-                    { v: 2, k: 2 },
-                    { v: 3, k: 2 },
-                    { v: 4, k: 1 },
-                    { v: 5, k: 3 }] },
-         { delete:  IDBKeyRange.bound(1, 2),
-           indexes:[{ v: 0, k: 3 },
-                    { v: 5, k: 3 }] },
-         { add:     { x: [0, 6], id: 8 },
-           fail:    true },
-         { add:     { x: 5, id: 8 },
-           fail:    true },
-         { put:     { x: 0, id: 8 },
-           fail:    true },
-        ];
-
-      store.deleteIndex("myindex");
-      index = store.createIndex("myindex", "x", { multiEntry: true, unique: true });
-      is(index.multiEntry, true, "index created with multiEntry");
-
-      let i;
-      let indexes;
-      for (i = 0; i < tests.length; ++i) {
-        let test = tests[i];
-        let testName = " for " + JSON.stringify(test);
-        let req;
-        if (test.add) {
-          req = store.add(test.add);
-        }
-        else if (test.put) {
-          req = store.put(test.put);
-        }
-        else if (test.delete) {
-          req = store.delete(test.delete);
-        }
-        else {
-          ok(false, "borked test");
-        }
-        
-        if (!test.fail) {
-          req.onsuccess = grabEventAndContinueHandler;
-          let e = yield;
-          indexes = test.indexes;
-        }
-        else {
-          req.onsuccess = unexpectedSuccessHandler;
-          req.onerror = grabEventAndContinueHandler;
-          ok(true, "waiting for error");
-          let e = yield;
-          ok(true, "got error: " + e.type);
-          e.preventDefault();
-          e.stopPropagation();
-        }
-
-        let e;
-        req = index.openKeyCursor();
-        req.onsuccess = grabEventAndContinueHandler;
-        for (let j = 0; j < indexes.length; ++j) {
-          e = yield;
-          is(req.result.key, indexes[j].v, "found expected index key at index " + j + testName);
-          is(req.result.primaryKey, indexes[j].k, "found expected index primary key at index " + j + testName);
-          req.result.continue();
-        }
-        e = yield;
-        is(req.result, undefined, "exhausted indexes");
-
-        let tempIndex = store.createIndex("temp index", "x", { multiEntry: true, unique: true });
-        req = tempIndex.openKeyCursor();
-        req.onsuccess = grabEventAndContinueHandler;
-        for (let j = 0; j < indexes.length; ++j) {
-          e = yield;
-          is(req.result.key, indexes[j].v, "found expected temp index key at index " + j + testName);
-          is(req.result.primaryKey, indexes[j].k, "found expected temp index primary key at index " + j + testName);
-          req.result.continue();
-        }
-        e = yield;
-        is(req.result, undefined, "exhausted temp index");
-        store.deleteIndex("temp index");
-      }
-
-
-      openRequest.onsuccess = grabEventAndContinueHandler;
-      yield;
-
-      let trans = db.transaction(["mystore"], IDBTransaction.READ_WRITE);
-      store = trans.objectStore("mystore");
-      index = store.index("myindex");
-      is(index.multiEntry, true, "index still is multiEntry");
-      trans.oncomplete = grabEventAndContinueHandler;
-      yield;
-
-      finishTest();
-      yield;
-    }
-  </script>
-  <script type="text/javascript;version=1.7" src="helpers.js"></script>
-</head>
-
-<body onload="runTest();"></body>
-
-</html>
--- a/dom/indexedDB/test/test_remove_index.html
+++ b/dom/indexedDB/test/test_remove_index.html
@@ -27,40 +27,24 @@
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
       let objectStore = db.createObjectStore("test store", { keyPath: "foo" });
       is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
       is(db.objectStoreNames.item(0), objectStore.name, "Correct name");
 
       is(objectStore.indexNames.length, 0, "Correct indexNames list");
 
-      let index = objectStore.createIndex(indexName, "foo");
+      objectStore.createIndex(indexName, "foo");
 
       is(objectStore.indexNames.length, 1, "Correct indexNames list");
       is(objectStore.indexNames.item(0), indexName, "Correct name");
-      is(objectStore.index(indexName), index, "Correct instance");
 
       objectStore.deleteIndex(indexName);
 
       is(objectStore.indexNames.length, 0, "Correct indexNames list");
-      try {
-        objectStore.index(indexName);
-        ok(false, "should have thrown");
-      }
-      catch(ex) {
-        ok(ex instanceof IDBDatabaseException, "Got a IDBDatabaseException");
-        is(ex.code, IDBDatabaseException.NOT_FOUND_ERR, "expect a NOT_FOUND_ERR");
-      }
-
-      let index2 = objectStore.createIndex(indexName, "foo");
-      isnot(index, index2, "New instance should be created");
-
-      is(objectStore.indexNames.length, 1, "Correct recreacted indexNames list");
-      is(objectStore.indexNames.item(0), indexName, "Correct recreacted name");
-      is(objectStore.index(indexName), index2, "Correct instance");
 
       finishTest();
       yield;
     }
   </script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
--- a/dom/indexedDB/test/test_remove_objectStore.html
+++ b/dom/indexedDB/test/test_remove_objectStore.html
@@ -50,36 +50,23 @@
       db.close();
 
       let request = mozIndexedDB.open(name, 2, description);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
-      let trans = event.target.transaction;
 
-      let oldObjectStore = trans.objectStore(objectStoreName);
-      isnot(oldObjectStore, null, "Correct object store prior to deleting");
-      db.deleteObjectStore(objectStoreName);
+      db.deleteObjectStore(objectStore.name);
       is(db.objectStoreNames.length, 0, "Correct objectStores list");
-      try {
-        trans.objectStore(objectStoreName);
-        ok(false, "should have thrown");
-      }
-      catch(ex) {
-        ok(ex instanceof IDBDatabaseException, "Got a IDBDatabaseException");
-        is(ex.code, IDBDatabaseException.NOT_FOUND_ERR, "expect a NOT_FOUND_ERR");
-      }
 
       objectStore = db.createObjectStore(objectStoreName, { keyPath: "foo" });
       is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
       is(db.objectStoreNames.item(0), objectStoreName, "Correct name");
-      is(trans.objectStore(objectStoreName), objectStore, "Correct new objectStore");
-      isnot(oldObjectStore, objectStore, "Old objectStore is not new objectStore");
 
       request = objectStore.openCursor();
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
         is(event.target.result, undefined, "ObjectStore shouldn't have any items");
         testGenerator.send(event);
       }
       event = yield;
--- a/dom/indexedDB/test/test_transaction_abort.html
+++ b/dom/indexedDB/test/test_transaction_abort.html
@@ -52,17 +52,17 @@
       is(transaction.mode, VERSION_CHANGE, "Correct mode");
       is(transaction.objectStoreNames.length, 1, "Correct names length");
       is(transaction.objectStoreNames.item(0), "foo", "Correct name");
       is(transaction.objectStore("foo"), objectStore, "Can get stores");
       is(transaction.oncomplete, null, "No complete listener");
       is(transaction.onabort, null, "No abort listener");
 
       is(objectStore.name, "foo", "Correct name");
-      is(objectStore.keyPath, null, "Correct keyPath");
+      is(objectStore.keyPath, "", "Correct keyPath");
 
       is(objectStore.indexNames.length, 1, "Correct indexNames length");
       is(objectStore.indexNames[0], "fooindex", "Correct indexNames name");
       is(objectStore.index("fooindex"), index, "Can get index");
 
       // Wait until it's complete!
       transaction.oncomplete = grabEventAndContinueHandler;
       event = yield;
@@ -78,17 +78,17 @@
         is(transaction.objectStore("foo").name, "foo", "Can't get stores");
         ok(false, "Should have thrown");
       }
       catch (e) {
         ok(true, "Out of scope transaction can't make stores");
       }
 
       is(objectStore.name, "foo", "Correct name");
-      is(objectStore.keyPath, null, "Correct keyPath");
+      is(objectStore.keyPath, "", "Correct keyPath");
 
       is(objectStore.indexNames.length, 1, "Correct indexNames length");
       is(objectStore.indexNames[0], "fooindex", "Correct indexNames name");
 
       try {
         objectStore.add({});
         ok(false, "Should have thrown");
       }