Bug 701772: Manage autoIncrement for objectStores ourselves in order to simplify the code, make ai-keys unique per objectStore and not per database, and allow ai-objectStores to contain non-integer keys. r=bent
☠☠ backed out by 5db46b0c2f14 ☠ ☠
authorJonas Sicking <jonas@sicking.cc>
Fri, 16 Dec 2011 12:29:15 -0800
changeset 82812 fb4d12d2a2dafb62a820dafda7e5fc231ffb5179
parent 82811 a658b1e5d56ba9e6beb98299f8e8ae9bf2760561
child 82813 61a46d539c69e9ff34a02074c1d83ae96ea84ab8
push id21705
push usermbrubeck@mozilla.com
push dateSat, 17 Dec 2011 17:01:50 +0000
treeherdermozilla-central@d4aad9645f77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbent
bugs701772
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
Bug 701772: Manage autoIncrement for objectStores ourselves in order to simplify the code, make ai-keys unique per objectStore and not per database, and allow ai-objectStores to contain non-integer keys. r=bent
dom/indexedDB/DatabaseInfo.cpp
dom/indexedDB/DatabaseInfo.h
dom/indexedDB/IDBDatabase.cpp
dom/indexedDB/IDBFactory.cpp
dom/indexedDB/IDBFactory.h
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/IndexedDatabaseManager.cpp
dom/indexedDB/Key.h
dom/indexedDB/OpenDatabaseHelper.cpp
dom/indexedDB/OpenDatabaseHelper.h
dom/indexedDB/nsIIDBObjectStore.idl
dom/indexedDB/test/Makefile.in
dom/indexedDB/test/error_events_abort_transactions_iframe.html
dom/indexedDB/test/helpers.js
dom/indexedDB/test/test_add_put.html
dom/indexedDB/test/test_autoIncrement.html
dom/indexedDB/test/test_autoIncrement_indexes.html
dom/indexedDB/test/test_setVersion_abort.html
--- a/dom/indexedDB/DatabaseInfo.cpp
+++ b/dom/indexedDB/DatabaseInfo.cpp
@@ -66,79 +66,77 @@ EnumerateObjectStoreNames(const nsAStrin
 
 PLDHashOperator
 CloneObjectStoreInfo(const nsAString& aKey,
                      ObjectStoreInfo* aData,
                      void* aUserArg)
 {
   ObjectStoreInfoHash* hash = static_cast<ObjectStoreInfoHash*>(aUserArg);
 
-  nsAutoPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo(*aData));
+  nsRefPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo(*aData));
 
   if (!hash->Put(aKey, newInfo)) {
     NS_WARNING("Out of memory?");
     return PL_DHASH_STOP;
   }
 
-  newInfo.forget();
   return PL_DHASH_NEXT;
 }
 
 }
 
 DatabaseInfo::~DatabaseInfo()
 {
   // Clones are never in the hash.
   if (!cloned) {
     DatabaseInfo::Remove(id);
   }
 }
 
+ObjectStoreInfo::ObjectStoreInfo(ObjectStoreInfo& aOther)
+: name(aOther.name),
+  id(aOther.id),
+  keyPath(aOther.keyPath),
+  indexes(aOther.indexes),
+  nextAutoIncrementId(aOther.nextAutoIncrementId),
+  comittedAutoIncrementId(aOther.comittedAutoIncrementId)
+{
+  // Doesn't copy the refcount
+  MOZ_COUNT_CTOR(ObjectStoreInfo);
+}
+
 #ifdef NS_BUILD_REFCNT_LOGGING
 
 IndexInfo::IndexInfo()
 : id(LL_MININT),
   unique(false),
-  autoIncrement(false),
   multiEntry(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)
 {
   MOZ_COUNT_CTOR(IndexInfo);
 }
 
 IndexInfo::~IndexInfo()
 {
   MOZ_COUNT_DTOR(IndexInfo);
 }
 
 ObjectStoreInfo::ObjectStoreInfo()
 : id(0),
-  autoIncrement(false),
-  databaseId(0)
-{
-  MOZ_COUNT_CTOR(ObjectStoreInfo);
-}
-
-ObjectStoreInfo::ObjectStoreInfo(ObjectStoreInfo& aOther)
-: name(aOther.name),
-  id(aOther.id),
-  keyPath(aOther.keyPath),
-  autoIncrement(aOther.autoIncrement),
-  databaseId(aOther.databaseId),
-  indexes(aOther.indexes)
+  nextAutoIncrementId(0),
+  comittedAutoIncrementId(0)
 {
   MOZ_COUNT_CTOR(ObjectStoreInfo);
 }
 
 ObjectStoreInfo::~ObjectStoreInfo()
 {
   MOZ_COUNT_DTOR(ObjectStoreInfo);
 }
@@ -201,31 +199,51 @@ DatabaseInfo::Put(DatabaseInfo* aInfo)
 }
 
 // static
 void
 DatabaseInfo::Remove(nsIAtom* aId)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  DatabaseInfo* info = nsnull;
-
-  DebugOnly<bool> got = Get(aId, &info);
-  NS_ASSERTION(got && info, "Don't know anything about this one!");
-
   if (gDatabaseHash) {
     gDatabaseHash->Remove(aId);
 
     if (!gDatabaseHash->Count()) {
       delete gDatabaseHash;
       gDatabaseHash = nsnull;
     }
   }
 }
 
+PLDHashOperator
+EnumerateDatabasesRemoveOrigin(nsISupports* aId,
+                               DatabaseInfo*& aDatabaseInfo,
+                               void* aUserArg)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  const nsACString* origin = static_cast<const nsACString*>(aUserArg);
+  return aDatabaseInfo->origin.Equals(*origin) ?
+    PL_DHASH_REMOVE :
+    PL_DHASH_NEXT;
+}
+
+// static
+void
+DatabaseInfo::RemoveAllForOrigin(const nsACString& aOrigin)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  if (gDatabaseHash) {
+    gDatabaseHash->Enumerate(EnumerateDatabasesRemoveOrigin,
+                             const_cast<nsACString*>(&aOrigin));
+  }
+}
+
 bool
 DatabaseInfo::GetObjectStoreNames(nsTArray<nsString>& aNames)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   aNames.Clear();
   if (objectStoreHash) {
     objectStoreHash->EnumerateRead(EnumerateObjectStoreNames, &aNames);
@@ -236,27 +254,26 @@ DatabaseInfo::GetObjectStoreNames(nsTArr
 bool
 DatabaseInfo::ContainsStoreName(const nsAString& aName)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   return objectStoreHash && objectStoreHash->Get(aName, nsnull);
 }
 
-bool
-DatabaseInfo::GetObjectStore(const nsAString& aName,
-                             ObjectStoreInfo** aInfo)
+ObjectStoreInfo*
+DatabaseInfo::GetObjectStore(const nsAString& aName)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (objectStoreHash) {
-    return objectStoreHash->Get(aName, aInfo);
+    return objectStoreHash->GetWeak(aName);
   }
 
-  return false;
+  return nsnull;
 }
 
 bool
 DatabaseInfo::PutObjectStore(ObjectStoreInfo* aInfo)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aInfo, "Null pointer!");
 
@@ -276,17 +293,17 @@ DatabaseInfo::PutObjectStore(ObjectStore
 
   return objectStoreHash->Put(aInfo->name, aInfo);
 }
 
 void
 DatabaseInfo::RemoveObjectStore(const nsAString& aName)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(GetObjectStore(aName, nsnull), "Don't know about this one!");
+  NS_ASSERTION(GetObjectStore(aName), "Don't know about this one!");
 
   if (objectStoreHash) {
     objectStoreHash->Remove(aName);
   }
 }
 
 already_AddRefed<DatabaseInfo>
 DatabaseInfo::Clone()
--- a/dom/indexedDB/DatabaseInfo.h
+++ b/dom/indexedDB/DatabaseInfo.h
@@ -41,24 +41,24 @@
 #define mozilla_dom_indexeddb_databaseinfo_h__
 
 // Only meant to be included in IndexedDB source files, not exported.
 #include "IndexedDatabase.h"
 
 #include "Key.h"
 #include "IDBObjectStore.h"
 
-#include "nsClassHashtable.h"
+#include "nsRefPtrHashtable.h"
 #include "nsHashKeys.h"
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 struct ObjectStoreInfo;
 
-typedef nsClassHashtable<nsStringHashKey, ObjectStoreInfo>
+typedef nsRefPtrHashtable<nsStringHashKey, ObjectStoreInfo>
         ObjectStoreInfoHash;
 
 class IDBDatabase;
 class OpenDatabaseHelper;
 
 struct DatabaseInfo
 {
   friend class IDBDatabase;
@@ -72,34 +72,36 @@ private:
   { }
   ~DatabaseInfo();
 
   static bool Get(nsIAtom* aId,
                   DatabaseInfo** aInfo);
 
   static bool Put(DatabaseInfo* aInfo);
 
+public:
   static void Remove(nsIAtom* aId);
 
-public:
+  static void RemoveAllForOrigin(const nsACString& aOrigin);
+
   bool GetObjectStoreNames(nsTArray<nsString>& aNames);
   bool ContainsStoreName(const nsAString& aName);
 
-  bool GetObjectStore(const nsAString& aName,
-                      ObjectStoreInfo** aInfo);
+  ObjectStoreInfo* GetObjectStore(const nsAString& aName);
 
   bool PutObjectStore(ObjectStoreInfo* aInfo);
 
   void RemoveObjectStore(const nsAString& aName);
 
   already_AddRefed<DatabaseInfo> Clone();
 
   nsString name;
+  nsCString origin;
   PRUint64 version;
-  nsIAtom* id;
+  nsCOMPtr<nsIAtom> id;
   nsString filePath;
   PRInt64 nextObjectStoreId;
   PRInt64 nextIndexId;
   bool cloned;
 
   nsAutoPtr<ObjectStoreInfoHash> objectStoreHash;
 
   NS_INLINE_DECL_REFCOUNTING(DatabaseInfo)
@@ -108,44 +110,63 @@ public:
 struct IndexInfo
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   IndexInfo();
   IndexInfo(const IndexInfo& aOther);
   ~IndexInfo();
 #else
   IndexInfo()
-  : id(LL_MININT), unique(false), autoIncrement(false) { }
+  : id(LL_MININT), unique(false), multiEntry(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();
 #else
   ObjectStoreInfo()
-  : id(0), autoIncrement(false), databaseId(0) { }
+  : id(0), nextAutoIncrementId(0), comittedAutoIncrementId(0) { }
 #endif
 
+  ObjectStoreInfo(ObjectStoreInfo& aOther);
+
+private:
+#ifdef NS_BUILD_REFCNT_LOGGING
+  ~ObjectStoreInfo();
+#else
+  ~ObjectStoreInfo() {}
+#endif
+public:
+
+  // Constant members, can be gotten on any thread
   nsString name;
   PRInt64 id;
   nsString keyPath;
-  bool autoIncrement;
-  nsIAtom* databaseId;
+
+  // Main-thread only members. This must *not* be touced on the database thread
   nsTArray<IndexInfo> indexes;
+
+  // Database-thread members. After the ObjectStoreInfo has been initialized,
+  // these can *only* be touced on the database thread.
+  PRInt64 nextAutoIncrementId;
+  PRInt64 comittedAutoIncrementId;
+
+  // This is threadsafe since the ObjectStoreInfos are created on the database
+  // thread but then only used from the main thread. Ideal would be if we
+  // could transfer ownership from the database thread to the main thread, but
+  // we don't have that ability yet.
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ObjectStoreInfo)
 };
 
 struct IndexUpdateInfo
 {
 #ifdef NS_BUILD_REFCNT_LOGGING
   IndexUpdateInfo();
   ~IndexUpdateInfo();
 #endif
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -119,34 +119,34 @@ private:
   // In-params.
   PRInt64 mObjectStoreId;
 };
 
 NS_STACK_CLASS
 class AutoRemoveObjectStore
 {
 public:
-  AutoRemoveObjectStore(IDBDatabase* aDatabase, const nsAString& aName)
-  : mDatabase(aDatabase), mName(aName)
+  AutoRemoveObjectStore(DatabaseInfo* aInfo, const nsAString& aName)
+  : mInfo(aInfo), mName(aName)
   { }
 
   ~AutoRemoveObjectStore()
   {
-    if (mDatabase) {
-      mDatabase->Info()->RemoveObjectStore(mName);
+    if (mInfo) {
+      mInfo->RemoveObjectStore(mName);
     }
   }
 
   void forget()
   {
-    mDatabase = nsnull;
+    mInfo = nsnull;
   }
 
 private:
-  IDBDatabase* mDatabase;
+  DatabaseInfo* mInfo;
   nsString mName;
 };
 
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBDatabase>
 IDBDatabase::Create(nsIScriptContext* aScriptContext,
@@ -379,17 +379,17 @@ IDBDatabase::CreateObjectStore(const nsA
 
   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
 
   if (!transaction ||
       transaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
-  DatabaseInfo* databaseInfo = Info();
+  DatabaseInfo* databaseInfo = transaction->DBInfo();
 
   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
@@ -441,35 +441,34 @@ IDBDatabase::CreateObjectStore(const nsA
     if (keyPath.IsEmpty() && autoIncrement) {
       return NS_ERROR_DOM_INVALID_ACCESS_ERR;
     }
     if (!IDBObjectStore::IsValidKeyPath(aCx, keyPath)) {
       return NS_ERROR_DOM_SYNTAX_ERR;
     }
   }
 
-  nsAutoPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
+  nsRefPtr<ObjectStoreInfo> newInfo(new ObjectStoreInfo());
 
   newInfo->name = aName;
   newInfo->id = databaseInfo->nextObjectStoreId++;
   newInfo->keyPath = keyPath;
-  newInfo->autoIncrement = autoIncrement;
-  newInfo->databaseId = mDatabaseId;
+  newInfo->nextAutoIncrementId = autoIncrement ? 1 : 0;
+  newInfo->comittedAutoIncrementId = newInfo->nextAutoIncrementId;
 
-  if (!Info()->PutObjectStore(newInfo)) {
+  if (!databaseInfo->PutObjectStore(newInfo)) {
     NS_WARNING("Put failed!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
-  ObjectStoreInfo* objectStoreInfo = newInfo.forget();
 
   // Don't leave this in the hash if we fail below!
-  AutoRemoveObjectStore autoRemove(this, aName);
+  AutoRemoveObjectStore autoRemove(databaseInfo, aName);
 
   nsRefPtr<IDBObjectStore> objectStore =
-    transaction->GetOrCreateObjectStore(aName, objectStoreInfo);
+    transaction->GetOrCreateObjectStore(aName, newInfo);
   NS_ENSURE_TRUE(objectStore, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<CreateObjectStoreHelper> helper =
     new CreateObjectStoreHelper(transaction, objectStore);
 
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
@@ -486,30 +485,28 @@ IDBDatabase::DeleteObjectStore(const nsA
 
   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
 
   if (!transaction ||
       transaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
-  DatabaseInfo* info = Info();
-  ObjectStoreInfo* objectStoreInfo;
-  if (!info->GetObjectStore(aName, &objectStoreInfo)) {
+  DatabaseInfo* info = transaction->DBInfo();
+  ObjectStoreInfo* objectStoreInfo = info->GetObjectStore(aName);
+  if (!objectStoreInfo) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
   }
 
   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);
+  transaction->RemoveObjectStore(aName);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBDatabase::Transaction(const jsval& aStoreNames,
                          PRUint16 aMode,
                          JSContext* aCx,
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -221,19 +221,18 @@ IDBFactory::LoadDatabaseInformation(mozI
     "FROM object_store"
   ), getter_AddRefs(stmt));
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsAutoTArray<ObjectStoreInfoMap, 20> infoMap;
 
   bool hasResult;
   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
-    nsAutoPtr<ObjectStoreInfo>* element =
+    nsRefPtr<ObjectStoreInfo>* element =
       aObjectStores.AppendElement(new ObjectStoreInfo());
-    NS_ENSURE_TRUE(element, NS_ERROR_OUT_OF_MEMORY);
 
     ObjectStoreInfo* info = element->get();
 
     rv = stmt->GetString(0, info->name);
     NS_ENSURE_SUCCESS(rv, rv);
 
     info->id = stmt->AsInt64(1);
 
@@ -245,31 +244,30 @@ IDBFactory::LoadDatabaseInformation(mozI
     }
     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;
+    info->nextAutoIncrementId = stmt->AsInt64(3);
+    info->comittedAutoIncrementId = info->nextAutoIncrementId;
 
     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, "
-           "object_store_autoincrement "
+    "SELECT object_store_id, id, name, key_path, unique_index, multientry "
     "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);
 
     ObjectStoreInfo* objectStoreInfo = nsnull;
@@ -293,17 +291,16 @@ 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);
   }
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Load version information.
   rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT version "
     "FROM database"
   ), getter_AddRefs(stmt));
@@ -322,45 +319,38 @@ IDBFactory::LoadDatabaseInformation(mozI
 
   *aVersion = NS_MAX<PRInt64>(version, 0);
 
   return rv;
 }
 
 // static
 nsresult
-IDBFactory::UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
-                                   PRUint64 aVersion,
-                                   ObjectStoreInfoArray& aObjectStores)
+IDBFactory::SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
+                                PRUint64 aVersion,
+                                ObjectStoreInfoArray& aObjectStores)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aDatabaseInfo, "Null pointer!");
 
   ObjectStoreInfoArray objectStores;
-  if (!objectStores.SwapElements(aObjectStores)) {
-    NS_WARNING("Out of memory!");
-    return NS_ERROR_OUT_OF_MEMORY;
-  }
+  objectStores.SwapElements(aObjectStores);
 
-  nsAutoTArray<nsString, 10> existingNames;
-  if (!aDatabaseInfo->GetObjectStoreNames(existingNames)) {
-    NS_WARNING("Out of memory!");
-    return NS_ERROR_OUT_OF_MEMORY;
+#ifdef DEBUG
+  {
+    nsTArray<nsString> existingNames;
+    aDatabaseInfo->GetObjectStoreNames(existingNames);
+    NS_ASSERTION(existingNames.IsEmpty(), "Should be an empty DatabaseInfo");
   }
-
-  // Remove all the old ones.
-  for (PRUint32 index = 0; index < existingNames.Length(); index++) {
-    aDatabaseInfo->RemoveObjectStore(existingNames[index]);
-  }
+#endif
 
   aDatabaseInfo->version = aVersion;
 
   for (PRUint32 index = 0; index < objectStores.Length(); index++) {
-    nsAutoPtr<ObjectStoreInfo>& info = objectStores[index];
-    NS_ASSERTION(info->databaseId == aDatabaseInfo->id, "Huh?!");
+    nsRefPtr<ObjectStoreInfo>& info = objectStores[index];
 
     if (!aDatabaseInfo->PutObjectStore(info)) {
       NS_WARNING("Out of memory!");
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     info.forget();
   }
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -54,17 +54,17 @@ class nsIAtom;
 BEGIN_INDEXEDDB_NAMESPACE
 
 struct DatabaseInfo;
 class IDBDatabase;
 struct ObjectStoreInfo;
 
 class IDBFactory : public nsIIDBFactory
 {
-  typedef nsTArray<nsAutoPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
+  typedef nsTArray<nsRefPtr<ObjectStoreInfo> > ObjectStoreInfoArray;
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIIDBFACTORY
 
   static already_AddRefed<nsIIDBFactory> Create(nsPIDOMWindow* aWindow);
 
   static already_AddRefed<mozIStorageConnection>
   GetConnection(const nsAString& aDatabaseFilePath);
@@ -85,19 +85,19 @@ public:
 
   static nsresult
   LoadDatabaseInformation(mozIStorageConnection* aConnection,
                           nsIAtom* aDatabaseId,
                           PRUint64* aVersion,
                           ObjectStoreInfoArray& aObjectStores);
 
   static nsresult
-  UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
-                         PRUint64 aVersion,
-                         ObjectStoreInfoArray& aObjectStores);
+  SetDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
+                      PRUint64 aVersion,
+                      ObjectStoreInfoArray& aObjectStores);
 
 private:
   IDBFactory();
   ~IDBFactory() { }
 
   nsresult
   OpenCommon(const nsAString& aName,
              PRInt64 aVersion,
--- a/dom/indexedDB/IDBIndex.cpp
+++ b/dom/indexedDB/IDBIndex.cpp
@@ -316,25 +316,23 @@ IDBIndex::Create(IDBObjectStore* aObject
   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),
-  mAutoIncrement(false)
+  mUnique(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBIndex::~IDBIndex()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
@@ -688,57 +686,42 @@ IDBIndex::Count(const jsval& aKey,
   return NS_OK;
 }
 
 nsresult
 GetKeyHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
-  nsCString keyColumn;
   nsCString indexTable;
-
-  if (mIndex->IsAutoIncrement()) {
-    keyColumn.AssignLiteral("ai_object_data_id");
-    if (mIndex->IsUnique()) {
-      indexTable.AssignLiteral("ai_unique_index_data");
-    }
-    else {
-      indexTable.AssignLiteral("ai_index_data");
-    }
+  if (mIndex->IsUnique()) {
+    indexTable.AssignLiteral("unique_index_data");
   }
   else {
-    keyColumn.AssignLiteral("object_data_key");
-    if (mIndex->IsUnique()) {
-      indexTable.AssignLiteral("unique_index_data");
-    }
-    else {
-      indexTable.AssignLiteral("index_data");
-    }
+    indexTable.AssignLiteral("index_data");
   }
 
   nsCString keyRangeClause;
   mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause);
 
   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
 
-  NS_NAMED_LITERAL_CSTRING(indexId, "index_id");
-
-  nsCString query = NS_LITERAL_CSTRING("SELECT ") + keyColumn +
-                    NS_LITERAL_CSTRING(" FROM ") + indexTable +
-                    NS_LITERAL_CSTRING(" WHERE ") + indexId +
-                    NS_LITERAL_CSTRING(" = :") + indexId + keyRangeClause +
+  nsCString query = NS_LITERAL_CSTRING("SELECT object_data_key FROM ") +
+                    indexTable +
+                    NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
+                    keyRangeClause +
                     NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
+                                      mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = mKeyRange->BindToStatement(stmt);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -758,63 +741,44 @@ GetKeyHelper::GetSuccessResult(JSContext
   return mKey.ToJSVal(aCx, aVal);
 }
 
 nsresult
 GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
-  nsCString objectTable;
-  nsCString joinTable;
-  nsCString objectColumn;
-
-  if (mIndex->IsAutoIncrement()) {
-    objectTable.AssignLiteral("ai_object_data");
-    objectColumn.AssignLiteral("ai_object_data_id");
-    if (mIndex->IsUnique()) {
-      joinTable.AssignLiteral("ai_unique_index_data");
-    }
-    else {
-      joinTable.AssignLiteral("ai_index_data");
-    }
+  nsCString indexTable;
+  if (mIndex->IsUnique()) {
+    indexTable.AssignLiteral("unique_index_data");
   }
   else {
-    objectTable.AssignLiteral("object_data");
-    objectColumn.AssignLiteral("object_data_id");
-    if (mIndex->IsUnique()) {
-      joinTable.AssignLiteral("unique_index_data");
-    }
-    else {
-      joinTable.AssignLiteral("index_data");
-    }
+    indexTable.AssignLiteral("index_data");
   }
 
   nsCString keyRangeClause;
   mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause);
 
   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
 
-  NS_NAMED_LITERAL_CSTRING(indexId, "index_id");
-
-  nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM ") + objectTable +
-                    NS_LITERAL_CSTRING(" INNER JOIN ") + joinTable +
-                    NS_LITERAL_CSTRING(" ON ") + objectTable +
-                    NS_LITERAL_CSTRING(".id = ") + joinTable +
-                    NS_LITERAL_CSTRING(".") + objectColumn +
-                    NS_LITERAL_CSTRING(" WHERE ") + indexId +
-                    NS_LITERAL_CSTRING(" = :") + indexId + keyRangeClause +
+  nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
+                                       "INNER JOIN ") + indexTable +
+                    NS_LITERAL_CSTRING(" AS index_table ON object_data.id = ") +
+                    NS_LITERAL_CSTRING("index_table.object_data_id WHERE "
+                                       "index_id = :index_id") +
+                    keyRangeClause +
                     NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
+                                      mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = mKeyRange->BindToStatement(stmt);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -838,63 +802,47 @@ GetHelper::GetSuccessResult(JSContext* a
 
   NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
   return NS_OK;
 }
 
 nsresult
 GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
-  nsCString keyColumn;
   nsCString tableName;
-
-  if (mIndex->IsAutoIncrement()) {
-    keyColumn.AssignLiteral("ai_object_data_id");
-    if (mIndex->IsUnique()) {
-      tableName.AssignLiteral("ai_unique_index_data");
-    }
-    else {
-      tableName.AssignLiteral("ai_index_data");
-    }
+  if (mIndex->IsUnique()) {
+    tableName.AssignLiteral("unique_index_data");
   }
   else {
-    keyColumn.AssignLiteral("object_data_key");
-    if (mIndex->IsUnique()) {
-      tableName.AssignLiteral("unique_index_data");
-    }
-    else {
-      tableName.AssignLiteral("index_data");
-    }
+    tableName.AssignLiteral("index_data");
   }
 
   nsCString keyRangeClause;
   if (mKeyRange) {
     mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause);
   }
 
   nsCString limitClause;
   if (mLimit != PR_UINT32_MAX) {
     limitClause = NS_LITERAL_CSTRING(" LIMIT ");
     limitClause.AppendInt(mLimit);
   }
 
-  NS_NAMED_LITERAL_CSTRING(indexId, "index_id");
-
-  nsCString query = NS_LITERAL_CSTRING("SELECT ") + keyColumn +
-                    NS_LITERAL_CSTRING(" FROM ") + tableName +
-                    NS_LITERAL_CSTRING(" WHERE ") + indexId  +
-                    NS_LITERAL_CSTRING(" = :") + indexId + keyRangeClause +
-                    limitClause;
+  nsCString query = NS_LITERAL_CSTRING("SELECT object_data_key FROM ") +
+                    tableName +
+                    NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
+                    keyRangeClause + limitClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
+                                      mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   mKeys.SetCapacity(50);
@@ -962,69 +910,49 @@ GetAllKeysHelper::GetSuccessResult(JSCon
 
   *aVal = OBJECT_TO_JSVAL(array);
   return NS_OK;
 }
 
 nsresult
 GetAllHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
-  nsCString dataTableName;
-  nsCString objectDataId;
-  nsCString indexTableName;
-
-  if (mIndex->IsAutoIncrement()) {
-    dataTableName.AssignLiteral("ai_object_data");
-    objectDataId.AssignLiteral("ai_object_data_id");
-    if (mIndex->IsUnique()) {
-      indexTableName.AssignLiteral("ai_unique_index_data");
-    }
-    else {
-      indexTableName.AssignLiteral("ai_index_data");
-    }
+  nsCString indexTable;
+  if (mIndex->IsUnique()) {
+    indexTable.AssignLiteral("unique_index_data");
   }
   else {
-    dataTableName.AssignLiteral("object_data");
-    objectDataId.AssignLiteral("object_data_id");
-    if (mIndex->IsUnique()) {
-      indexTableName.AssignLiteral("unique_index_data");
-    }
-    else {
-      indexTableName.AssignLiteral("index_data");
-    }
+    indexTable.AssignLiteral("index_data");
   }
 
-  NS_NAMED_LITERAL_CSTRING(indexId, "index_id");
-
   nsCString keyRangeClause;
   if (mKeyRange) {
     mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause);
   }
 
   nsCString limitClause;
   if (mLimit != PR_UINT32_MAX) {
     limitClause = NS_LITERAL_CSTRING(" LIMIT ");
     limitClause.AppendInt(mLimit);
   }
 
-  nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM ") + dataTableName +
-                    NS_LITERAL_CSTRING(" INNER JOIN ") + indexTableName  +
-                    NS_LITERAL_CSTRING(" ON ") + dataTableName +
-                    NS_LITERAL_CSTRING(".id = ") + indexTableName +
-                    NS_LITERAL_CSTRING(".") + objectDataId +
-                    NS_LITERAL_CSTRING(" WHERE ") + indexId  +
-                    NS_LITERAL_CSTRING(" = :") + indexId + keyRangeClause +
-                    limitClause;
+  nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
+                                       "INNER JOIN ") + indexTable +
+                    NS_LITERAL_CSTRING(" AS index_table ON object_data.id = "
+                                       "index_table.object_data_id "
+                                       "WHERE index_id = :index_id") +
+                    keyRangeClause + limitClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(indexId, mIndex->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
+                                      mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   mCloneReadInfos.SetCapacity(50);
@@ -1064,82 +992,62 @@ GetAllHelper::GetSuccessResult(JSContext
 }
 
 nsresult
 OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_ASSERTION(aConnection, "Passed a null connection!");
 
   nsCString table;
-  nsCString keyColumn;
-
-  if (mIndex->IsAutoIncrement()) {
-    keyColumn.AssignLiteral("ai_object_data_id");
-    if (mIndex->IsUnique()) {
-      table.AssignLiteral("ai_unique_index_data");
-    }
-    else {
-      table.AssignLiteral("ai_index_data");
-    }
+  if (mIndex->IsUnique()) {
+    table.AssignLiteral("unique_index_data");
   }
   else {
-    keyColumn.AssignLiteral("object_data_key");
-    if (mIndex->IsUnique()) {
-      table.AssignLiteral("unique_index_data");
-    }
-    else {
-      table.AssignLiteral("index_data");
-    }
+    table.AssignLiteral("index_data");
   }
 
-  NS_NAMED_LITERAL_CSTRING(id, "id");
-  NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
-  NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
-
   NS_NAMED_LITERAL_CSTRING(value, "value");
 
   nsCString keyRangeClause;
   if (mKeyRange) {
     mKeyRange->GetBindingClause(value, keyRangeClause);
   }
 
-  nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + value;
+  nsCAutoString directionClause(" ORDER BY value ");
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
-      directionClause += NS_LITERAL_CSTRING(" ASC, ") + keyColumn +
-                         NS_LITERAL_CSTRING(" ASC");
+      directionClause += NS_LITERAL_CSTRING("ASC, object_data_key ASC");
       break;
 
     case nsIIDBCursor::PREV:
-      directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyColumn +
-                         NS_LITERAL_CSTRING(" DESC");
+      directionClause += NS_LITERAL_CSTRING("DESC, object_data_key DESC");
       break;
 
     case nsIIDBCursor::PREV_NO_DUPLICATE:
-      directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyColumn +
-                         NS_LITERAL_CSTRING(" ASC");
+      directionClause += NS_LITERAL_CSTRING("DESC, object_data_key ASC");
       break;
 
     default:
       NS_NOTREACHED("Unknown direction!");
   }
-  nsCString firstQuery = NS_LITERAL_CSTRING("SELECT value, ") + keyColumn +
-                         NS_LITERAL_CSTRING(" FROM ") + table +
-                         NS_LITERAL_CSTRING(" WHERE index_id = :") + id +
+  nsCString firstQuery = NS_LITERAL_CSTRING("SELECT value, object_data_key "
+                                            "FROM ") + table +
+                         NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
                          keyRangeClause + directionClause +
                          NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(firstQuery);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(id, mIndex->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
+                                      mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bool hasResult;
@@ -1153,84 +1061,96 @@ OpenKeyCursorHelper::DoDatabaseWork(mozI
 
   rv = mKey.SetFromStatement(stmt, 0);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = mObjectKey.SetFromStatement(stmt, 1);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Now we need to make the query to get the next match.
-  nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT value, ") + keyColumn +
-                             NS_LITERAL_CSTRING(" FROM ") + table +
-                             NS_LITERAL_CSTRING(" WHERE index_id = :") + id;
+  nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT value, object_data_key"
+                                                " FROM ") + table +
+                             NS_LITERAL_CSTRING(" WHERE index_id = :id");
 
-  NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
-  NS_NAMED_LITERAL_CSTRING(objectKey, "object_key");
 
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
         AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Upper();
       }
-      mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND value >= :") +
-                       currentKey + NS_LITERAL_CSTRING(" AND ( value > :") +
-                       currentKey + NS_LITERAL_CSTRING(" OR ") + keyColumn +
-                       NS_LITERAL_CSTRING(" > :") + objectKey +
-                       NS_LITERAL_CSTRING(" )") + directionClause +
-                       NS_LITERAL_CSTRING(" LIMIT ");
-      mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value >= :") +
-                         currentKey + NS_LITERAL_CSTRING(" LIMIT ");
+      mContinueQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND value >= :current_key AND "
+                           "( value > :current_key OR "
+                           "  object_data_key > :object_key )") +
+        directionClause +
+        NS_LITERAL_CSTRING(" LIMIT ");
+      mContinueToQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND value >= :current_key ") +
+        directionClause +
+        NS_LITERAL_CSTRING(" LIMIT ");
       break;
 
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
         AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Upper();
       }
-      mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND value > :") +
-                       currentKey + directionClause +
-                       NS_LITERAL_CSTRING(" LIMIT ");
-      mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value >= :") +
-                         currentKey + directionClause +
-                         NS_LITERAL_CSTRING(" LIMIT ");
+      mContinueQuery =
+        queryStart + NS_LITERAL_CSTRING(" AND value > :current_key") +
+        directionClause +
+        NS_LITERAL_CSTRING(" LIMIT ");
+      mContinueToQuery =
+        queryStart + NS_LITERAL_CSTRING(" AND value >= :current_key") +
+        directionClause +
+        NS_LITERAL_CSTRING(" LIMIT ");
       break;
 
     case nsIIDBCursor::PREV:
       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
         AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Lower();
       }
 
-      mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND value <= :") +
-                       currentKey + NS_LITERAL_CSTRING(" AND ( value < :") +
-                       currentKey + NS_LITERAL_CSTRING(" OR ") + keyColumn +
-                       NS_LITERAL_CSTRING(" < :") + objectKey +
-                       NS_LITERAL_CSTRING(" ) ") + directionClause +
-                       NS_LITERAL_CSTRING(" LIMIT ");
-      mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value <= :") +
-                         currentKey + NS_LITERAL_CSTRING(" LIMIT ");
+      mContinueQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND value <= :current_key AND "
+                           "( value < :current_key OR "
+                           "  object_data_key < :object_key )") +
+        directionClause +
+        NS_LITERAL_CSTRING(" LIMIT ");
+      mContinueToQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND value <= :current_key ") +
+        directionClause +
+        NS_LITERAL_CSTRING(" LIMIT ");
       break;
 
     case nsIIDBCursor::PREV_NO_DUPLICATE:
       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
         AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Lower();
       }
-      mContinueQuery = queryStart + NS_LITERAL_CSTRING(" AND value < :") +
-                       currentKey + directionClause +
-                       NS_LITERAL_CSTRING(" LIMIT ");
-      mContinueToQuery = queryStart + NS_LITERAL_CSTRING(" AND value <= :") +
-                         currentKey + directionClause +
-                         NS_LITERAL_CSTRING(" LIMIT ");
+      mContinueQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND value < :current_key") +
+        directionClause +
+        NS_LITERAL_CSTRING(" LIMIT ");
+      mContinueToQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND value <= :current_key") +
+        directionClause +
+        NS_LITERAL_CSTRING(" LIMIT ");
       break;
 
     default:
       NS_NOTREACHED("Unknown direction type!");
   }
 
   return NS_OK;
 }
@@ -1253,99 +1173,70 @@ OpenKeyCursorHelper::GetSuccessResult(JS
 }
 
 nsresult
 OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_ASSERTION(aConnection, "Passed a null connection!");
 
   nsCString indexTable;
-  nsCString objectTable;
-  nsCString objectDataIdColumn;
-  nsCString keyValueColumn;
-
-  if (mIndex->IsAutoIncrement()) {
-    objectTable.AssignLiteral("ai_object_data");
-    objectDataIdColumn.AssignLiteral("ai_object_data_id");
-    keyValueColumn.AssignLiteral("ai_object_data_id");
-    if (mIndex->IsUnique()) {
-      indexTable.AssignLiteral("ai_unique_index_data");
-    }
-    else {
-      indexTable.AssignLiteral("ai_index_data");
-    }
+  if (mIndex->IsUnique()) {
+    indexTable.AssignLiteral("unique_index_data");
   }
   else {
-    objectTable.AssignLiteral("object_data");
-    objectDataIdColumn.AssignLiteral("object_data_id");
-    keyValueColumn.AssignLiteral("object_data_key");
-    if (mIndex->IsUnique()) {
-      indexTable.AssignLiteral("unique_index_data");
-    }
-    else {
-      indexTable.AssignLiteral("index_data");
-    }
+    indexTable.AssignLiteral("index_data");
   }
 
-  nsCString value = indexTable + NS_LITERAL_CSTRING(".value");
-  nsCString keyValue = indexTable + NS_LITERAL_CSTRING(".") + keyValueColumn;
+  NS_NAMED_LITERAL_CSTRING(value, "index_table.value");
 
   nsCString keyRangeClause;
   if (mKeyRange) {
     mKeyRange->GetBindingClause(value, keyRangeClause);
   }
 
-  nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + value;
+  nsCAutoString directionClause(" ORDER BY index_table.value ");
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
-      directionClause += NS_LITERAL_CSTRING(" ASC, ") + keyValue +
-                         NS_LITERAL_CSTRING(" ASC");
+      directionClause +=
+        NS_LITERAL_CSTRING("ASC, index_table.object_data_key ASC");
       break;
 
     case nsIIDBCursor::PREV:
-      directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyValue +
-                         NS_LITERAL_CSTRING(" DESC");
+      directionClause +=
+        NS_LITERAL_CSTRING("DESC, index_table.object_data_key DESC");
       break;
 
     case nsIIDBCursor::PREV_NO_DUPLICATE:
-      directionClause += NS_LITERAL_CSTRING(" DESC, ") + keyValue +
-                         NS_LITERAL_CSTRING(" ASC");
+      directionClause +=
+        NS_LITERAL_CSTRING("DESC, index_table.object_data_key ASC");
       break;
 
     default:
       NS_NOTREACHED("Unknown direction!");
   }
 
-  NS_NAMED_LITERAL_CSTRING(id, "id");
-  NS_NAMED_LITERAL_CSTRING(dot, ".");
-  NS_NAMED_LITERAL_CSTRING(commaspace, ", ");
-
-  nsCString data = objectTable + NS_LITERAL_CSTRING(".data");
-  nsCString fileIds = objectTable + NS_LITERAL_CSTRING(".file_ids");
-
-  nsCString firstQuery = NS_LITERAL_CSTRING("SELECT ") + value + commaspace +
-                         keyValue + commaspace + data + commaspace + fileIds +
-                         NS_LITERAL_CSTRING(" FROM ") + indexTable +
-                         NS_LITERAL_CSTRING(" INNER JOIN ") + objectTable +
-                         NS_LITERAL_CSTRING(" ON ") + indexTable + dot +
-                         objectDataIdColumn + NS_LITERAL_CSTRING(" = ") +
-                         objectTable + dot + id +
-                         NS_LITERAL_CSTRING(" WHERE ") + indexTable +
-                         NS_LITERAL_CSTRING(".index_id = :") + id +
-                         keyRangeClause + directionClause +
-                         NS_LITERAL_CSTRING(" LIMIT 1");
+  nsCString firstQuery =
+    NS_LITERAL_CSTRING("SELECT index_table.value, "
+                       "index_table.object_data_key, object_data.data, "
+                       "object_data.file_ids FROM ") +
+    indexTable +
+    NS_LITERAL_CSTRING(" AS index_table INNER JOIN object_data ON "
+                       "index_table.object_data_id = object_data.id "
+                       "WHERE index_table.index_id = :id") +
+    keyRangeClause + directionClause +
+    NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(firstQuery);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(id, mIndex->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bool hasResult;
@@ -1363,90 +1254,96 @@ OpenCursorHelper::DoDatabaseWork(mozISto
   rv = mObjectKey.SetFromStatement(stmt, 1);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 2, 3,
     mDatabase->Manager(), mCloneReadInfo);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Now we need to make the query to get the next match.
-  nsCAutoString queryStart = NS_LITERAL_CSTRING("SELECT ") + value +
-                             commaspace + keyValue + commaspace + data +
-                             commaspace + fileIds +
-                             NS_LITERAL_CSTRING(" FROM ") + indexTable +
-                             NS_LITERAL_CSTRING(" INNER JOIN ") + objectTable +
-                             NS_LITERAL_CSTRING(" ON ") + indexTable + dot +
-                             objectDataIdColumn + NS_LITERAL_CSTRING(" = ") +
-                             objectTable + dot + id +
-                             NS_LITERAL_CSTRING(" WHERE ") + indexTable +
-                             NS_LITERAL_CSTRING(".index_id = :") + id;
+  nsCAutoString queryStart =
+    NS_LITERAL_CSTRING("SELECT index_table.value, "
+                       "index_table.object_data_key, object_data.data, "
+                       "object_data.file_ids FROM ") +
+    indexTable +
+    NS_LITERAL_CSTRING(" AS index_table INNER JOIN object_data ON "
+                       "index_table.object_data_id = object_data.id "
+                       "WHERE index_table.index_id = :id");
 
-  NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
-  NS_NAMED_LITERAL_CSTRING(objectKey, "object_key");
 
-  NS_NAMED_LITERAL_CSTRING(andStr, " AND ");
-  NS_NAMED_LITERAL_CSTRING(orStr, " OR ");
-  NS_NAMED_LITERAL_CSTRING(ge, " >= :");
-  NS_NAMED_LITERAL_CSTRING(gt, " > :");
-  NS_NAMED_LITERAL_CSTRING(le, " <= :");
-  NS_NAMED_LITERAL_CSTRING(lt, " < :");
-  NS_NAMED_LITERAL_CSTRING(openparen, " ( ");
-  NS_NAMED_LITERAL_CSTRING(closeparen, " ) ");
   NS_NAMED_LITERAL_CSTRING(limit, " LIMIT ");
 
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
         AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Upper();
       }
-      mContinueQuery = queryStart + andStr + value + ge + currentKey + andStr +
-                       openparen + value + gt + currentKey + orStr + keyValue +
-                       gt + objectKey + closeparen + directionClause + limit;
-      mContinueToQuery = queryStart + andStr + value + ge + currentKey +
-                         directionClause + limit;
+      mContinueQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND index_table.value >= :current_key AND "
+                           "( index_table.value > :current_key OR "
+                           "  index_table.object_data_key > :object_key ) ") +
+        directionClause + limit;
+      mContinueToQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND index_table.value >= :current_key") +
+        directionClause + limit;
       break;
 
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
         AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Upper();
       }
-      mContinueQuery = queryStart + andStr + value + gt + currentKey +
-                       directionClause + limit;
-      mContinueToQuery = queryStart + andStr + value + ge + currentKey +
-                         directionClause + limit;
+      mContinueQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND index_table.value > :current_key") +
+        directionClause + limit;
+      mContinueToQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND index_table.value >= :current_key") +
+        directionClause + limit;
       break;
 
     case nsIIDBCursor::PREV:
       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
         AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Lower();
       }
-      mContinueQuery = queryStart + andStr + value + le + currentKey + andStr +
-                       openparen + value + lt + currentKey + orStr + keyValue +
-                       lt + objectKey + closeparen + directionClause + limit;
-      mContinueToQuery = queryStart + andStr + value + le + currentKey +
-                         directionClause + limit;
+      mContinueQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND index_table.value <= :current_key AND "
+                           "( index_table.value < :current_key OR "
+                           "  index_table.object_data_key < :object_key ) ") +
+        directionClause + limit;
+      mContinueToQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND index_table.value <= :current_key") +
+        directionClause + limit;
       break;
 
     case nsIIDBCursor::PREV_NO_DUPLICATE:
       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
         AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
                               queryStart);
         mRangeKey = mKeyRange->Lower();
       }
-      mContinueQuery = queryStart + andStr + value + lt + currentKey +
-                       directionClause +limit;
-      mContinueToQuery = queryStart + andStr + value + le + currentKey +
-                         directionClause + limit;
+      mContinueQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND index_table.value < :current_key") +
+        directionClause + limit;
+      mContinueToQuery =
+        queryStart +
+        NS_LITERAL_CSTRING(" AND index_table.value <= :current_key") +
+        directionClause + limit;
       break;
 
     default:
       NS_NOTREACHED("Unknown direction type!");
   }
 
   return NS_OK;
 }
@@ -1470,32 +1367,21 @@ OpenCursorHelper::GetSuccessResult(JSCon
 
   return WrapNative(aCx, cursor, aVal);
 }
 
 nsresult
 CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   nsCString table;
-
-  if (mIndex->IsAutoIncrement()) {
-    if (mIndex->IsUnique()) {
-      table.AssignLiteral("ai_unique_index_data");
-    }
-    else {
-      table.AssignLiteral("ai_index_data");
-    }
+  if (mIndex->IsUnique()) {
+    table.AssignLiteral("unique_index_data");
   }
   else {
-    if (mIndex->IsUnique()) {
-      table.AssignLiteral("unique_index_data");
-    }
-    else {
-      table.AssignLiteral("index_data");
-    }
+    table.AssignLiteral("index_data");
   }
 
   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
   NS_NAMED_LITERAL_CSTRING(value, "value");
 
   nsCAutoString keyRangeClause;
   if (mKeyRange) {
@@ -1504,28 +1390,26 @@ CountHelper::DoDatabaseWork(mozIStorageC
                             !mKeyRange->IsLowerOpen(), keyRangeClause);
     }
     if (!mKeyRange->Upper().IsUnset()) {
       AppendConditionClause(value, upperKeyName, true,
                             !mKeyRange->IsUpperOpen(), keyRangeClause);
     }
   }
 
-  NS_NAMED_LITERAL_CSTRING(id, "id");
-
   nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM ") + table +
-                    NS_LITERAL_CSTRING(" WHERE index_id = :") + id +
+                    NS_LITERAL_CSTRING(" WHERE index_id = :id") +
                     keyRangeClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(id, mIndex->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     if (!mKeyRange->Lower().IsUnset()) {
       rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     if (!mKeyRange->Upper().IsUnset()) {
--- a/dom/indexedDB/IDBIndex.h
+++ b/dom/indexedDB/IDBIndex.h
@@ -87,21 +87,16 @@ public:
     return mUnique;
   }
 
   bool IsMultiEntry() const
   {
     return mMultiEntry;
   }
 
-  bool IsAutoIncrement() const
-  {
-    return mAutoIncrement;
-  }
-
   const nsString& KeyPath() const
   {
     return mKeyPath;
   }
 
 private:
   IDBIndex();
   ~IDBIndex();
@@ -111,14 +106,13 @@ 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
@@ -377,46 +377,40 @@ protected:
 private:
   PRUint64 mCount;
 };
 
 NS_STACK_CLASS
 class AutoRemoveIndex
 {
 public:
-  AutoRemoveIndex(IDBDatabase* aDatabase,
-                  const nsAString& aObjectStoreName,
+  AutoRemoveIndex(ObjectStoreInfo* aObjectStoreInfo,
                   const nsAString& aIndexName)
-  : mDatabase(aDatabase), mObjectStoreName(aObjectStoreName),
-    mIndexName(aIndexName)
+  : mObjectStoreInfo(aObjectStoreInfo), mIndexName(aIndexName)
   { }
 
   ~AutoRemoveIndex()
   {
-    if (mDatabase) {
-      ObjectStoreInfo* info;
-      if (mDatabase->Info()->GetObjectStore(mObjectStoreName, &info)) {
-        for (PRUint32 index = 0; index < info->indexes.Length(); index++) {
-          if (info->indexes[index].name == mIndexName) {
-            info->indexes.RemoveElementAt(index);
-            break;
-          }
+    if (mObjectStoreInfo) {
+      for (PRUint32 i = 0; i < mObjectStoreInfo->indexes.Length(); i++) {
+        if (mObjectStoreInfo->indexes[i].name == mIndexName) {
+          mObjectStoreInfo->indexes.RemoveElementAt(i);
+          break;
         }
       }
     }
   }
 
   void forget()
   {
-    mDatabase = nsnull;
+    mObjectStoreInfo = nsnull;
   }
 
 private:
-  IDBDatabase* mDatabase;
-  nsString mObjectStoreName;
+  ObjectStoreInfo* mObjectStoreInfo;
   nsString mIndexName;
 };
 
 inline
 bool
 IgnoreWhitespace(PRUnichar c)
 {
   return false;
@@ -498,31 +492,33 @@ JSClass gDummyPropClass = {
   JSCLASS_NO_OPTIONAL_MEMBERS
 };
 
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBObjectStore>
 IDBObjectStore::Create(IDBTransaction* aTransaction,
-                       const ObjectStoreInfo* aStoreInfo)
+                       ObjectStoreInfo* aStoreInfo,
+                       nsIAtom* aDatabaseId)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<IDBObjectStore> objectStore = new IDBObjectStore();
 
   objectStore->mScriptContext = aTransaction->Database()->ScriptContext();
   objectStore->mOwner = aTransaction->Database()->Owner();
 
   objectStore->mTransaction = aTransaction;
   objectStore->mName = aStoreInfo->name;
   objectStore->mId = aStoreInfo->id;
   objectStore->mKeyPath = aStoreInfo->keyPath;
-  objectStore->mAutoIncrement = aStoreInfo->autoIncrement;
-  objectStore->mDatabaseId = aStoreInfo->databaseId;
+  objectStore->mAutoIncrement = !!aStoreInfo->nextAutoIncrementId;
+  objectStore->mDatabaseId = aDatabaseId;
+  objectStore->mInfo = aStoreInfo;
 
   return objectStore.forget();
 }
 
 // static
 bool
 IDBObjectStore::IsValidKeyPath(JSContext* aCx,
                                const nsAString& aKeyPath)
@@ -620,112 +616,75 @@ IDBObjectStore::AppendIndexUpdateInfo(PR
   return NS_OK;
 }
 
 // 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!");
-
   nsCOMPtr<mozIStorageStatement> stmt;
   nsresult rv;
 
-  if (aObjectDataId == LL_MININT) {
+  NS_ASSERTION(aObjectDataId != LL_MININT, "Bad objectData id!");
+
+  NS_NAMED_LITERAL_CSTRING(objectDataId, "object_data_id");
+
+  if (aOverwrite) {
     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);
+      "DELETE FROM unique_index_data "
+      "WHERE object_data_id = :object_data_id; "
+      "DELETE FROM index_data "
+      "WHERE object_data_id = :object_data_id");
 
     mozStorageStatementScoper scoper(stmt);
 
-    rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), aObjectStoreId);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    NS_ASSERTION(!aObjectStoreKey.IsUnset(), "This shouldn't happen!");
-
-    rv = aObjectStoreKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key_value"));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    bool hasResult;
-    rv = stmt->ExecuteStep(&hasResult);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    if (!hasResult) {
-      NS_ERROR("This is bad, we just added this value! Where'd it go?!");
-      return NS_ERROR_FAILURE;
-    }
-
-    aObjectDataId = stmt->AsInt64(0);
-  }
-
-  NS_ASSERTION(aObjectDataId != LL_MININT, "Bad objectData id!");
-
-  NS_NAMED_LITERAL_CSTRING(indexId, "index_id");
-  NS_NAMED_LITERAL_CSTRING(objectDataId, "object_data_id");
-  NS_NAMED_LITERAL_CSTRING(objectDataKey, "object_data_key");
-  NS_NAMED_LITERAL_CSTRING(value, "value");
-
-  if (aOverwrite) {
-    stmt = aTransaction->IndexDataDeleteStatement(aAutoIncrement, false);
-    NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE);
-
-    mozStorageStatementScoper scoper2(stmt);
-
-    rv = stmt->BindInt64ByName(objectDataId, aObjectDataId);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = stmt->Execute();
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    stmt = aTransaction->IndexDataDeleteStatement(aAutoIncrement, true);
-    NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE);
-
-    mozStorageStatementScoper scoper3(stmt);
-
     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];
 
     // Insert new values.
-    stmt = aTransaction->IndexDataInsertStatement(aAutoIncrement,
-                                                  updateInfo.indexUnique);
+
+    stmt = updateInfo.indexUnique ?
+      aTransaction->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)") :
+      aTransaction->GetCachedStatement(
+        "INSERT OR IGNORE INTO index_data ("
+          "index_id, object_data_id, object_data_key, value) "
+        "VALUES (:index_id, :object_data_id, :object_data_key, :value)");
+
     NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE);
 
     mozStorageStatementScoper scoper4(stmt);
 
-    rv = stmt->BindInt64ByName(indexId, updateInfo.indexId);
+    rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
+                               updateInfo.indexId);
     NS_ENSURE_SUCCESS(rv, rv);
 
     rv = stmt->BindInt64ByName(objectDataId, aObjectDataId);
     NS_ENSURE_SUCCESS(rv, rv);
 
-    if (!aAutoIncrement) {
-      rv = aObjectStoreKey.BindToStatement(stmt, objectDataKey);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-
-    rv = updateInfo.value.BindToStatement(stmt, value);
+    rv = aObjectStoreKey.BindToStatement(stmt,
+                                         NS_LITERAL_CSTRING("object_data_key"));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = updateInfo.value.BindToStatement(stmt, NS_LITERAL_CSTRING("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.
       
@@ -1124,38 +1083,16 @@ IDBObjectStore::ConvertFileIdsToArray(co
     
     PRInt64* element = aResult.AppendElement();
     *element = id;
   }
 
   return NS_OK;
 }
 
-nsresult
-IDBObjectStore::ModifyValueForNewKey(StructuredCloneWriteInfo& aCloneWriteInfo,
-                                     Key& aKey)
-{
-  NS_ASSERTION(IsAutoIncrement() && aKey.IsInteger(), "Don't call me!");
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread");
-
-  // This is a duplicate of the js engine's byte munging here
-  union {
-    jsdouble d;
-    PRUint64 u;
-  } pun;
-
-  pun.d = SwapBytes(static_cast<PRUint64>(aKey.ToInteger()));
-
-  JSAutoStructuredCloneBuffer& buffer = aCloneWriteInfo.mCloneBuffer;
-  PRUint64 offsetToKeyProp = aCloneWriteInfo.mOffsetToKeyProp;
-
-  memcpy((char*)buffer.data() + offsetToKeyProp, &pun.u, sizeof(PRUint64));
-  return NS_OK;
-}
-
 IDBObjectStore::IDBObjectStore()
 : mId(LL_MININT),
   mAutoIncrement(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 IDBObjectStore::~IDBObjectStore()
@@ -1195,25 +1132,20 @@ IDBObjectStore::GetAddInfo(JSContext* aC
 
   // 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();
+  PRUint32 count = mInfo->indexes.Length();
   aUpdateInfoArray.SetCapacity(count); // Pretty good estimate
   for (PRUint32 indexesIndex = 0; indexesIndex < count; indexesIndex++) {
-    const IndexInfo& indexInfo = info->indexes[indexesIndex];
+    const IndexInfo& indexInfo = mInfo->indexes[indexesIndex];
 
     rv = AppendIndexUpdateInfo(indexInfo.id, indexInfo.keyPath,
                                indexInfo.unique, indexInfo.multiEntry,
                                aCx, aValue, aUpdateInfoArray);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsString targetObjectPropName;
@@ -1368,21 +1300,16 @@ IDBObjectStore::AddOrPut(const jsval& aV
   nsTArray<IndexUpdateInfo> updateInfo;
 
   nsresult rv = GetAddInfo(aCx, aValue, keyval, cloneWriteInfo, key,
                            updateInfo);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
-  // Put requires a key, unless this is an autoIncrementing objectStore.
-  if (aOverwrite && !mAutoIncrement && key.IsUnset()) {
-    return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
-  }
-
   nsRefPtr<IDBRequest> request = GenerateRequest(this);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<AddHelper> helper =
     new AddHelper(mTransaction, request, this, cloneWriteInfo, key, aOverwrite,
                   updateInfo);
 
   rv = helper->DispatchToTransactionPool();
@@ -1449,30 +1376,34 @@ IDBObjectStore::GetTransaction(nsIIDBTra
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsCOMPtr<nsIIDBTransaction> transaction(mTransaction);
   transaction.forget(aTransaction);
   return NS_OK;
 }
 
 NS_IMETHODIMP
+IDBObjectStore::GetAutoIncrement(bool* aAutoIncrement)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+
+  *aAutoIncrement = mAutoIncrement;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 IDBObjectStore::GetIndexNames(nsIDOMDOMStringList** aIndexNames)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  ObjectStoreInfo* info;
-  if (!mTransaction->Database()->Info()->GetObjectStore(mName, &info)) {
-    NS_ERROR("This should never fail!");
-  }
-
   nsRefPtr<nsDOMStringList> list(new nsDOMStringList());
 
-  PRUint32 count = info->indexes.Length();
+  PRUint32 count = mInfo->indexes.Length();
   for (PRUint32 index = 0; index < count; index++) {
-    NS_ENSURE_TRUE(list->Add(info->indexes[index].name),
+    NS_ENSURE_TRUE(list->Add(mInfo->indexes[index].name),
                    NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
   list.forget(aIndexNames);
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -1694,25 +1625,20 @@ IDBObjectStore::CreateIndex(const nsAStr
   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
 
   if (!transaction ||
       transaction != mTransaction ||
       mTransaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
-  ObjectStoreInfo* info;
-  if (!mTransaction->Database()->Info()->GetObjectStore(mName, &info)) {
-    NS_ERROR("This should never fail!");
-  }
-
   bool found = false;
-  PRUint32 indexCount = info->indexes.Length();
+  PRUint32 indexCount = mInfo->indexes.Length();
   for (PRUint32 index = 0; index < indexCount; index++) {
-    if (info->indexes[index].name == aName) {
+    if (mInfo->indexes[index].name == aName) {
       found = true;
       break;
     }
   }
 
   if (found) {
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
@@ -1752,33 +1678,27 @@ IDBObjectStore::CreateIndex(const nsAStr
 
     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;
-  }
-
+  DatabaseInfo* databaseInfo = mTransaction->DBInfo();
+
+  IndexInfo* indexInfo = mInfo->indexes.AppendElement();
   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);
+  AutoRemoveIndex autoRemove(mInfo, aName);
 
 #ifdef DEBUG
   for (PRUint32 index = 0; index < mCreatedIndexes.Length(); index++) {
     if (mCreatedIndexes[index]->Name() == aName) {
       NS_ERROR("Already created this one!");
     }
   }
 #endif
@@ -1807,26 +1727,21 @@ IDBObjectStore::Index(const nsAString& a
                       nsIIDBIndex** _retval)
 {
   NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
 
   if (!mTransaction->IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
   }
 
-  ObjectStoreInfo* info;
-  if (!mTransaction->Database()->Info()->GetObjectStore(mName, &info)) {
-    NS_ERROR("This should never fail!");
-  }
-
   IndexInfo* indexInfo = nsnull;
-  PRUint32 indexCount = info->indexes.Length();
+  PRUint32 indexCount = mInfo->indexes.Length();
   for (PRUint32 index = 0; index < indexCount; index++) {
-    if (info->indexes[index].name == aName) {
-      indexInfo = &(info->indexes[index]);
+    if (mInfo->indexes[index].name == aName) {
+      indexInfo = &(mInfo->indexes[index]);
       break;
     }
   }
 
   if (!indexInfo) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
   }
 
@@ -1863,39 +1778,34 @@ IDBObjectStore::DeleteIndex(const nsAStr
   if (!transaction ||
       transaction != mTransaction ||
       mTransaction->Mode() != nsIIDBTransaction::VERSION_CHANGE) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
 
-  ObjectStoreInfo* info;
-  if (!mTransaction->Database()->Info()->GetObjectStore(mName, &info)) {
-    NS_ERROR("This should never fail!");
-  }
-
   PRUint32 index = 0;
-  for (; index < info->indexes.Length(); index++) {
-    if (info->indexes[index].name == aName) {
+  for (; index < mInfo->indexes.Length(); index++) {
+    if (mInfo->indexes[index].name == aName) {
       break;
     }
   }
 
-  if (index == info->indexes.Length()) {
+  if (index == mInfo->indexes.Length()) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
   }
 
   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);
+  mInfo->indexes.RemoveElementAt(index);
 
   for (PRUint32 i = 0; i < mCreatedIndexes.Length(); i++) {
     if (mCreatedIndexes[i]->Name() == aName) {
       mCreatedIndexes.RemoveElementAt(i);
       break;
     }
   }
 
@@ -1958,77 +1868,100 @@ CopyData(nsIInputStream* aStream, quota_
 }
 
 nsresult
 AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_PRECONDITION(aConnection, "Passed a null connection!");
 
   nsresult rv;
-  bool mayOverwrite = mOverwrite;
-  bool unsetKey = mKey.IsUnset();
-
-  bool autoIncrement = mObjectStore->IsAutoIncrement();
+  bool keyUnset = mKey.IsUnset();
   PRInt64 osid = mObjectStore->Id();
   const nsString& keyPath = mObjectStore->KeyPath();
 
-  if (unsetKey) {
-    NS_ASSERTION(autoIncrement, "Must have a key for non-autoIncrement!");
-
-    // Will need to add first and then set the key later.
-    mayOverwrite = false;
-  }
-
-  if (autoIncrement && !unsetKey) {
-    mayOverwrite = true;
-  }
-
-  nsCOMPtr<mozIStorageStatement> stmt;
-  if (!mOverwrite && !unsetKey) {
-    // Make sure the key doesn't exist already
-    NS_NAMED_LITERAL_CSTRING(id, "id");
-    NS_NAMED_LITERAL_CSTRING(osidStr, "osid");
-
-    nsCString table;
-    nsCString value;
-
-    if (autoIncrement) {
-      table.AssignLiteral("ai_object_data");
-      value = id;
+  // The "|| keyUnset" here is mostly a debugging tool. If a key isn't
+  // specified we should never have a collision and so it shouldn't matter
+  // if we allow overwrite or not. By not allowing overwrite we raise
+  // detectable errors rather than corrupting data
+  nsCOMPtr<mozIStorageStatement> stmt = !mOverwrite || keyUnset ?
+    mTransaction->GetCachedStatement(
+      "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
+      "VALUES (:osid, :key_value, :data, :file_ids)") :
+    mTransaction->GetCachedStatement(
+      "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data, file_ids) "
+      "VALUES (:osid, :key_value, :data, :file_ids)");
+  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  mozStorageStatementScoper scoper(stmt);
+
+  rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  NS_ASSERTION(!keyUnset || mObjectStore->IsAutoIncrement(),
+               "Should have key unless autoincrement");
+
+  PRInt64 autoIncrementNum = 0;
+
+  if (mObjectStore->IsAutoIncrement()) {
+    if (keyUnset) {
+      autoIncrementNum = mObjectStore->Info()->nextAutoIncrementId;
+      if (autoIncrementNum > (1LL << 53)) {
+        return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+      }
+      mKey.SetFromInteger(autoIncrementNum);
     }
-    else {
-      table.AssignLiteral("object_data");
-      value.AssignLiteral("key_value");
+    else if (mKey.IsInteger() &&
+             mKey.ToInteger() >= mObjectStore->Info()->nextAutoIncrementId) {
+      // XXX Once we support floats, we should use floor(mKey.ToFloat()) here
+      autoIncrementNum = mKey.ToInteger();
     }
 
-    nsCString query = NS_LITERAL_CSTRING("SELECT data FROM ") + table +
-                      NS_LITERAL_CSTRING(" WHERE ") + value +
-                      NS_LITERAL_CSTRING(" = :") + id +
-                      NS_LITERAL_CSTRING(" AND object_store_id = :") + osidStr;
-
-    stmt = mTransaction->GetCachedStatement(query);
-    NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    mozStorageStatementScoper scoper(stmt);
-
-    rv = stmt->BindInt64ByName(osidStr, osid);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    rv = mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("id"));
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    bool hasResult;
-    rv = stmt->ExecuteStep(&hasResult);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    if (hasResult) {
-      return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
+    if (keyUnset && !keyPath.IsEmpty()) {
+      // Special case where someone put an object into an autoIncrement'ing
+      // objectStore with no key in its keyPath set. We needed to figure out
+      // which row id we would get above before we could set that properly.
+
+      // This is a duplicate of the js engine's byte munging here
+      union {
+        jsdouble d;
+        PRUint64 u;
+      } pun;
+    
+      pun.d = SwapBytes(static_cast<PRUint64>(mKey.ToInteger()));    
+
+      JSAutoStructuredCloneBuffer& buffer = mCloneWriteInfo.mCloneBuffer;
+      PRUint64 offsetToKeyProp = mCloneWriteInfo.mOffsetToKeyProp;
+
+      memcpy((char*)buffer.data() + offsetToKeyProp, &pun.u, sizeof(PRUint64));
     }
   }
 
+  mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key_value"));
+
+  // Compress the bytes before adding into the database.
+  const char* uncompressed =
+    reinterpret_cast<const char*>(mCloneWriteInfo.mCloneBuffer.data());
+  size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes();
+
+  size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
+  // This will hold our compressed data until the end of the method. The
+  // BindBlobByName function will copy it.
+  nsAutoArrayPtr<char> compressed(new char[compressedLength]);
+
+  snappy::RawCompress(uncompressed, uncompressedLength, compressed.get(),
+                      &compressedLength);
+
+  const PRUint8* dataBuffer = reinterpret_cast<const PRUint8*>(compressed.get());
+  size_t dataBufferLength = compressedLength;
+
+  rv = stmt->BindBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer,
+                            dataBufferLength);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  // Handle blobs
   nsRefPtr<FileManager> fileManager = mDatabase->Manager();
   nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
   NS_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsAutoString fileIds;
 
   for (PRUint32 index = 0; index < mCloneWriteInfo.mBlobs.Length(); index++) {
     nsCOMPtr<nsIDOMBlob>& domBlob = mCloneWriteInfo.mBlobs[index];
@@ -2077,203 +2010,48 @@ AddHelper::DoDatabaseWork(mozIStorageCon
     }
 
     if (index) {
       fileIds.Append(NS_LITERAL_STRING(" "));
     }
     fileIds.AppendInt(id);
   }
 
-  // Now we add it to the database (or update, depending on our variables).
-  stmt = mTransaction->AddStatement(true, mayOverwrite, autoIncrement);
-  NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  mozStorageStatementScoper scoper(stmt);
-
-  NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
-
-  rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  if (!autoIncrement || mayOverwrite) {
-    NS_ASSERTION(!mKey.IsUnset(), "This shouldn't happen!");
-
-    rv = mKey.BindToStatement(stmt, keyValue);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  NS_NAMED_LITERAL_CSTRING(data, "data");
-
-  // This will hold our compressed data until the end of the method. The
-  // BindBlobByName function will copy it.
-  nsAutoArrayPtr<char> compressed;
-
-  // This points to the compressed buffer.
-  const PRUint8* dataBuffer = nsnull;
-  size_t dataBufferLength = 0;
-
-  // If we're going to modify the buffer later to add a key property on an
-  // autoIncrement objectStore then we will wait to compress our data until we
-  // have the appropriate key value.
-  if (autoIncrement && !mOverwrite && !keyPath.IsEmpty() && unsetKey) {
-    rv = stmt->BindInt32ByName(data, 0);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  }
-  else {
-    // Compress the bytes before adding into the database.
-    const char* uncompressed =
-      reinterpret_cast<const char*>(mCloneWriteInfo.mCloneBuffer.data());
-    size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes();
-
-    size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
-    compressed = new char[compressedLength];
-
-    snappy::RawCompress(uncompressed, uncompressedLength, compressed.get(),
-                        &compressedLength);
-
-    dataBuffer = reinterpret_cast<const PRUint8*>(compressed.get());
-    dataBufferLength = compressedLength;
-
-    rv = stmt->BindBlobByName(data, dataBuffer, dataBufferLength);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  }
-
   if (fileIds.IsEmpty()) {
     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids"));
   } else {
     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds);
   }
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = stmt->Execute();
-  if (NS_FAILED(rv)) {
-    if (mayOverwrite && rv == NS_ERROR_STORAGE_CONSTRAINT) {
-      scoper.Abandon();
-
-      rv = stmt->Reset();
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      stmt = mTransaction->AddStatement(false, true, autoIncrement);
-      NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      mozStorageStatementScoper scoper2(stmt);
-
-      rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      NS_ASSERTION(!mKey.IsUnset(), "This shouldn't happen!");
-
-      rv = mKey.BindToStatement(stmt, keyValue);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      NS_ASSERTION(dataBuffer && dataBufferLength, "These should be set!");
-
-      rv = stmt->BindBlobByName(data, dataBuffer, dataBufferLength);
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      if (fileIds.IsEmpty()) {
-        rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids"));
-      } else {
-        rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds);
-      }
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      rv = stmt->Execute();
-    }
-
-    if (NS_FAILED(rv)) {
-      return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
-    }
+  if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
+    NS_ASSERTION(!keyUnset, "Generated key had a collision!?");
+    return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
-
-  // If we are supposed to generate a key, get the new id.
-  if (autoIncrement && !mayOverwrite) {
-#ifdef DEBUG
-    PRInt64 oldKey = unsetKey ? 0 : mKey.ToInteger();
-#endif
-
-    PRInt64 newIntKey;
-    rv = aConnection->GetLastInsertRowID(&newIntKey);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-    rv = mKey.SetFromInteger(newIntKey);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-#ifdef DEBUG
-    NS_ASSERTION(mKey.IsInteger(), "Bad key value!");
-    if (!unsetKey) {
-      NS_ASSERTION(mKey.ToInteger() == oldKey, "Something went haywire!");
-    }
-#endif
-
-    if (!keyPath.IsEmpty() && unsetKey) {
-      // Special case where someone put an object into an autoIncrement'ing
-      // objectStore with no key in its keyPath set. We needed to figure out
-      // which row id we would get above before we could set that properly.
-      rv = mObjectStore->ModifyValueForNewKey(mCloneWriteInfo, mKey);
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      scoper.Abandon();
-      rv = stmt->Reset();
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      stmt = mTransaction->AddStatement(false, true, true);
-      NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      mozStorageStatementScoper scoper2(stmt);
-
-      rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      rv = mKey.BindToStatement(stmt, keyValue);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      NS_ASSERTION(!dataBuffer && !dataBufferLength, "These should be unset!");
-
-      const char* uncompressed =
-        reinterpret_cast<const char*>(mCloneWriteInfo.mCloneBuffer.data());
-      size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes();
-
-      size_t compressedLength =
-        snappy::MaxCompressedLength(uncompressedLength);
-      compressed = new char[compressedLength];
-
-      snappy::RawCompress(uncompressed, uncompressedLength, compressed.get(),
-                          &compressedLength);
-
-      dataBuffer = reinterpret_cast<const PRUint8*>(compressed.get());
-      dataBufferLength = compressedLength;
-
-      rv = stmt->BindBlobByName(data, dataBuffer, dataBufferLength);
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      if (fileIds.IsEmpty()) {
-        rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids"));
-      } else {
-        rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds);
-      }
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-      rv = stmt->Execute();
-      NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-    }
-  }
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  PRInt64 objectDataId;
+  rv = aConnection->GetLastInsertRowID(&objectDataId);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   // Update our indexes if needed.
   if (mOverwrite || !mIndexUpdateInfo.IsEmpty()) {
-    PRInt64 objectDataId = autoIncrement ? mKey.ToInteger() : LL_MININT;
-    rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey,
-                                       autoIncrement, mOverwrite,
+    rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey, mOverwrite,
                                        objectDataId, mIndexUpdateInfo);
     if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
       return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
     }
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   }
 
+  if (autoIncrementNum) {
+    mObjectStore->Info()->nextAutoIncrementId = autoIncrementNum + 1;
+  }
+
   return NS_OK;
 }
 
 nsresult
 AddHelper::GetSuccessResult(JSContext* aCx,
                             jsval* aVal)
 {
   NS_ASSERTION(!mKey.IsUnset(), "Badness!");
@@ -2283,44 +2061,31 @@ AddHelper::GetSuccessResult(JSContext* a
   return mKey.ToJSVal(aCx, aVal);
 }
 
 nsresult
 GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
 {
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
-  nsCString table;
-  nsCString value;
-  if (mObjectStore->IsAutoIncrement()) {
-    table.AssignLiteral("ai_object_data");
-    value.AssignLiteral("id");
-  }
-  else {
-    table.AssignLiteral("object_data");
-    value.AssignLiteral("key_value");
-  }
-
   nsCString keyRangeClause;
-  mKeyRange->GetBindingClause(value, keyRangeClause);
+  mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause);
 
   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
 
-  NS_NAMED_LITERAL_CSTRING(osid, "osid");
-
-  nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM ") + table +
-                    NS_LITERAL_CSTRING(" WHERE object_store_id = :") + osid +
+  nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
+                                       "WHERE object_store_id = :osid") +
                     keyRangeClause + NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = mKeyRange->BindToStatement(stmt);
   NS_ENSURE_SUCCESS(rv, rv);
 
   bool hasResult;
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -2346,44 +2111,32 @@ GetHelper::GetSuccessResult(JSContext* a
   return NS_OK;
 }
 
 nsresult
 DeleteHelper::DoDatabaseWork(mozIStorageConnection* /*aConnection */)
 {
   NS_ASSERTION(mKeyRange, "Must have a key range here!");
 
-  nsCString table;
-  nsCString value;
-  if (mObjectStore->IsAutoIncrement()) {
-    table.AssignLiteral("ai_object_data");
-    value.AssignLiteral("id");
-  }
-  else {
-    table.AssignLiteral("object_data");
-    value.AssignLiteral("key_value");
-  }
-
   nsCString keyRangeClause;
-  mKeyRange->GetBindingClause(value, keyRangeClause);
+  mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause);
 
   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
 
-  NS_NAMED_LITERAL_CSTRING(osid, "osid");
-
-  nsCString query = NS_LITERAL_CSTRING("DELETE FROM ") + table +
-                    NS_LITERAL_CSTRING(" WHERE object_store_id = :") + osid +
+  nsCString query = NS_LITERAL_CSTRING("DELETE FROM object_data "
+                                       "WHERE object_store_id = :osid") +
                     keyRangeClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
+                                      mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = mKeyRange->BindToStatement(stmt);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = stmt->Execute();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
@@ -2398,28 +2151,20 @@ DeleteHelper::GetSuccessResult(JSContext
   return NS_OK;
 }
 
 nsresult
 ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   NS_PRECONDITION(aConnection, "Passed a null connection!");
 
-  nsCString table;
-  if (mObjectStore->IsAutoIncrement()) {
-    table.AssignLiteral("ai_object_data");
-  }
-  else {
-    table.AssignLiteral("object_data");
-  }
-
-  nsCString query = NS_LITERAL_CSTRING("DELETE FROM ") + table +
-                    NS_LITERAL_CSTRING(" WHERE object_store_id = :osid");
-
-  nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
+  nsCOMPtr<mozIStorageStatement> stmt =
+    mTransaction->GetCachedStatement(
+      NS_LITERAL_CSTRING("DELETE FROM object_data "
+                         "WHERE object_store_id = :osid"));
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
                                       mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
@@ -2427,64 +2172,53 @@ ClearHelper::DoDatabaseWork(mozIStorageC
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
 nsresult
 OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
-  nsCString table;
-  nsCString keyColumn;
-
-  if (mObjectStore->IsAutoIncrement()) {
-    table.AssignLiteral("ai_object_data");
-    keyColumn.AssignLiteral("id");
-  }
-  else {
-    table.AssignLiteral("object_data");
-    keyColumn.AssignLiteral("key_value");
-  }
-
-  NS_NAMED_LITERAL_CSTRING(id, "id");
+  NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
 
   nsCString keyRangeClause;
   if (mKeyRange) {
-    mKeyRange->GetBindingClause(keyColumn, keyRangeClause);
+    mKeyRange->GetBindingClause(keyValue, keyRangeClause);
   }
 
-  nsCAutoString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + keyColumn;
+  nsCAutoString directionClause;
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
-      directionClause += NS_LITERAL_CSTRING(" ASC");
+      directionClause.AssignLiteral(" ORDER BY key_value ASC");
       break;
 
     case nsIIDBCursor::PREV:
     case nsIIDBCursor::PREV_NO_DUPLICATE:
-      directionClause += NS_LITERAL_CSTRING(" DESC");
+      directionClause.AssignLiteral(" ORDER BY key_value DESC");
       break;
 
     default:
       NS_NOTREACHED("Unknown direction type!");
   }
 
-  nsCString firstQuery = NS_LITERAL_CSTRING("SELECT ") + keyColumn +
-                         NS_LITERAL_CSTRING(", data, file_ids FROM ") + table +
-                         NS_LITERAL_CSTRING(" WHERE object_store_id = :") +
-                         id + keyRangeClause + directionClause +
+  nsCString firstQuery = NS_LITERAL_CSTRING("SELECT key_value, data, file_ids "
+                                            "FROM object_data "
+                                            "WHERE object_store_id = :id") +
+                         keyRangeClause + directionClause +
                          NS_LITERAL_CSTRING(" LIMIT 1");
 
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(firstQuery);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(id, mObjectStore->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
+                                      mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     rv = mKeyRange->BindToStatement(stmt);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   bool hasResult;
@@ -2508,59 +2242,57 @@ OpenCursorHelper::DoDatabaseWork(mozISto
   nsCAutoString continueToKeyRangeClause;
 
   NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
 
   switch (mDirection) {
     case nsIIDBCursor::NEXT:
     case nsIIDBCursor::NEXT_NO_DUPLICATE:
-      AppendConditionClause(keyColumn, currentKey, false, false,
+      AppendConditionClause(keyValue, currentKey, false, false,
                             keyRangeClause);
-      AppendConditionClause(keyColumn, currentKey, false, true,
+      AppendConditionClause(keyValue, currentKey, false, true,
                             continueToKeyRangeClause);
       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
-        AppendConditionClause(keyColumn, rangeKey, true,
+        AppendConditionClause(keyValue, rangeKey, true,
                               !mKeyRange->IsUpperOpen(), keyRangeClause);
-        AppendConditionClause(keyColumn, rangeKey, true,
+        AppendConditionClause(keyValue, rangeKey, true,
                               !mKeyRange->IsUpperOpen(),
                               continueToKeyRangeClause);
         mRangeKey = mKeyRange->Upper();
       }
       break;
 
     case nsIIDBCursor::PREV:
     case nsIIDBCursor::PREV_NO_DUPLICATE:
-      AppendConditionClause(keyColumn, currentKey, true, false, keyRangeClause);
-      AppendConditionClause(keyColumn, currentKey, true, true,
+      AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause);
+      AppendConditionClause(keyValue, currentKey, true, true,
                            continueToKeyRangeClause);
       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
-        AppendConditionClause(keyColumn, rangeKey, false,
+        AppendConditionClause(keyValue, rangeKey, false,
                               !mKeyRange->IsLowerOpen(), keyRangeClause);
-        AppendConditionClause(keyColumn, rangeKey, false,
+        AppendConditionClause(keyValue, rangeKey, false,
                               !mKeyRange->IsLowerOpen(),
                               continueToKeyRangeClause);
         mRangeKey = mKeyRange->Lower();
       }
       break;
 
     default:
       NS_NOTREACHED("Unknown direction type!");
   }
 
-  mContinueQuery = NS_LITERAL_CSTRING("SELECT ") + keyColumn +
-                   NS_LITERAL_CSTRING(", data, file_ids FROM ") + table +
-                   NS_LITERAL_CSTRING(" WHERE object_store_id = :") + id +
-                   keyRangeClause + directionClause +
+  NS_NAMED_LITERAL_CSTRING(queryStart, "SELECT key_value, data, file_ids "
+                                       "FROM object_data "
+                                       "WHERE object_store_id = :id");
+
+  mContinueQuery = queryStart + keyRangeClause + directionClause +
                    NS_LITERAL_CSTRING(" LIMIT ");
 
-  mContinueToQuery = NS_LITERAL_CSTRING("SELECT ") + keyColumn +
-                     NS_LITERAL_CSTRING(", data, file_ids FROM ") + table +
-                     NS_LITERAL_CSTRING(" WHERE object_store_id = :") + id +
-                     continueToKeyRangeClause + directionClause +
+  mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause +
                      NS_LITERAL_CSTRING(" LIMIT ");
 
   return NS_OK;
 }
 
 nsresult
 OpenCursorHelper::GetSuccessResult(JSContext* aCx,
                                    jsval* aVal)
@@ -2670,19 +2402,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)"
+      "multientry, object_store_id) "
+    "VALUES (:id, :name, :key_path, :unique, :multientry, :osid)"
   );
   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);
@@ -2701,20 +2432,16 @@ CreateIndexHelper::DoDatabaseWork(mozISt
   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);
-
   if (NS_FAILED(stmt->Execute())) {
     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
   }
 
 #ifdef DEBUG
   {
     PRInt64 id;
     aConnection->GetLastInsertRowID(&id);
@@ -2729,32 +2456,20 @@ CreateIndexHelper::DoDatabaseWork(mozISt
   }
 
   return NS_OK;
 }
 
 nsresult
 CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
 {
-  nsCAutoString table;
-  nsCAutoString columns;
-  if (mIndex->IsAutoIncrement()) {
-    table.AssignLiteral("ai_object_data");
-    columns.AssignLiteral("id, data, file_ids");
-  }
-  else {
-    table.AssignLiteral("object_data");
-    columns.AssignLiteral("id, data, file_ids, key_value");
-  }
-
-  nsCString query = NS_LITERAL_CSTRING("SELECT ") + columns +
-                    NS_LITERAL_CSTRING(" FROM ") + table +
-                    NS_LITERAL_CSTRING(" WHERE object_store_id = :osid");
-
-  nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
+  nsCOMPtr<mozIStorageStatement> stmt =
+    mTransaction->GetCachedStatement(
+      NS_LITERAL_CSTRING("SELECT id, data, file_ids, key_value FROM object_data "
+                         "WHERE object_store_id = :osid"));
   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);
 
@@ -2808,27 +2523,21 @@ CreateIndexHelper::InsertDataFromObjectS
                                                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, 3);
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-    else {
-      key.SetFromInteger(objectDataID);
-    }
+    rv = key.SetFromStatement(stmt, 3);
+    NS_ENSURE_SUCCESS(rv, rv);
 
     rv = IDBObjectStore::UpdateIndexes(mTransaction, mIndex->Id(),
-                                       key, mIndex->IsAutoIncrement(),
-                                       false, objectDataID, updateInfo);
+                                       key, false, objectDataID, updateInfo);
     NS_ENSURE_SUCCESS(rv, rv);
 
   } while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   return NS_OK;
 }
 
@@ -2854,76 +2563,65 @@ DeleteIndexHelper::DoDatabaseWork(mozISt
   }
 
   return NS_OK;
 }
 
 nsresult
 GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
-  nsCString table;
-  nsCString keyColumn;
-
-  if (mObjectStore->IsAutoIncrement()) {
-    table.AssignLiteral("ai_object_data");
-    keyColumn.AssignLiteral("id");
-  }
-  else {
-    table.AssignLiteral("object_data");
-    keyColumn.AssignLiteral("key_value");
-  }
-
-  NS_NAMED_LITERAL_CSTRING(osid, "osid");
   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
 
   nsCAutoString keyRangeClause;
   if (mKeyRange) {
     if (!mKeyRange->Lower().IsUnset()) {
-      keyRangeClause = NS_LITERAL_CSTRING(" AND ") + keyColumn;
+      keyRangeClause = NS_LITERAL_CSTRING(" AND key_value");
       if (mKeyRange->IsLowerOpen()) {
         keyRangeClause.AppendLiteral(" > :");
       }
       else {
         keyRangeClause.AppendLiteral(" >= :");
       }
       keyRangeClause.Append(lowerKeyName);
     }
 
     if (!mKeyRange->Upper().IsUnset()) {
-      keyRangeClause += NS_LITERAL_CSTRING(" AND ") + keyColumn;
+      keyRangeClause += NS_LITERAL_CSTRING(" AND key_value");
       if (mKeyRange->IsUpperOpen()) {
         keyRangeClause.AppendLiteral(" < :");
       }
       else {
         keyRangeClause.AppendLiteral(" <= :");
       }
       keyRangeClause.Append(upperKeyName);
     }
   }
 
   nsCAutoString limitClause;
   if (mLimit != PR_UINT32_MAX) {
     limitClause.AssignLiteral(" LIMIT ");
     limitClause.AppendInt(mLimit);
   }
 
-  nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM ") + table +
-                    NS_LITERAL_CSTRING(" WHERE object_store_id = :") + osid +
-                    keyRangeClause + NS_LITERAL_CSTRING(" ORDER BY ") +
-                    keyColumn + NS_LITERAL_CSTRING(" ASC") + limitClause;
+  nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
+                                       "WHERE object_store_id = :osid") +
+                    keyRangeClause +
+                    NS_LITERAL_CSTRING(" ORDER BY key_value ASC") +
+                    limitClause;
 
   mCloneReadInfos.SetCapacity(50);
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
+                                      mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     if (!mKeyRange->Lower().IsUnset()) {
       rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     if (!mKeyRange->Upper().IsUnset()) {
@@ -2967,67 +2665,55 @@ GetAllHelper::GetSuccessResult(JSContext
 
   NS_ENSURE_SUCCESS(rv, rv);
   return NS_OK;
 }
 
 nsresult
 CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
-  nsCString table;
-  nsCString keyColumn;
-
-  if (mObjectStore->IsAutoIncrement()) {
-    table.AssignLiteral("ai_object_data");
-    keyColumn.AssignLiteral("id");
-  }
-  else {
-    table.AssignLiteral("object_data");
-    keyColumn.AssignLiteral("key_value");
-  }
-
-  NS_NAMED_LITERAL_CSTRING(osid, "osid");
   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
 
   nsCAutoString keyRangeClause;
   if (mKeyRange) {
     if (!mKeyRange->Lower().IsUnset()) {
-      keyRangeClause = NS_LITERAL_CSTRING(" AND ") + keyColumn;
+      keyRangeClause = NS_LITERAL_CSTRING(" AND key_value");
       if (mKeyRange->IsLowerOpen()) {
         keyRangeClause.AppendLiteral(" > :");
       }
       else {
         keyRangeClause.AppendLiteral(" >= :");
       }
       keyRangeClause.Append(lowerKeyName);
     }
 
     if (!mKeyRange->Upper().IsUnset()) {
-      keyRangeClause += NS_LITERAL_CSTRING(" AND ") + keyColumn;
+      keyRangeClause += NS_LITERAL_CSTRING(" AND key_value");
       if (mKeyRange->IsUpperOpen()) {
         keyRangeClause.AppendLiteral(" < :");
       }
       else {
         keyRangeClause.AppendLiteral(" <= :");
       }
       keyRangeClause.Append(upperKeyName);
     }
   }
 
-  nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM ") + table +
-                    NS_LITERAL_CSTRING(" WHERE object_store_id = :") + osid +
+  nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM object_data "
+                                       "WHERE object_store_id = :osid") +
                     keyRangeClause;
 
   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   mozStorageStatementScoper scoper(stmt);
 
-  nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id());
+  nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
+                                      mObjectStore->Id());
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mKeyRange) {
     if (!mKeyRange->Lower().IsUnset()) {
       rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     if (!mKeyRange->Upper().IsUnset()) {
--- a/dom/indexedDB/IDBObjectStore.h
+++ b/dom/indexedDB/IDBObjectStore.h
@@ -67,17 +67,18 @@ class IDBObjectStore : public nsIIDBObje
 public:
   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
   NS_DECL_NSIIDBOBJECTSTORE
 
   NS_DECL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
 
   static already_AddRefed<IDBObjectStore>
   Create(IDBTransaction* aTransaction,
-         const ObjectStoreInfo* aInfo);
+         ObjectStoreInfo* aInfo,
+         nsIAtom* aDatabaseId);
 
   static bool
   IsValidKeyPath(JSContext* aCx, const nsAString& aKeyPath);
 
   static nsresult
   AppendIndexUpdateInfo(PRInt64 aIndexID,
                         const nsAString& aKeyPath,
                         bool aUnique,
@@ -85,17 +86,16 @@ public:
                         JSContext* aCx,
                         jsval aObject,
                         nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
 
   static nsresult
   UpdateIndexes(IDBTransaction* aTransaction,
                 PRInt64 aObjectStoreId,
                 const Key& aObjectStoreKey,
-                bool aAutoIncrement,
                 bool aOverwrite,
                 PRInt64 aObjectDataId,
                 const nsTArray<IndexUpdateInfo>& aUpdateInfoArray);
 
   static nsresult
   GetStructuredCloneReadInfoFromStatement(mozIStorageStatement* aStatement,
                                           PRUint32 aDataIndex,
                                           PRUint32 aFileIdsIndex,
@@ -162,18 +162,20 @@ public:
     return !mKeyPath.IsVoid();
   }
 
   IDBTransaction* Transaction()
   {
     return mTransaction;
   }
 
-  nsresult ModifyValueForNewKey(StructuredCloneWriteInfo& aCloneWriteInfo,
-                                Key& aKey);
+  ObjectStoreInfo* Info()
+  {
+    return mInfo;
+  }
 
 protected:
   IDBObjectStore();
   ~IDBObjectStore();
 
   nsresult GetAddInfo(JSContext* aCx,
                       jsval aValue,
                       jsval aKeyVal,
@@ -194,16 +196,17 @@ private:
   nsCOMPtr<nsIScriptContext> mScriptContext;
   nsCOMPtr<nsPIDOMWindow> mOwner;
 
   PRInt64 mId;
   nsString mName;
   nsString mKeyPath;
   bool mAutoIncrement;
   nsCOMPtr<nsIAtom> mDatabaseId;
+  nsRefPtr<ObjectStoreInfo> mInfo;
   PRUint32 mStructuredCloneVersion;
 
   nsTArray<nsRefPtr<IDBIndex> > mCreatedIndexes;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbobjectstore_h__
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -116,16 +116,18 @@ IDBTransaction::Create(IDBDatabase* aDat
 
   nsRefPtr<IDBTransaction> transaction = new IDBTransaction();
 
   transaction->mScriptContext = aDatabase->ScriptContext();
   transaction->mOwner = aDatabase->Owner();
 
   transaction->mDatabase = aDatabase;
   transaction->mMode = aMode;
+  
+  transaction->mDatabaseInfo = aDatabase->Info();
 
   if (!transaction->mObjectStoreNames.AppendElements(aObjectStoreNames)) {
     NS_ERROR("Out of memory!");
     return nsnull;
   }
 
   if (!transaction->mCachedStatements.Init()) {
     NS_ERROR("Failed to initialize hash!");
@@ -206,18 +208,23 @@ IDBTransaction::OnRequestFinished()
     NS_ASSERTION(mAborted || mReadyState == nsIIDBTransaction::LOADING,
                  "Bad state!");
     mReadyState = IDBTransaction::COMMITTING;
     CommitOrRollback();
   }
 }
 
 void
-IDBTransaction::ReleaseCachedObjectStore(const nsAString& aName)
+IDBTransaction::RemoveObjectStore(const nsAString& aName)
 {
+  NS_ASSERTION(mMode == nsIIDBTransaction::VERSION_CHANGE,
+               "Only remove object stores on VERSION_CHANGE transactions");
+
+  mDatabaseInfo->RemoveObjectStore(aName);
+
   for (PRUint32 i = 0; i < mCreatedObjectStores.Length(); i++) {
     if (mCreatedObjectStores[i]->Name() == aName) {
       mCreatedObjectStores.RemoveElementAt(i);
       break;
     }
   }
 }
 
@@ -232,17 +239,18 @@ IDBTransaction::SetTransactionListener(I
 nsresult
 IDBTransaction::CommitOrRollback()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
   NS_ENSURE_STATE(pool);
 
-  nsRefPtr<CommitHelper> helper(new CommitHelper(this, mListener));
+  nsRefPtr<CommitHelper> helper(new CommitHelper(this, mListener,
+                                                 mCreatedObjectStores));
 
   mCachedStatements.Enumerate(DoomCachedStatements, helper);
   NS_ASSERTION(!mCachedStatements.Count(), "Statements left!");
 
   nsresult rv = pool->Dispatch(this, helper, true, helper);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
@@ -359,129 +367,16 @@ IDBTransaction::GetOrCreateConnection(mo
   }
 
   nsCOMPtr<mozIStorageConnection> result(mConnection);
   result.forget(aResult);
   return NS_OK;
 }
 
 already_AddRefed<mozIStorageStatement>
-IDBTransaction::AddStatement(bool aCreate,
-                             bool aOverwrite,
-                             bool aAutoIncrement)
-{
-#ifdef DEBUG
-  if (!aCreate) {
-    NS_ASSERTION(aOverwrite, "Bad param combo!");
-  }
-#endif
-
-  if (aAutoIncrement) {
-    if (aCreate) {
-      if (aOverwrite) {
-        return GetCachedStatement(
-          "INSERT OR FAIL INTO ai_object_data (object_store_id, id, data, "
-          "file_ids) "
-          "VALUES (:osid, :key_value, :data, :file_ids)"
-        );
-      }
-      return GetCachedStatement(
-        "INSERT INTO ai_object_data (object_store_id, data, file_ids) "
-        "VALUES (:osid, :data, :file_ids)"
-      );
-    }
-    return GetCachedStatement(
-      "UPDATE ai_object_data "
-      "SET data = :data, file_ids = :file_ids "
-      "WHERE object_store_id = :osid "
-      "AND id = :key_value"
-    );
-  }
-  if (aCreate) {
-    if (aOverwrite) {
-      return GetCachedStatement(
-        "INSERT OR FAIL INTO object_data (object_store_id, key_value, data, "
-        "file_ids) "
-        "VALUES (:osid, :key_value, :data, :file_ids)"
-      );
-    }
-    return GetCachedStatement(
-      "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
-      "VALUES (:osid, :key_value, :data, :file_ids)"
-    );
-  }
-  return GetCachedStatement(
-    "UPDATE object_data "
-    "SET data = :data, file_ids = :file_ids "
-    "WHERE object_store_id = :osid "
-    "AND key_value = :key_value"
-  );
-}
-
-already_AddRefed<mozIStorageStatement>
-IDBTransaction::IndexDataInsertStatement(bool aAutoIncrement,
-                                         bool aUnique)
-{
-  if (aAutoIncrement) {
-    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 "
-        "(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 ("
-      "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)
-{
-  if (aAutoIncrement) {
-    if (aUnique) {
-      return GetCachedStatement(
-        "DELETE FROM ai_unique_index_data "
-        "WHERE ai_object_data_id = :object_data_id"
-      );
-    }
-    return GetCachedStatement(
-      "DELETE FROM ai_index_data "
-      "WHERE ai_object_data_id = :object_data_id"
-    );
-  }
-  if (aUnique) {
-    return GetCachedStatement(
-      "DELETE FROM unique_index_data "
-      "WHERE object_data_id = :object_data_id"
-    );
-  }
-  return GetCachedStatement(
-    "DELETE FROM index_data "
-    "WHERE object_data_id = :object_data_id"
-  );
-}
-
-already_AddRefed<mozIStorageStatement>
 IDBTransaction::GetCachedStatement(const nsACString& aQuery)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!aQuery.IsEmpty(), "Empty sql statement!");
   NS_ASSERTION(mConnection, "No connection!");
 
   nsCOMPtr<mozIStorageStatement> stmt;
 
@@ -552,23 +447,19 @@ IDBTransaction::GetOrCreateObjectStore(c
   for (PRUint32 index = 0; index < mCreatedObjectStores.Length(); index++) {
     nsRefPtr<IDBObjectStore>& objectStore = mCreatedObjectStores[index];
     if (objectStore->Name() == aName) {
       retval = objectStore;
       return retval.forget();
     }
   }
 
-  retval = IDBObjectStore::Create(this, aObjectStoreInfo);
-  NS_ENSURE_TRUE(retval, nsnull);
+  retval = IDBObjectStore::Create(this, aObjectStoreInfo, mDatabaseInfo->id);
 
-  if (!mCreatedObjectStores.AppendElement(retval)) {
-    NS_WARNING("Out of memory!");
-    return nsnull;
-  }
+  mCreatedObjectStores.AppendElement(retval);
 
   return retval.forget();
 }
 
 void
 IDBTransaction::OnNewFileInfo(FileInfo* aFileInfo)
 {
   mCreatedFileInfos.AppendElement(aFileInfo);
@@ -653,22 +544,17 @@ IDBTransaction::GetObjectStoreNames(nsID
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   nsRefPtr<nsDOMStringList> list(new nsDOMStringList());
 
   nsAutoTArray<nsString, 10> stackArray;
   nsTArray<nsString>* arrayOfNames;
 
   if (mMode == IDBTransaction::VERSION_CHANGE) {
-    DatabaseInfo* info = mDatabase->Info();
-
-    if (!info->GetObjectStoreNames(stackArray)) {
-      NS_ERROR("Out of memory!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
+    mDatabaseInfo->GetObjectStoreNames(stackArray);
 
     arrayOfNames = &stackArray;
   }
   else {
     arrayOfNames = &mObjectStoreNames;
   }
 
   PRUint32 count = arrayOfNames->Length();
@@ -690,17 +576,17 @@ IDBTransaction::ObjectStore(const nsAStr
   if (!IsOpen()) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   ObjectStoreInfo* info = nsnull;
 
   if (mMode == nsIIDBTransaction::VERSION_CHANGE ||
       mObjectStoreNames.Contains(aName)) {
-    mDatabase->Info()->GetObjectStore(aName, &info);
+    info = mDatabaseInfo->GetObjectStore(aName);
   }
 
   if (!info) {
     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
   }
 
   nsRefPtr<IDBObjectStore> objectStore = GetOrCreateObjectStore(aName, info);
   NS_ENSURE_TRUE(objectStore, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -842,25 +728,33 @@ IDBTransaction::AfterProcessNextEvent(ns
     if(NS_FAILED(aThread->RemoveObserver(this))) {
       NS_ERROR("Failed to remove observer!");
     }
   }
 
   return NS_OK;
 }
 
-CommitHelper::CommitHelper(IDBTransaction* aTransaction,
-                           IDBTransactionListener* aListener)
+CommitHelper::CommitHelper(
+              IDBTransaction* aTransaction,
+              IDBTransactionListener* aListener,
+              const nsTArray<nsRefPtr<IDBObjectStore> >& aUpdatedObjectStores)
 : mTransaction(aTransaction),
   mListener(aListener),
-  mAborted(!!aTransaction->mAborted),
-  mHaveMetadata(false)
+  mAborted(!!aTransaction->mAborted)
 {
   mConnection.swap(aTransaction->mConnection);
   mUpdateFileRefcountFunction.swap(aTransaction->mUpdateFileRefcountFunction);
+
+  for (PRUint32 i = 0; i < aUpdatedObjectStores.Length(); i++) {
+    ObjectStoreInfo* info = aUpdatedObjectStores[i]->Info();
+    if (info->comittedAutoIncrementId != info->nextAutoIncrementId) {
+      mAutoIncrementObjectStores.AppendElement(aUpdatedObjectStores[i]);
+    }
+  }
 }
 
 CommitHelper::~CommitHelper()
 {
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(CommitHelper, nsIRunnable)
 
@@ -877,29 +771,21 @@ CommitHelper::Run()
     mTransaction->ClearCreatedFileInfos();
     if (mUpdateFileRefcountFunction) {
       mUpdateFileRefcountFunction->ClearFileInfoEntries();
       mUpdateFileRefcountFunction = nsnull;
     }
 
     nsCOMPtr<nsIDOMEvent> event;
     if (mAborted) {
-      if (mHaveMetadata) {
-        NS_ASSERTION(mTransaction->Mode() == nsIIDBTransaction::VERSION_CHANGE,
-                     "Bad transaction type!");
-
-        DatabaseInfo* dbInfo = mTransaction->Database()->Info();
-
-        if (NS_FAILED(IDBFactory::UpdateDatabaseMetadata(dbInfo, mOldVersion,
-                                                         mOldObjectStores))) {
-          NS_WARNING("Failed to update database metadata!");
-        }
-        else {
-          NS_ASSERTION(mOldObjectStores.IsEmpty(), "Should have swapped!");
-        }
+      if (mTransaction->Mode() == nsIIDBTransaction::VERSION_CHANGE) {
+        // This will make the database take a snapshot of it's DatabaseInfo
+        mTransaction->Database()->Close();
+        // Then remove the info from the hash as it contains invalid data.
+        DatabaseInfo::Remove(mTransaction->Database()->Id());
       }
 
       event = CreateGenericEvent(NS_LITERAL_STRING(ABORT_EVT_STR),
                                  eDoesBubble, eNotCancelable);
     }
     else {
       event = CreateGenericEvent(NS_LITERAL_STRING(COMPLETE_EVT_STR),
                                  eDoesNotBubble, eNotCancelable);
@@ -933,46 +819,39 @@ CommitHelper::Run()
   if (mConnection) {
     IndexedDatabaseManager::SetCurrentWindow(database->Owner());
 
     if (!mAborted && mUpdateFileRefcountFunction &&
         NS_FAILED(mUpdateFileRefcountFunction->UpdateDatabase(mConnection))) {
       mAborted = true;
     }
 
+    if (!mAborted && NS_FAILED(WriteAutoIncrementCounts())) {
+      mAborted = true;
+    }
+
     if (!mAborted) {
       NS_NAMED_LITERAL_CSTRING(release, "COMMIT TRANSACTION");
       if (NS_SUCCEEDED(mConnection->ExecuteSimpleSQL(release))) {
         if (mUpdateFileRefcountFunction) {
           mUpdateFileRefcountFunction->UpdateFileInfos();
         }
+        CommitAutoIncrementCounts();
       }
       else {
         mAborted = true;
       }
     }
 
     if (mAborted) {
+      RevertAutoIncrementCounts();
       NS_NAMED_LITERAL_CSTRING(rollback, "ROLLBACK TRANSACTION");
       if (NS_FAILED(mConnection->ExecuteSimpleSQL(rollback))) {
         NS_WARNING("Failed to rollback transaction!");
       }
-
-      if (mTransaction->Mode() == nsIIDBTransaction::VERSION_CHANGE) {
-        nsresult rv =
-          IDBFactory::LoadDatabaseInformation(mConnection,
-                                              mTransaction->Database()->Id(),
-                                              &mOldVersion, mOldObjectStores);
-        if (NS_SUCCEEDED(rv)) {
-          mHaveMetadata = true;
-        }
-        else {
-          NS_WARNING("Failed to get database information!");
-        }
-      }
     }
   }
 
   mDoomedObjects.Clear();
 
   if (mConnection) {
     if (mUpdateFileRefcountFunction) {
       nsresult rv = mConnection->RemoveFunction(
@@ -987,16 +866,65 @@ CommitHelper::Run()
 
     IndexedDatabaseManager::SetCurrentWindow(nsnull);
   }
 
   return NS_OK;
 }
 
 nsresult
+CommitHelper::WriteAutoIncrementCounts()
+{
+  nsCOMPtr<mozIStorageStatement> stmt;
+  nsresult rv;
+  for (PRUint32 i = 0; i < mAutoIncrementObjectStores.Length(); i++) {
+    ObjectStoreInfo* info = mAutoIncrementObjectStores[i]->Info();
+    if (!stmt) {
+      rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
+        "UPDATE object_store SET auto_increment = :ai "
+        "WHERE id = :osid;"), getter_AddRefs(stmt));
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+    else {
+      stmt->Reset();
+    }
+
+    rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), info->id);
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+    rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("ai"),
+                               info->nextAutoIncrementId);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = stmt->Execute();
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+  
+  return NS_OK;
+}
+
+void
+CommitHelper::CommitAutoIncrementCounts()
+{
+  for (PRUint32 i = 0; i < mAutoIncrementObjectStores.Length(); i++) {
+    ObjectStoreInfo* info = mAutoIncrementObjectStores[i]->Info();
+    info->comittedAutoIncrementId = info->nextAutoIncrementId;
+  }
+}
+
+void
+CommitHelper::RevertAutoIncrementCounts()
+{
+  for (PRUint32 i = 0; i < mAutoIncrementObjectStores.Length(); i++) {
+    ObjectStoreInfo* info = mAutoIncrementObjectStores[i]->Info();
+    info->nextAutoIncrementId = info->comittedAutoIncrementId;
+  }
+}
+
+nsresult
 UpdateRefcountFunction::Init()
 {
   NS_ENSURE_TRUE(mFileInfoEntries.Init(), NS_ERROR_OUT_OF_MEMORY);
 
   return NS_OK;
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(UpdateRefcountFunction, mozIStorageFunction)
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -102,50 +102,35 @@ public:
          bool aDispatchDelayed);
 
   // nsIDOMEventTarget
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   void OnNewRequest();
   void OnRequestFinished();
 
-  void ReleaseCachedObjectStore(const nsAString& aName);
+  void RemoveObjectStore(const nsAString& aName);
 
   void SetTransactionListener(IDBTransactionListener* aListener);
 
   bool StartSavepoint();
   nsresult ReleaseSavepoint();
   void RollbackSavepoint();
 
   // Only meant to be called on mStorageThread!
   nsresult GetOrCreateConnection(mozIStorageConnection** aConnection);
 
   already_AddRefed<mozIStorageStatement>
-  AddStatement(bool aCreate,
-               bool aOverwrite,
-               bool aAutoIncrement);
-
-  already_AddRefed<mozIStorageStatement>
-  IndexDataInsertStatement(bool aAutoIncrement,
-                           bool aUnique);
-
-  already_AddRefed<mozIStorageStatement>
-  IndexDataDeleteStatement(bool aAutoIncrement,
-                           bool aUnique);
-
-  already_AddRefed<mozIStorageStatement>
   GetCachedStatement(const nsACString& aQuery);
 
   template<int N>
   already_AddRefed<mozIStorageStatement>
   GetCachedStatement(const char (&aQuery)[N])
   {
-    nsCString query;
-    query.AssignLiteral(aQuery);
-    return GetCachedStatement(query);
+    return GetCachedStatement(NS_LITERAL_CSTRING(aQuery));
   }
 
   bool IsOpen() const;
 
   bool IsWriteAllowed() const
   {
     return mMode == nsIIDBTransaction::READ_WRITE ||
            mMode == nsIIDBTransaction::VERSION_CHANGE;
@@ -162,31 +147,37 @@ public:
   }
 
   IDBDatabase* Database()
   {
     NS_ASSERTION(mDatabase, "This should never be null!");
     return mDatabase;
   }
 
+  DatabaseInfo* DBInfo() const
+  {
+    return mDatabaseInfo;
+  }
+
   already_AddRefed<IDBObjectStore>
   GetOrCreateObjectStore(const nsAString& aName,
                          ObjectStoreInfo* aObjectStoreInfo);
 
   void OnNewFileInfo(FileInfo* aFileInfo);
 
   void ClearCreatedFileInfos();
 
 private:
   IDBTransaction();
   ~IDBTransaction();
 
   nsresult CommitOrRollback();
 
   nsRefPtr<IDBDatabase> mDatabase;
+  nsRefPtr<DatabaseInfo> mDatabaseInfo;
   nsTArray<nsString> mObjectStoreNames;
   PRUint16 mReadyState;
   PRUint16 mMode;
   PRUint32 mPendingRequests;
   PRUint32 mCreatedRecursionDepth;
 
   // Only touched on the main thread.
   nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
@@ -219,44 +210,51 @@ private:
 
 class CommitHelper : public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
   CommitHelper(IDBTransaction* aTransaction,
-               IDBTransactionListener* aListener);
+               IDBTransactionListener* aListener,
+               const nsTArray<nsRefPtr<IDBObjectStore> >& mUpdatedObjectStores);
   ~CommitHelper();
 
   template<class T>
   bool AddDoomedObject(nsCOMPtr<T>& aCOMPtr)
   {
     if (aCOMPtr) {
       if (!mDoomedObjects.AppendElement(do_QueryInterface(aCOMPtr))) {
         NS_ERROR("Out of memory!");
         return false;
       }
       aCOMPtr = nsnull;
     }
     return true;
   }
 
 private:
+  // Writes new autoincrement counts to database
+  nsresult WriteAutoIncrementCounts();
+
+  // Updates counts after a successful commit
+  void CommitAutoIncrementCounts();
+
+  // Reverts counts when a transaction is aborted
+  void RevertAutoIncrementCounts();
+
   nsRefPtr<IDBTransaction> mTransaction;
   nsRefPtr<IDBTransactionListener> mListener;
   nsCOMPtr<mozIStorageConnection> mConnection;
   nsRefPtr<UpdateRefcountFunction> mUpdateFileRefcountFunction;
   nsAutoTArray<nsCOMPtr<nsISupports>, 10> mDoomedObjects;
-
-  PRUint64 mOldVersion;
-  nsTArray<nsAutoPtr<ObjectStoreInfo> > mOldObjectStores;
+  nsAutoTArray<nsRefPtr<IDBObjectStore>, 10> mAutoIncrementObjectStores;
 
   bool mAborted;
-  bool mHaveMetadata;
 };
 
 class UpdateRefcountFunction : public mozIStorageFunction
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_MOZISTORAGEFUNCTION
 
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -33,16 +33,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "IndexedDatabaseManager.h"
+#include "DatabaseInfo.h"
 
 #include "nsIFile.h"
 #include "nsIObserverService.h"
 #include "nsIScriptObjectPrincipal.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsISHEntry.h"
 #include "nsISimpleEnumerator.h"
 #include "nsITimer.h"
@@ -74,19 +75,16 @@
 #define DEFAULT_SHUTDOWN_TIMER_MS 30000
 
 // Amount of space that IndexedDB databases may use by default in megabytes.
 #define DEFAULT_QUOTA_MB 50
 
 // Preference that users can set to override DEFAULT_QUOTA_MB
 #define PREF_INDEXEDDB_QUOTA "dom.indexedDB.warningQuota"
 
-// A bad TLS index number.
-#define BAD_TLS_INDEX (PRUintn)-1 
-
 USING_INDEXEDDB_NAMESPACE
 using namespace mozilla::services;
 using mozilla::Preferences;
 
 namespace {
 
 PRInt32 gShutdown = 0;
 PRInt32 gClosed = 0;
@@ -1178,16 +1176,18 @@ IndexedDatabaseManager::ClearDatabasesFo
   if (mLiveDatabases.Get(origin, &array)) {
     liveDatabases.AppendElements(*array);
   }
 
   // Invalidate all the live databases first.
   for (PRUint32 index = 0; index < liveDatabases.Length(); index++) {
     liveDatabases[index]->Invalidate();
   }
+  
+  DatabaseInfo::RemoveAllForOrigin(origin);
 
   // After everything has been invalidated the helper should be dispatched to
   // the end of the event queue.
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
--- a/dom/indexedDB/Key.h
+++ b/dom/indexedDB/Key.h
@@ -233,22 +233,20 @@ public:
   nsresult BindToStatement(mozIStorageStatement* aStatement,
                            const nsACString& aParamName) const
   {
     nsresult rv;
 
     if (IsString()) {
       rv = aStatement->BindStringByName(aParamName, ToString());
     }
-    else if (IsInteger()) {
+    else {
+      NS_ASSERTION(IsInteger(), "Bad key!");
       rv = aStatement->BindInt64ByName(aParamName, ToInteger());
     }
-    else {
-      NS_NOTREACHED("Bad key!");
-    }
 
     return NS_SUCCEEDED(rv) ? NS_OK : NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   nsresult SetFromStatement(mozIStorageStatement* aStatement,
                             PRUint32 aIndex)
   {
     PRInt32 columnType;
--- a/dom/indexedDB/OpenDatabaseHelper.cpp
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -55,17 +55,17 @@ USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 // If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major
 // schema version.
 PR_STATIC_ASSERT(JS_STRUCTURED_CLONE_VERSION == 1);
 
 // Major schema version. Bump for almost everything.
-const PRUint32 kMajorSchemaVersion = 10;
+const PRUint32 kMajorSchemaVersion = 11;
 
 // Minor schema version. Should almost always be 0 (maybe bump on release
 // branches if we have to).
 const PRUint32 kMinorSchemaVersion = 0;
 
 // The schema version we store in the SQLite database is a (signed) 32-bit
 // integer. The major version is left-shifted 4 bits so the max value is
 // 0xFFFFFFF. The minor version occupies the lower 4 bits and its max is 0xF.
@@ -165,48 +165,16 @@ CreateFileTables(mozIStorageConnection* 
     "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
     "BEGIN "
       "SELECT update_refcount(OLD.file_ids, NULL); "
     "END;"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TRIGGER ai_object_data_insert_trigger "
-    "AFTER INSERT ON ai_object_data "
-    "FOR EACH ROW "
-    "WHEN NEW.file_ids IS NOT NULL "
-    "BEGIN "
-      "SELECT update_refcount(NULL, NEW.file_ids); "
-    "END;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TRIGGER ai_object_data_update_trigger "
-    "AFTER UPDATE OF file_ids ON ai_object_data "
-    "FOR EACH ROW "
-    "WHEN OLD.file_ids IS NOT NULL OR NEW.file_ids IS NOT NULL "
-    "BEGIN "
-      "SELECT update_refcount(OLD.file_ids, NEW.file_ids); "
-    "END;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TRIGGER ai_object_data_delete_trigger "
-    "AFTER DELETE ON ai_object_data "
-    "FOR EACH ROW WHEN OLD.file_ids IS NOT NULL "
-    "BEGIN "
-      "SELECT update_refcount(OLD.file_ids, NULL); "
-    "END;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TRIGGER file_update_trigger "
     "AFTER UPDATE ON file "
     "FOR EACH ROW WHEN NEW.refcount = 0 "
     "BEGIN "
       "DELETE FROM file WHERE id = OLD.id; "
     "END;"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
@@ -252,41 +220,25 @@ CreateTables(mozIStorageConnection* aDBC
       "file_ids TEXT, "
       "UNIQUE (object_store_id, key_value), "
       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
         "CASCADE"
     ");"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Table `ai_object_data`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE ai_object_data ("
-      "id INTEGER PRIMARY KEY AUTOINCREMENT, "
-      "object_store_id INTEGER NOT NULL, "
-      "data BLOB NOT NULL, "
-      "file_ids TEXT, "
-      "UNIQUE (object_store_id, id), "
-      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
-        "CASCADE"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
   // Table `index`
   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE TABLE object_store_index ("
-      "id INTEGER, "
+      "id INTEGER PRIMARY KEY, "
       "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), "
+      "multientry INTEGER NOT NULL, "
       "UNIQUE (object_store_id, name), "
       "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
         "CASCADE"
     ");"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Table `index_data`
@@ -331,63 +283,16 @@ CreateTables(mozIStorageConnection* aDBC
 
   // Need this to make cascading deletes from object_data and object_store fast.
   rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
     "CREATE INDEX unique_index_data_object_data_id_index "
     "ON unique_index_data (object_data_id);"
   ));
   NS_ENSURE_SUCCESS(rv, rv);
 
-  // Table `ai_index_data`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE ai_index_data ("
-      "index_id INTEGER NOT NULL, "
-      "value NOT NULL, "
-      "ai_object_data_id INTEGER NOT NULL, "
-      "PRIMARY KEY (index_id, value, ai_object_data_id), "
-      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
-        "CASCADE, "
-      "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
-        "CASCADE"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Need this to make cascading deletes from ai_object_data and object_store
-  // fast.
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE INDEX ai_index_data_ai_object_data_id_index "
-    "ON ai_index_data (ai_object_data_id);"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Table `ai_unique_index_data`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE ai_unique_index_data ("
-      "index_id INTEGER NOT NULL, "
-      "value NOT NULL, "
-      "ai_object_data_id INTEGER NOT NULL, "
-      "UNIQUE (index_id, value), "
-      "PRIMARY KEY (index_id, value, ai_object_data_id), "
-      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
-        "CASCADE, "
-      "FOREIGN KEY (ai_object_data_id) REFERENCES ai_object_data(id) ON DELETE "
-        "CASCADE"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Need this to make cascading deletes from ai_object_data and object_store
-  // fast.
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE INDEX ai_unique_index_data_ai_object_data_id_index "
-    "ON ai_unique_index_data (ai_object_data_id);"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
   rv = CreateFileTables(aDBConn);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aDBConn->SetSchemaVersion(kSQLiteSchemaVersion);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
@@ -1053,16 +958,131 @@ UpgradeSchemaFrom9_0To10_0(mozIStorageCo
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aConnection->SetSchemaVersion(MakeSchemaVersion(10, 0));
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
+nsresult
+UpgradeSchemaFrom10_0To11_0(mozIStorageConnection* aConnection)
+{
+  nsresult rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TEMPORARY TABLE temp_upgrade ("
+      "id, "
+      "object_store_id, "
+      "name, "
+      "key_path, "
+      "unique_index, "
+      "multientry"
+    ");"
+  ));
+  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, multientry "
+      "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 PRIMARY KEY, "
+      "object_store_id INTEGER NOT NULL, "
+      "name TEXT NOT NULL, "
+      "key_path TEXT NOT NULL, "
+      "unique_index INTEGER NOT NULL, "
+      "multientry INTEGER NOT NULL, "
+      "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, multientry "
+      "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->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
+      "SELECT object_store_id, id, data, file_ids "
+      "FROM ai_object_data;"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "INSERT INTO index_data (index_id, value, object_data_key, object_data_id) "
+      "SELECT ai_index_data.index_id, ai_index_data.value, ai_index_data.ai_object_data_id, object_data.id "
+      "FROM ai_index_data "
+      "INNER JOIN object_store_index ON "
+        "object_store_index.id = ai_index_data.index_id "
+      "INNER JOIN object_data ON "
+        "object_data.object_store_id = object_store_index.object_store_id AND "
+        "object_data.key_value = ai_index_data.ai_object_data_id;"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "INSERT INTO unique_index_data (index_id, value, object_data_key, object_data_id) "
+      "SELECT ai_unique_index_data.index_id, ai_unique_index_data.value, ai_unique_index_data.ai_object_data_id, object_data.id "
+      "FROM ai_unique_index_data "
+      "INNER JOIN object_store_index ON "
+        "object_store_index.id = ai_unique_index_data.index_id "
+      "INNER JOIN object_data ON "
+        "object_data.object_store_id = object_store_index.object_store_id AND "
+        "object_data.key_value = ai_unique_index_data.ai_object_data_id;"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "UPDATE object_store "
+      "SET auto_increment = (SELECT max(id) FROM ai_object_data) + 1 "
+      "WHERE auto_increment;"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "DROP TABLE ai_unique_index_data;"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "DROP TABLE ai_index_data;"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "DROP TABLE ai_object_data;"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aConnection->SetSchemaVersion(MakeSchemaVersion(11, 0));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
 class VersionChangeEventsRunnable;
 
 class SetVersionHelper : public AsyncConnectionHelper,
                          public IDBTransactionListener
 {
   friend class VersionChangeEventsRunnable;
 public:
   SetVersionHelper(IDBTransaction* aTransaction,
@@ -1358,17 +1378,17 @@ OpenDatabaseHelper::DoDatabaseWork()
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   if (mForDeletion) {
     mState = eDeletePending;
     return NS_OK;
   }
 
   for (PRUint32 i = 0; i < mObjectStores.Length(); i++) {
-    nsAutoPtr<ObjectStoreInfo>& objectStoreInfo = mObjectStores[i];
+    nsRefPtr<ObjectStoreInfo>& objectStoreInfo = mObjectStores[i];
     for (PRUint32 j = 0; j < objectStoreInfo->indexes.Length(); j++) {
       IndexInfo& indexInfo = objectStoreInfo->indexes[j];
       mLastIndexId = NS_MAX(indexInfo.id, mLastIndexId);
     }
     mLastObjectStoreId = NS_MAX(objectStoreInfo->id, mLastObjectStoreId);
   }
 
   // See if we need to do a VERSION_CHANGE transaction
@@ -1504,17 +1524,17 @@ OpenDatabaseHelper::CreateDatabaseConnec
       rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName);
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
       rv = stmt->Execute();
       NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
     }
     else  {
       // This logic needs to change next time we change the schema!
-      PR_STATIC_ASSERT(kSQLiteSchemaVersion == PRInt32((10 << 4) + 0));
+      PR_STATIC_ASSERT(kSQLiteSchemaVersion == PRInt32((11 << 4) + 0));
 
       while (schemaVersion != kSQLiteSchemaVersion) {
         if (schemaVersion == 4) {
           rv = UpgradeSchemaFrom4To5(connection);
         }
         else if (schemaVersion == 5) {
           rv = UpgradeSchemaFrom5To6(connection);
         }
@@ -1526,16 +1546,19 @@ OpenDatabaseHelper::CreateDatabaseConnec
         }
         else if (schemaVersion == 8) {
           rv = UpgradeSchemaFrom8To9_0(connection);
           vacuumNeeded = true;
         }
         else if (schemaVersion == MakeSchemaVersion(9, 0)) {
           rv = UpgradeSchemaFrom9_0To10_0(connection);
         }
+        else if (schemaVersion == MakeSchemaVersion(10, 0)) {
+          rv = UpgradeSchemaFrom10_0To11_0(connection);
+        }
         else {
           NS_WARNING("Unable to open IndexedDB database, no upgrade path is "
                      "available!");
           return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
         }
         NS_ENSURE_SUCCESS(rv, rv);
 
         rv = connection->GetSchemaVersion(&schemaVersion);
@@ -1676,16 +1699,18 @@ OpenDatabaseHelper::Run()
         mState = eFiringEvents;
         break;
       }
 
       case eDeleteCompleted: {
         // Destroy the database now (we should have the only ref).
         mDatabase = nsnull;
 
+        DatabaseInfo::Remove(mDatabaseId);
+
         IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
         NS_ASSERTION(mgr, "This should never fail!");
 
         mgr->InvalidateFileManager(mASCIIOrigin, mName);
 
         mState = eFiringEvents;
         break;
       }
@@ -1744,28 +1769,24 @@ OpenDatabaseHelper::EnsureSuccessResult(
       NS_ASSERTION(dbInfo->name == mName &&
                    dbInfo->version == mCurrentVersion &&
                    dbInfo->id == mDatabaseId &&
                    dbInfo->filePath == mDatabaseFilePath,
                    "Metadata mismatch!");
 
       PRUint32 objectStoreCount = mObjectStores.Length();
       for (PRUint32 index = 0; index < objectStoreCount; index++) {
-        nsAutoPtr<ObjectStoreInfo>& info = mObjectStores[index];
-        NS_ASSERTION(info->databaseId == mDatabaseId, "Huh?!");
+        nsRefPtr<ObjectStoreInfo>& info = mObjectStores[index];
 
-        ObjectStoreInfo* otherInfo;
-        NS_ASSERTION(dbInfo->GetObjectStore(info->name, &otherInfo),
-                     "ObjectStore not known!");
+        ObjectStoreInfo* otherInfo = dbInfo->GetObjectStore(info->name);
+        NS_ASSERTION(otherInfo, "ObjectStore not known!");
 
         NS_ASSERTION(info->name == otherInfo->name &&
                      info->id == otherInfo->id &&
-                     info->keyPath == otherInfo->keyPath &&
-                     info->autoIncrement == otherInfo->autoIncrement &&
-                     info->databaseId == otherInfo->databaseId,
+                     info->keyPath == otherInfo->keyPath,
                      "Metadata mismatch!");
         NS_ASSERTION(dbInfo->ContainsStoreName(info->name),
                      "Object store names out of date!");
         NS_ASSERTION(info->indexes.Length() == otherInfo->indexes.Length(),
                      "Bad index length!");
 
         PRUint32 indexCount = info->indexes.Length();
         for (PRUint32 indexIndex = 0; indexIndex < indexCount; indexIndex++) {
@@ -1774,40 +1795,39 @@ OpenDatabaseHelper::EnsureSuccessResult(
           NS_ASSERTION(indexInfo.id == otherIndexInfo.id,
                        "Bad index id!");
           NS_ASSERTION(indexInfo.name == otherIndexInfo.name,
                        "Bad index name!");
           NS_ASSERTION(indexInfo.keyPath == otherIndexInfo.keyPath,
                        "Bad index keyPath!");
           NS_ASSERTION(indexInfo.unique == otherIndexInfo.unique,
                        "Bad index unique value!");
-          NS_ASSERTION(indexInfo.autoIncrement == otherIndexInfo.autoIncrement,
-                       "Bad index autoIncrement value!");
         }
       }
     }
 #endif
 
   }
   else {
     nsRefPtr<DatabaseInfo> newInfo(new DatabaseInfo());
 
     newInfo->name = mName;
+    newInfo->origin = mASCIIOrigin;
     newInfo->id = mDatabaseId;
     newInfo->filePath = mDatabaseFilePath;
 
     if (!DatabaseInfo::Put(newInfo)) {
       NS_ERROR("Failed to add to hash!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
 
     newInfo.swap(dbInfo);
 
-    nsresult rv = IDBFactory::UpdateDatabaseMetadata(dbInfo, mCurrentVersion,
-                                                     mObjectStores);
+    nsresult rv = IDBFactory::SetDatabaseMetadata(dbInfo, mCurrentVersion,
+                                                  mObjectStores);
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     NS_ASSERTION(mObjectStores.IsEmpty(), "Should have swapped!");
   }
 
   dbInfo->nextObjectStoreId = mLastObjectStoreId + 1;
   dbInfo->nextIndexId = mLastIndexId + 1;
 
--- a/dom/indexedDB/OpenDatabaseHelper.h
+++ b/dom/indexedDB/OpenDatabaseHelper.h
@@ -57,17 +57,17 @@ public:
                      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),
       mLastObjectStoreId(0), mLastIndexId(0), mState(eCreated),
-      mResultCode(NS_OK)
+      mResultCode(NS_OK), mLoadDBMetadata(false)
   {
     NS_ASSERTION(!aForDeletion || !aRequestedVersion,
                  "Can't be for deletion and request a version!");
   }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
@@ -127,17 +127,17 @@ private:
   nsRefPtr<IDBOpenDBRequest> mOpenDBRequest;
   nsString mName;
   nsCString mASCIIOrigin;
   PRUint64 mRequestedVersion;
   bool mForDeletion;
   nsCOMPtr<nsIAtom> mDatabaseId;
 
   // Out-params.
-  nsTArray<nsAutoPtr<ObjectStoreInfo> > mObjectStores;
+  nsTArray<nsRefPtr<ObjectStoreInfo> > mObjectStores;
   PRUint64 mCurrentVersion;
   nsString mDatabaseFilePath;
   PRInt64 mLastObjectStoreId;
   PRInt64 mLastIndexId;
   nsRefPtr<IDBDatabase> mDatabase;
 
   // State variables
   enum OpenDatabaseState {
@@ -148,13 +148,16 @@ private:
     eSetVersionCompleted, // SetVersionHelper is done
     eDeletePending, // Waiting on a DeleteDatabaseHelper
     eDeleteCompleted, // DeleteDatabaseHelper is done
   };
   OpenDatabaseState mState;
   nsresult mResultCode;
 
   nsRefPtr<FileManager> mFileManager;
+
+  nsRefPtr<DatabaseInfo> mDBInfo;
+  bool mLoadDBMetadata;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_opendatabasehelper_h__
--- a/dom/indexedDB/nsIIDBObjectStore.idl
+++ b/dom/indexedDB/nsIIDBObjectStore.idl
@@ -45,27 +45,29 @@ interface nsIIDBRequest;
 interface nsIIDBTransaction;
 interface nsIDOMDOMStringList;
 
 /**
  * nsIIDBObjectStore interface.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-nsIIDBObjectStore
  * for more information.
  */
-[scriptable, builtinclass, uuid(adc6a1e2-9fd7-4d28-a7f9-9c653313124b)]
+[scriptable, builtinclass, uuid(e93c5ca4-89da-4eb4-b839-271ba4f65a27)]
 interface nsIIDBObjectStore : nsISupports
 {
   readonly attribute DOMString name;
 
   readonly attribute DOMString keyPath;
 
   readonly attribute nsIDOMDOMStringList indexNames;
 
   readonly attribute nsIIDBTransaction transaction;
 
+  readonly attribute boolean autoIncrement;
+
   // Success fires IDBTransactionEvent, result == value for key
   [implicit_jscontext]
   nsIIDBRequest
   get(in jsval key);
 
   // Success fires IDBTransactionEvent, result == array of values for given keys
   [implicit_jscontext, optional_argc]
   nsIIDBRequest
--- a/dom/indexedDB/test/Makefile.in
+++ b/dom/indexedDB/test/Makefile.in
@@ -52,16 +52,17 @@ TEST_FILES = \
   exceptions_in_success_events_iframe.html \
   file.js \
   helpers.js \
   leaving_page_iframe.html \
   test_add_put.html \
   test_add_twice_failure.html \
   test_advance.html \
   test_autoIncrement_indexes.html \
+  test_autoIncrement.html \
   test_bfcache.html \
   test_clear.html \
   test_cmp.html \
   test_complex_keyPaths.html \
   test_count.html \
   test_create_index.html \
   test_create_index_with_integer_keys.html \
   test_create_objectStore.html \
--- a/dom/indexedDB/test/error_events_abort_transactions_iframe.html
+++ b/dom/indexedDB/test/error_events_abort_transactions_iframe.html
@@ -83,25 +83,23 @@
       request = objectStore.add({}, 1);
       request.onsuccess = unexpectedSuccessHandler;
       request.onerror = function(event) {
         // Don't do anything! We want this error.
       }
       event = yield;
 
       is(event.type, "abort", "Got a transaction abort event");
-      //todo(db.version, 1, "Correct version");
-      is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
+      is(db.version, 1, "Correct version");
+      is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
 
       event = yield;
       is(event.type, "error", "Got request error event");
       is(event.target.errorCode, IDBDatabaseException.ABORT_ERR, "Right error code");
 
-      db.close();
-
       let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
       request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
       event.target.transaction.oncomplete = grabEventAndContinueHandler;
--- a/dom/indexedDB/test/helpers.js
+++ b/dom/indexedDB/test/helpers.js
@@ -42,16 +42,21 @@ function grabEventAndContinueHandler(eve
 
 function continueToNextStep()
 {
   SimpleTest.executeSoon(function() {
     testGenerator.next();
   });
 }
 
+function continueToNextStepSync()
+{
+  testGenerator.next();
+}
+
 function errorHandler(event)
 {
   ok(false, "indexedDB error, code " + event.target.errorCode);
   finishTest();
 }
 
 function browserErrorHandler(event)
 {
@@ -70,16 +75,17 @@ function ExpectError(code)
   this._code = code;
 }
 ExpectError.prototype = {
   handleEvent: function(event)
   {
     is(event.type, "error", "Got an error event");
     is(this._code, event.target.errorCode, "Expected error was thrown.");
     event.preventDefault();
+    event.stopPropagation();
     grabEventAndContinueHandler(event);
   }
 };
 
 function addPermission(type, allow, url)
 {
   netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
--- a/dom/indexedDB/test/test_add_put.html
+++ b/dom/indexedDB/test/test_add_put.html
@@ -77,35 +77,40 @@
                   args.push(undefined);
                 }
                 else if (explicit === "invalid") {
                   args.push(/x/);
                 }
 
                 let expected = expectedResult(method, keypath, explicit, autoincrement, existing);
 
+                let valueJSON = JSON.stringify(value);
+
                 ok(true, "making call" + test);
 
                 // Make function call for throwing functions
                 if (expected === "throw") {
                   try {
                     store[method].apply(store, args);
                     ok(false, "should have thrown" + test);
                   }
                   catch (ex) {
                     ok(true, "did throw" + test);
                     ok(ex instanceof IDBDatabaseException, "Got a IDBDatabaseException" + test);
                     is(ex.code, IDBDatabaseException.DATA_ERR, "expect a DATA_ERR" + test);
+                    is(JSON.stringify(value), valueJSON, "call didn't modify value" + test);
                   }
                   continue;
                 }
 
                 // Make non-throwing function call
                 let req = store[method].apply(store, args);
-                req.onsuccess = req.onerror = grabEventAndContinueHandler
+                is(JSON.stringify(value), valueJSON, "call didn't modify value" + test);
+
+                req.onsuccess = req.onerror = grabEventAndContinueHandler;
                 let e = yield;
 
                 // Figure out what key we used
                 let key = 5;
                 if (autoincrement && speccedNoKey) {
                   key = 1;
                 }
 
@@ -118,26 +123,17 @@
                 if (expected === "error") {
                   is(e.type, "error", "write should fail" + test);
                   e.preventDefault();
                   e.stopPropagation();
                   continue;
                 }
 
                 is(e.type, "success", "write should succeed" + test);
-                if (autoincrement && speccedNoKey) {
-                  todo_is(e.target.result, key, "(fix ai) write should return correct key" + test);
-                  key = e.target.result;
-                  if (keypath) {
-                    value.id = key;
-                  }
-                }
-                else {
-                  is(e.target.result, key, "write should return correct key" + test);
-                }
+                is(e.target.result, key, "write should return correct key" + test);
 
                 store.get(key).onsuccess = grabEventAndContinueHandler;
                 e = yield;
                 is(e.type, "success", "read back should succeed" + test);
                 is(JSON.stringify(e.target.result),
                    JSON.stringify(value),
                    "read back should return correct value" + test);
               }
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/test/test_autoIncrement.html
@@ -0,0 +1,384 @@
+<!--
+  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 genCheck(key, value, test, options) {
+      return function(event) {
+        is(event.target.result, key, "correct returned key in " + test);
+        if (options && options.store) {
+          is(event.target.source, options.store, "correct store in " + test);
+        }
+        if (options && options.trans) {
+          is(event.target.transaction, options.trans, "correct transaction in " + test);
+        }
+        
+        event.target.source.get(key).onsuccess = function(event) {
+          is(JSON.stringify(event.target.result), JSON.stringify(value),
+             "correct stored value in " + test);
+          continueToNextStepSync();
+        }
+      }
+    }
+
+    function testSteps()
+    {
+      const dbname = window.location.pathname;
+      const RW = IDBTransaction.READ_WRITE
+      let c1 = 1;
+      let c2 = 1;
+
+      let openRequest = mozIndexedDB.open(dbname, 1);
+      openRequest.onerror = errorHandler;
+      openRequest.onupgradeneeded = grabEventAndContinueHandler;
+      openRequest.onsuccess = unexpectedSuccessHandler;
+      let event = yield;
+      let db = event.target.result;
+      let trans = event.target.transaction;
+
+      // Create test stores
+      let store1 = db.createObjectStore("store1", { autoIncrement: true });
+      let store2 = db.createObjectStore("store2", { autoIncrement: true, keyPath: "id" });
+      let store3 = db.createObjectStore("store3", { autoIncrement: false });
+      is(store1.autoIncrement, true, "store1 .autoIncrement");
+      is(store2.autoIncrement, true, "store2 .autoIncrement");
+      is(store3.autoIncrement, false, "store3 .autoIncrement");
+
+      store1.createIndex("unique1", "unique", { unique: true });
+      store2.createIndex("unique1", "unique", { unique: true });
+
+      // Test simple inserts
+      let test = " for test simple insert"
+      store1.add({ foo: "value1" }).onsuccess =
+        genCheck(c1++, { foo: "value1" }, "first" + test);
+      store1.add({ foo: "value2" }).onsuccess =
+        genCheck(c1++, { foo: "value2" }, "second" + test);
+
+      yield;
+      yield;
+
+      store2.put({ bar: "value1" }).onsuccess =
+        genCheck(c2, { bar: "value1", id: c2 }, "first in store2" + test,
+                 { store: store2 });
+      c2++;
+      store1.put({ foo: "value3" }).onsuccess =
+        genCheck(c1++, { foo: "value3" }, "third" + test,
+                 { store: store1 });
+
+      yield;
+      yield;
+      
+      store2.get(IDBKeyRange.lowerBound(c2)).onsuccess = grabEventAndContinueHandler;
+      event = yield;
+      is(event.target.result, undefined, "no such value" + test);
+
+      // Close version_change transaction
+      openRequest.onsuccess = grabEventAndContinueHandler;
+      event = yield;
+      is(event.target, openRequest, "succeeded to open" + test);
+      is(event.type, "success", "succeeded to open" + test);
+
+      // Test inserting explicit keys
+      test = " for test explicit keys";
+      trans = db.transaction("store1", RW);
+      trans.objectStore("store1").add({ explicit: 1 }, 100).onsuccess =
+        genCheck(100, { explicit: 1 }, "first" + test);
+      c1 = 101;
+      trans = db.transaction("store1", RW);
+      trans.objectStore("store1").add({ explicit: 2 }).onsuccess =
+        genCheck(c1++, { explicit: 2 }, "second" + test);
+      yield; yield;
+
+      trans = db.transaction("store1", RW);
+      trans.objectStore("store1").add({ explicit: 3 }, 200).onsuccess =
+        genCheck(200, { explicit: 3 }, "third" + test);
+      c1 = 201;
+      trans.objectStore("store1").add({ explicit: 4 }).onsuccess =
+        genCheck(c1++, { explicit: 4 }, "fourth" + test);
+      yield; yield;
+
+      trans = db.transaction("store1", RW);
+      trans.objectStore("store1").add({ explicit: 5 }, 150).onsuccess =
+        genCheck(150, { explicit: 5 }, "fifth" + test);
+      yield;
+      trans.objectStore("store1").add({ explicit: 6 }).onsuccess =
+        genCheck(c1++, { explicit: 6 }, "sixth" + test);
+      yield;
+
+      trans = db.transaction("store1", RW);
+      trans.objectStore("store1").add({ explicit: 7 }, "key").onsuccess =
+        genCheck("key", { explicit: 7 }, "seventh" + test);
+      yield;
+      trans.objectStore("store1").add({ explicit: 8 }).onsuccess =
+        genCheck(c1++, { explicit: 8 }, "eighth" + test);
+      yield;
+
+      trans = db.transaction("store1", RW);
+      trans.objectStore("store1").add({ explicit: 9 }, -100000).onsuccess =
+        genCheck(-100000, { explicit: 9 }, "ninth" + test);
+      yield;
+      trans.objectStore("store1").add({ explicit: 10 }).onsuccess =
+        genCheck(c1++, { explicit: 10 }, "tenth" + test);
+      yield;
+
+
+      trans = db.transaction("store2", RW);
+      trans.objectStore("store2").add({ explicit2: 1, id: 300 }).onsuccess =
+        genCheck(300, { explicit2: 1, id: 300 }, "first store2" + test);
+      c2 = 301;
+      trans = db.transaction("store2", RW);
+      trans.objectStore("store2").add({ explicit2: 2 }).onsuccess =
+        genCheck(c2, { explicit2: 2, id: c2 }, "second store2" + test);
+      c2++;
+      yield; yield;
+
+      trans = db.transaction("store2", RW);
+      trans.objectStore("store2").add({ explicit2: 3, id: 400 }).onsuccess =
+        genCheck(400, { explicit2: 3, id: 400 }, "third store2" + test);
+      c2 = 401;
+      trans.objectStore("store2").add({ explicit2: 4 }).onsuccess =
+        genCheck(c2, { explicit2: 4, id: c2 }, "fourth store2" + test);
+      c2++;
+      yield; yield;
+
+      trans = db.transaction("store2", RW);
+      trans.objectStore("store2").add({ explicit: 5, id: 150 }).onsuccess =
+        genCheck(150, { explicit: 5, id: 150 }, "fifth store2" + test);
+      yield;
+      trans.objectStore("store2").add({ explicit: 6 }).onsuccess =
+        genCheck(c2, { explicit: 6, id: c2 }, "sixth store2" + test);
+      c2++;
+      yield;
+
+      trans = db.transaction("store2", RW);
+      trans.objectStore("store2").add({ explicit: 7, id: "key" }).onsuccess =
+        genCheck("key", { explicit: 7, id: "key" }, "seventh store2" + test);
+      yield;
+      trans.objectStore("store2").add({ explicit: 8 }).onsuccess =
+        genCheck(c2, { explicit: 8, id: c2 }, "eighth store2" + test);
+      c2++;
+      yield;
+
+      trans = db.transaction("store2", RW);
+      trans.objectStore("store2").add({ explicit: 9, id: -100000 }).onsuccess =
+        genCheck(-100000, { explicit: 9, id: -100000 }, "ninth store2" + test);
+      yield;
+      trans.objectStore("store2").add({ explicit: 10 }).onsuccess =
+        genCheck(c2, { explicit: 10, id: c2 }, "tenth store2" + test);
+      c2++;
+      yield;
+
+
+      // Test separate transactions doesn't generate overlapping numbers
+      test = " for test non-overlapping counts";
+      trans = db.transaction("store1", RW);
+      trans2 = db.transaction("store1", RW);
+      trans2.objectStore("store1").put({ over: 2 }).onsuccess =
+        genCheck(c1 + 1, { over: 2 }, "first" + test,
+                 { trans: trans2 });
+      trans.objectStore("store1").put({ over: 1 }).onsuccess =
+        genCheck(c1, { over: 1 }, "second" + test,
+                 { trans: trans });
+      c1 += 2;
+      yield; yield;
+
+      trans = db.transaction("store2", RW);
+      trans2 = db.transaction("store2", RW);
+      trans2.objectStore("store2").put({ over: 2 }).onsuccess =
+        genCheck(c2 + 1, { over: 2, id: c2 + 1 }, "third" + test,
+                 { trans: trans2 });
+      trans.objectStore("store2").put({ over: 1 }).onsuccess =
+        genCheck(c2, { over: 1, id: c2 }, "fourth" + test,
+                 { trans: trans });
+      c2 += 2;
+      yield; yield;
+
+      // Test that error inserts doesn't increase generator
+      test = " for test error inserts";
+      trans = db.transaction(["store1", "store2"], RW);
+      trans.objectStore("store1").add({ unique: 1 }, -1);
+      trans.objectStore("store2").add({ unique: 1, id: "unique" });
+
+      trans.objectStore("store1").add({ error: 1, unique: 1 }).onerror =
+        new ExpectError(IDBDatabaseException.CONSTRAINT_ERR);
+      trans.objectStore("store1").add({ error: 2 }).onsuccess =
+        genCheck(c1++, { error: 2 }, "first" + test);
+      yield; yield;
+
+      trans.objectStore("store2").add({ error: 3, unique: 1 }).onerror =
+        new ExpectError(IDBDatabaseException.CONSTRAINT_ERR);
+      trans.objectStore("store2").add({ error: 4 }).onsuccess =
+        genCheck(c2, { error: 4, id: c2 }, "second" + test);
+      c2++;
+      yield; yield;
+
+      trans.objectStore("store1").add({ error: 5, unique: 1 }, 100000).onerror =
+        new ExpectError(IDBDatabaseException.CONSTRAINT_ERR);
+      trans.objectStore("store1").add({ error: 6 }).onsuccess =
+        genCheck(c1++, { error: 6 }, "third" + test);
+      yield; yield;
+
+      trans.objectStore("store2").add({ error: 7, unique: 1, id: 100000 }).onerror =
+        new ExpectError(IDBDatabaseException.CONSTRAINT_ERR);
+      trans.objectStore("store2").add({ error: 8 }).onsuccess =
+        genCheck(c2, { error: 8, id: c2 }, "fourth" + test);
+      c2++;
+      yield; yield;
+
+      // Test that aborts doesn't increase generator
+      test = " for test aborted transaction";
+      trans = db.transaction(["store1", "store2"], RW);
+      trans.objectStore("store1").add({ abort: 1 }).onsuccess =
+        genCheck(c1, { abort: 1 }, "first" + test);
+      trans.objectStore("store2").put({ abort: 2 }).onsuccess =
+        genCheck(c2, { abort: 2, id: c2 }, "second" + test);
+      yield; yield;
+
+      trans.objectStore("store1").add({ abort: 3 }, 500).onsuccess =
+        genCheck(500, { abort: 3 }, "third" + test);
+      trans.objectStore("store2").put({ abort: 4, id: 600 }).onsuccess =
+        genCheck(600, { abort: 4, id: 600 }, "fourth" + test);
+      yield; yield;
+
+      trans.objectStore("store1").add({ abort: 5 }).onsuccess =
+        genCheck(501, { abort: 5 }, "fifth" + test);
+      trans.objectStore("store2").put({ abort: 6 }).onsuccess =
+        genCheck(601, { abort: 6, id: 601 }, "sixth" + test);
+      yield; yield;
+
+      trans.abort();
+      trans.onabort = grabEventAndContinueHandler;
+      event = yield
+      is(event.type, "abort", "transaction aborted");
+      is(event.target, trans, "correct transaction aborted");
+
+      trans = db.transaction(["store1", "store2"], RW);
+      trans.objectStore("store1").add({ abort: 1 }).onsuccess =
+        genCheck(c1++, { abort: 1 }, "re-first" + test);
+      trans.objectStore("store2").put({ abort: 2 }).onsuccess =
+        genCheck(c2, { abort: 2, id: c2 }, "re-second" + test);
+      c2++;
+      yield; yield;
+
+      // Test that delete doesn't decrease generator
+      test = " for test delete items"
+      trans = db.transaction(["store1", "store2"], RW);
+      trans.objectStore("store1").add({ delete: 1 }).onsuccess =
+        genCheck(c1++, { delete: 1 }, "first" + test);
+      trans.objectStore("store2").put({ delete: 2 }).onsuccess =
+        genCheck(c2, { delete: 2, id: c2 }, "second" + test);
+      c2++;
+      yield; yield;
+
+      trans.objectStore("store1").delete(c1 - 1).onsuccess =
+        grabEventAndContinueHandler;
+      trans.objectStore("store2").delete(c2 - 1).onsuccess =
+        grabEventAndContinueHandler;
+      yield; yield;
+
+      trans.objectStore("store1").add({ delete: 3 }).onsuccess =
+        genCheck(c1++, { delete: 3 }, "first" + test);
+      trans.objectStore("store2").put({ delete: 4 }).onsuccess =
+        genCheck(c2, { delete: 4, id: c2 }, "second" + test);
+      c2++;
+      yield; yield;
+
+      trans.objectStore("store1").delete(c1 - 1).onsuccess =
+        grabEventAndContinueHandler;
+      trans.objectStore("store2").delete(c2 - 1).onsuccess =
+        grabEventAndContinueHandler;
+      yield; yield;
+
+      trans = db.transaction(["store1", "store2"], RW);
+      trans.objectStore("store1").add({ delete: 5 }).onsuccess =
+        genCheck(c1++, { delete: 5 }, "first" + test);
+      trans.objectStore("store2").put({ delete: 6 }).onsuccess =
+        genCheck(c2, { delete: 6, id: c2 }, "second" + test);
+      c2++;
+      yield; yield;
+
+      // Test that clears doesn't decrease generator
+      test = " for test clear stores";
+      trans = db.transaction(["store1", "store2"], RW);
+      trans.objectStore("store1").add({ clear: 1 }).onsuccess =
+        genCheck(c1++, { clear: 1 }, "first" + test);
+      trans.objectStore("store2").put({ clear: 2 }).onsuccess =
+        genCheck(c2, { clear: 2, id: c2 }, "second" + test);
+      c2++;
+      yield; yield;
+
+      trans.objectStore("store1").clear().onsuccess =
+        grabEventAndContinueHandler;
+      trans.objectStore("store2").clear().onsuccess =
+        grabEventAndContinueHandler;
+      yield; yield;
+
+      trans.objectStore("store1").add({ clear: 3 }).onsuccess =
+        genCheck(c1++, { clear: 3 }, "third" + test);
+      trans.objectStore("store2").put({ clear: 4 }).onsuccess =
+        genCheck(c2, { clear: 4, id: c2 }, "forth" + test);
+      c2++;
+      yield; yield;
+
+      trans.objectStore("store1").clear().onsuccess =
+        grabEventAndContinueHandler;
+      trans.objectStore("store2").clear().onsuccess =
+        grabEventAndContinueHandler;
+      yield; yield;
+
+      trans = db.transaction(["store1", "store2"], RW);
+      trans.objectStore("store1").add({ clear: 5 }).onsuccess =
+        genCheck(c1++, { clear: 5 }, "fifth" + test);
+      trans.objectStore("store2").put({ clear: 6 }).onsuccess =
+        genCheck(c2, { clear: 6, id: c2 }, "sixth" + test);
+      c2++;
+      yield; yield;
+
+ 
+      // Test that close/reopen doesn't decrease generator
+      test = " for test clear stores";
+      trans = db.transaction(["store1", "store2"], RW);
+      trans.objectStore("store1").clear().onsuccess =
+        grabEventAndContinueHandler;
+      trans.objectStore("store2").clear().onsuccess =
+        grabEventAndContinueHandler;
+      yield; yield;
+      db.close();
+
+      SpecialPowers.gc();
+
+      openRequest = mozIndexedDB.open(dbname, 2);
+      openRequest.onerror = errorHandler;
+      openRequest.onupgradeneeded = grabEventAndContinueHandler;
+      openRequest.onsuccess = unexpectedSuccessHandler;
+      event = yield;
+      db = event.target.result;
+      trans = event.target.transaction;
+
+      trans.objectStore("store1").add({ reopen: 1 }).onsuccess =
+        genCheck(c1++, { reopen: 1 }, "first" + test);
+      trans.objectStore("store2").put({ reopen: 2 }).onsuccess =
+        genCheck(c2, { reopen: 2, id: c2 }, "second" + test);
+      c2++;
+      yield; yield;
+
+      openRequest.onsuccess = 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_autoIncrement_indexes.html
+++ b/dom/indexedDB/test/test_autoIncrement_indexes.html
@@ -26,41 +26,40 @@
       objectStore.createIndex("second","second");
       objectStore.createIndex("third","third");
 
       let data = { first: "foo", second: "foo", third: "foo" };
 
       objectStore.add(data).onsuccess = grabEventAndContinueHandler;
       event = yield;
 
-      let key = event.target.result;
-      ok(key, "Added entry");
+      is(event.target.result, 1, "Added entry");
       request.onsuccess = grabEventAndContinueHandler;
 
       event = yield;
 
       let objectStore = db.transaction("foo").objectStore("foo");
       let first = objectStore.index("first");
       let second = objectStore.index("second");
       let third = objectStore.index("third");
 
       first.get("foo").onsuccess = grabEventAndContinueHandler;
       event = yield;
 
-      is (event.target.result.id, key, "Entry in first");
+      is (event.target.result.id, 1, "Entry in first");
 
       second.get("foo").onsuccess = grabEventAndContinueHandler;
       event = yield;
 
-      is (event.target.result.id, key, "Entry in second");
+      is (event.target.result.id, 1, "Entry in second");
 
       third.get("foo").onsuccess = grabEventAndContinueHandler;
       event = yield;
 
-      is (event.target.result.id, key, "Entry in third");
+      is (event.target.result.id, 1, "Entry in third");
 
       finishTest();
       yield;
     }
   </script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
--- a/dom/indexedDB/test/test_setVersion_abort.html
+++ b/dom/indexedDB/test/test_setVersion_abort.html
@@ -16,17 +16,17 @@ function testSteps()
   const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
   const VERSION_CHANGE = Components.interfaces.nsIIDBTransaction.VERSION_CHANGE;
 
   const name = window.location.pathname;
   const description = "My Test Database";
 
   let request = mozIndexedDB.open(name, 1, description);
   request.onerror = grabEventAndContinueHandler;
-  request.onsuccess = errorHandler;
+  request.onsuccess = unexpectedSuccessHandler;
   request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   let objectStore = db.createObjectStore("foo");
   let index = objectStore.createIndex("bar", "baz");
 
@@ -38,23 +38,38 @@ function testSteps()
   transaction.oncomplete = unexpectedSuccessHandler;
   transaction.onabort = grabEventAndContinueHandler;
   transaction.abort();
 
   event = yield;
   is(event.type, "abort", "Got transaction abort event");
   is(event.target, transaction, "Right target");
 
-  todo(db.version, 1, "Correct version");
-  is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
+  is(db.version, 1, "Correct version");
+  is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
 
   event = yield;
   is(event.type, "error", "Got request error event");
   is(event.target, request, "Right target");
 
+  request = mozIndexedDB.open(name, 1, description);
+  request.onerror = grabEventAndContinueHandler;
+  request.onsuccess = unexpectedSuccessHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
+  let event = yield;
+
+  let db2 = event.target.result;
+  
+  isnot(db, db2, "Should give a different db instance");
+  is(db2.version, 1, "Correct version");
+  is(db2.objectStoreNames.length, 0, "Correct objectStoreNames length");
+
+  request.onsuccess = grabEventAndContinueHandler;
+  yield;
+
   finishTest();
   yield;
 }
   </script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>