Make indexedDB.open async
authorBen Turner <bent.mozilla@gmail.com>
Sun, 09 May 2010 21:26:31 -0700
changeset 43987 8de2e436badd0448685a00775d45bd1b69a70c12
parent 43986 1789a859699ea4e92b47074c74466d3b7afbbf2f
child 43988 8d33bc40b3dd6c2e684e8e1d585c98afc214486d
push id1
push userroot
push dateMon, 20 Oct 2014 17:29:22 +0000
milestone1.9.3a5pre
Make indexedDB.open async
dom/base/nsGlobalWindow.cpp
dom/base/nsGlobalWindow.h
dom/indexedDB/AsyncConnectionHelper.cpp
dom/indexedDB/IDBDatabaseRequest.cpp
dom/indexedDB/IDBDatabaseRequest.h
dom/indexedDB/IndexedDatabaseRequest.cpp
dom/indexedDB/IndexedDatabaseRequest.h
dom/indexedDB/nsIIndexedDatabaseRequest.idl
dom/indexedDB/test/test_create_objectStore.html
dom/indexedDB/test/test_event_source.html
dom/indexedDB/test/test_objectStore_remove_values.html
dom/indexedDB/test/test_open_empty_db.html
dom/indexedDB/test/test_open_objectStore.html
dom/indexedDB/test/test_put_get_values.html
dom/indexedDB/test/test_put_get_values_autoIncrement.html
dom/indexedDB/test/test_remove_objectStore.html
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -910,16 +910,17 @@ nsGlobalWindow::CleanUp(PRBool aIgnoreMo
   mToolbar = nsnull;
   mLocationbar = nsnull;
   mPersonalbar = nsnull;
   mStatusbar = nsnull;
   mScrollbars = nsnull;
   mLocation = nsnull;
   mFrames = nsnull;
   mApplicationCache = nsnull;
+  mIndexedDB = nsnull;
 
   ClearControllers();
 
   mOpener = nsnull;             // Forces Release
   if (mContext) {
 #ifdef DEBUG
     nsCycleCollector_DEBUG_shouldBeFreed(mContext);
 #endif
@@ -1070,16 +1071,18 @@ nsGlobalWindow::FreeInnerObjects(PRBool 
   mDocument = nsnull;
   mDoc = nsnull;
 
   if (mApplicationCache) {
     static_cast<nsDOMOfflineResourceList*>(mApplicationCache.get())->Disconnect();
     mApplicationCache = nsnull;
   }
 
+  mIndexedDB = nsnull;
+
   if (aClearScope) {
     // NB: This might not clear our scope, but fire an event to do so
     // instead.
     ReallyClearScope(nsnull);
   }
 
   if (mDummyJavaPluginOwner) {
     // Tear down the dummy java plugin.
@@ -7484,21 +7487,23 @@ nsGlobalWindow::GetLocalStorage(nsIDOMSt
 
   NS_ADDREF(*aLocalStorage = mLocalStorage);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsGlobalWindow::GetIndexedDB(nsIIndexedDatabaseRequest** _retval)
 {
-  nsCOMPtr<nsIIndexedDatabaseRequest> indexedDB =
-    mozilla::dom::indexedDB::IndexedDatabaseRequest::Create();
-  NS_ENSURE_TRUE(indexedDB, NS_ERROR_FAILURE);
-
-  indexedDB.forget(_retval);
+  if (!mIndexedDB) {
+    mIndexedDB = mozilla::dom::indexedDB::IndexedDatabaseRequest::Create();
+    NS_ENSURE_TRUE(mIndexedDB, NS_ERROR_FAILURE);
+  }
+
+  nsCOMPtr<nsIIndexedDatabaseRequest> request(mIndexedDB);
+  request.forget(_retval);
   return NS_OK;
 }
 
 //*****************************************************************************
 // nsGlobalWindow::nsIInterfaceRequestor
 //*****************************************************************************
 
 NS_IMETHODIMP
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -96,16 +96,17 @@
 #include "nsIDOMStorageObsolete.h"
 #include "nsIDOMStorageList.h"
 #include "nsIDOMStorageWindow.h"
 #include "nsIDOMStorageEvent.h"
 #include "nsIDOMOfflineResourceList.h"
 #include "nsPIDOMEventTarget.h"
 #include "nsIArray.h"
 #include "nsIContent.h"
+#include "nsIIndexedDatabaseRequest.h"
 
 #define DEFAULT_HOME_PAGE "www.mozilla.org"
 #define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
 
 class nsIDOMBarProp;
 class nsIDocument;
 class nsPresContext;
 class nsIDOMEvent;
@@ -814,16 +815,18 @@ protected:
   PRBool mCleanedUp, mCallCleanUpAfterModalDialogCloses;
 
   nsCOMPtr<nsIDOMOfflineResourceList> mApplicationCache;
 
   nsDataHashtable<nsVoidPtrHashKey, void*> mCachedXBLPrototypeHandlers;
 
   nsCOMPtr<nsIDocument> mSuspendedDoc;
 
+  nsCOMPtr<nsIIndexedDatabaseRequest> mIndexedDB;
+
   friend class nsDOMScriptableHelper;
   friend class nsDOMWindowUtils;
   friend class PostMessageEvent;
   static nsIDOMStorageList* sGlobalStorageList;
 };
 
 /*
  * nsGlobalChromeWindow inherits from nsGlobalWindow. It is the global
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -53,17 +53,17 @@ USING_INDEXEDDB_NAMESPACE
 AsyncConnectionHelper::AsyncConnectionHelper(IDBDatabaseRequest* aDatabase,
                                              IDBRequest* aRequest)
 : mDatabase(aDatabase),
   mRequest(aRequest),
   mErrorCode(0),
   mError(PR_FALSE)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-  NS_ASSERTION(mDatabase, "Null owner!");
+  // mDatabase may be null if we're opening the database.
   NS_ASSERTION(mRequest, "Null request!");
 }
 
 AsyncConnectionHelper::~AsyncConnectionHelper()
 {
   if (!NS_IsMainThread()) {
     NS_ASSERTION(mErrorCode == NOREPLY,
                  "This should only happen if NOREPLY was returned!");
@@ -71,27 +71,26 @@ AsyncConnectionHelper::~AsyncConnectionH
     IDBDatabaseRequest* database;
     mDatabase.forget(&database);
 
     IDBRequest* request;
     mRequest.forget(&request);
 
     nsCOMPtr<nsIThread> mainThread;
     NS_GetMainThread(getter_AddRefs(mainThread));
+    NS_WARN_IF_FALSE(mainThread, "Couldn't get the main thread!");
 
     if (mainThread) {
-      NS_ProxyRelease(mainThread, static_cast<nsIIDBDatabase*>(database));
-      NS_ProxyRelease(mainThread, static_cast<nsIDOMEventTarget*>(request));
+      if (database) {
+        NS_ProxyRelease(mainThread, static_cast<nsIIDBDatabase*>(database));
+      }
+      if (request) {
+        NS_ProxyRelease(mainThread, static_cast<nsIDOMEventTarget*>(request));
+      }
     }
-    else {
-      NS_WARNING("Couldn't get the main thread?! Leaking instead of crashing.");
-    }
-
-    NS_ASSERTION(!mDatabase, "Should have been released before now!");
-    NS_ASSERTION(!mRequest, "Should have been released before now!");
   }
 
   NS_ASSERTION(!mDatabaseThread, "Should have been released before now!");
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(AsyncConnectionHelper, nsIRunnable)
 
 NS_IMETHODIMP
--- a/dom/indexedDB/IDBDatabaseRequest.cpp
+++ b/dom/indexedDB/IDBDatabaseRequest.cpp
@@ -37,38 +37,31 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "IDBDatabaseRequest.h"
 
 #include "nsIIDBDatabaseException.h"
 
 #include "mozilla/Storage.h"
-#include "nsAppDirectoryServiceDefs.h"
-#include "nsContentUtils.h"
-#include "nsDirectoryServiceUtils.h"
 #include "nsDOMClassInfo.h"
-#include "nsHashKeys.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 
 #include "AsyncConnectionHelper.h"
 #include "IDBEvents.h"
 #include "IDBObjectStoreRequest.h"
-#include "IDBRequest.h"
+#include "IndexedDatabaseRequest.h"
 #include "LazyIdleThread.h"
 
-#define DB_SCHEMA_VERSION 1
-
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 const PRUint32 kDefaultDatabaseTimeoutMS = 5000;
-const PRUint32 kDefaultThreadTimeoutMS = 30000;
 
 inline
 nsISupports*
 isupports_cast(IDBDatabaseRequest* aClassPtr)
 {
   return static_cast<nsISupports*>(
     static_cast<IDBRequest::Generator*>(aClassPtr));
 }
@@ -162,215 +155,46 @@ public:
   PRUint16 DoDatabaseWork();
   void GetSuccessResult(nsIWritableVariant* aResult);
 
 private:
   // In-params.
   nsString mName;
 };
 
-/**
- * Creates the needed tables and their indexes.
- *
- * @param aDBConn
- *        The database connection to create the tables on.
- */
-nsresult
-CreateTables(mozIStorageConnection* aDBConn)
-{
-  NS_PRECONDITION(!NS_IsMainThread(),
-                  "Creating tables on the main thread!");
-  NS_PRECONDITION(aDBConn, "Passing a null database connection!");
-
-  // Table `database`
-  nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE database ("
-      "name TEXT NOT NULL, "
-      "description TEXT NOT NULL, "
-      "version TEXT DEFAULT NULL, "
-      "UNIQUE (name)"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Table `object_store`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE object_store ("
-      "id INTEGER, "
-      "name TEXT NOT NULL, "
-      "key_path TEXT DEFAULT NULL, "
-      "auto_increment INTEGER NOT NULL DEFAULT 0, "
-      "readers INTEGER NOT NULL DEFAULT 0, "
-      "is_writing INTEGER NOT NULL DEFAULT 0, "
-      "PRIMARY KEY (id), "
-      "UNIQUE (name)"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Table `object_data`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE object_data ("
-      "id INTEGER, "
-      "object_store_id INTEGER NOT NULL, "
-      "data TEXT NOT NULL, "
-      "key_value TEXT DEFAULT NULL, "
-      "PRIMARY KEY (id), "
-      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
-        "CASCADE"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE INDEX key_index "
-    "ON object_data (id, object_store_id);"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Table `ai_object_data`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE ai_object_data ("
-      "id INTEGER, "
-      "object_store_id INTEGER NOT NULL, "
-      "data TEXT NOT NULL, "
-      "PRIMARY KEY (id), "
-      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
-        "CASCADE"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE INDEX ai_key_index "
-    "ON ai_object_data (id, object_store_id);"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aDBConn->SetSchemaVersion(DB_SCHEMA_VERSION);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
 } // anonymous namespace
 
 // static
 already_AddRefed<IDBDatabaseRequest>
 IDBDatabaseRequest::Create(const nsAString& aName,
                            const nsAString& aDescription,
-                           PRBool aReadOnly)
+                           PRBool aReadOnly,
+                           nsTArray<nsString>& aObjectStoreNames,
+                           nsTArray<nsString>& aIndexNames,
+                           const nsAString& aVersion,
+                           LazyIdleThread* aThread,
+                           const nsAString& aDatabaseFilePath,
+                           nsCOMPtr<mozIStorageConnection>& aConnection)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  nsCOMPtr<nsIPrincipal> principal;
-  nsresult rv = nsContentUtils::GetSecurityManager()->
-    GetSubjectPrincipal(getter_AddRefs(principal));
-  NS_ENSURE_SUCCESS(rv, nsnull);
-
-  nsCString origin;
-  if (nsContentUtils::IsSystemPrincipal(principal)) {
-    origin.AssignLiteral("chrome");
-  }
-  else {
-    rv = nsContentUtils::GetASCIIOrigin(principal, origin);
-    NS_ENSURE_SUCCESS(rv, nsnull);
-  }
-
   nsRefPtr<IDBDatabaseRequest> db(new IDBDatabaseRequest());
 
-  db->mConnectionThread = new LazyIdleThread(kDefaultThreadTimeoutMS, db);
-
-  db->mASCIIOrigin.Assign(origin);
   db->mName.Assign(aName);
   db->mDescription.Assign(aDescription);
   db->mReadOnly = aReadOnly;
-
-#if 1
-  // XXX Do this before we load the page! This is all duplicated code that needs
-  // to be totally removed before this code sees the light of day!
-  NS_WARNING("Using a sync algorithm to open indexedDB data! Fix this now!");
-
-  nsCOMPtr<nsIFile> dbFile;
-  rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
-                              getter_AddRefs(dbFile));
-  NS_ENSURE_SUCCESS(rv, nsnull);
-
-  rv = dbFile->Append(NS_LITERAL_STRING("indexedDB"));
-  NS_ENSURE_SUCCESS(rv, nsnull);
-
-  PRBool exists;
-  rv = dbFile->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, nsnull);
-
-  if (exists) {
-    PRBool isDirectory;
-    rv = dbFile->IsDirectory(&isDirectory);
-    NS_ENSURE_SUCCESS(rv, nsnull);
-
-    if (isDirectory) {
-      nsAutoString filename;
-      filename.AppendInt(HashString(origin));
-
-      rv = dbFile->Append(filename);
-      NS_ENSURE_SUCCESS(rv, nsnull);
-
-      rv = dbFile->Exists(&exists);
-      NS_ENSURE_SUCCESS(rv, nsnull);
-
-      if (exists) {
-        rv = dbFile->IsDirectory(&isDirectory);
-        NS_ENSURE_SUCCESS(rv, nsnull);
-
-        if (isDirectory) {
-          filename.Truncate();
-          filename.AppendInt(HashString(aName));
-          filename.AppendLiteral(".sqlite");
+  db->mObjectStoreNames.SwapElements(aObjectStoreNames);
+  db->mIndexNames.SwapElements(aIndexNames);
+  db->mVersion.Assign(aVersion);
+  db->mDatabaseFilePath.Assign(aDatabaseFilePath);
 
-          rv = dbFile->Append(filename);
-          NS_ENSURE_SUCCESS(rv, nsnull);
-
-          rv = dbFile->Exists(&exists);
-          NS_ENSURE_SUCCESS(rv, nsnull);
-
-          if (exists) {
-            nsCOMPtr<mozIStorageService> ss =
-              do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
-
-            nsCOMPtr<mozIStorageConnection> connection;
-            rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
-            NS_ENSURE_SUCCESS(rv, nsnull);
-
-            // Check to make sure that the database schema is correct.
-            PRInt32 schemaVersion;
-            rv = connection->GetSchemaVersion(&schemaVersion);
-            NS_ENSURE_SUCCESS(rv, nsnull);
+  aThread->SetWeakIdleObserver(db);
+  db->mConnectionThread = aThread;
 
-            if (schemaVersion == DB_SCHEMA_VERSION) {
-              nsCOMPtr<mozIStorageStatement> stmt;
-              rv = connection->CreateStatement(NS_LITERAL_CSTRING(
-                "SELECT name "
-                "FROM object_store"
-              ), getter_AddRefs(stmt));
-              NS_ENSURE_SUCCESS(rv, nsnull);
-
-              PRBool hasResult;
-              while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
-                nsString name;
-                (void)stmt->GetString(0, name);
-                NS_ENSURE_TRUE(db->mObjectStoreNames.AppendElement(name),
-                               nsnull);
-              }
-            }
-          }
-        }
-      }
-    }
-  }
-#endif
+  db->mConnection.swap(aConnection);
 
   return db.forget();
 }
 
 IDBDatabaseRequest::IDBDatabaseRequest()
 : mReadOnly(PR_FALSE)
 {
   
@@ -389,121 +213,21 @@ IDBDatabaseRequest::Connection()
   return mConnection;
 }
 
 nsresult
 IDBDatabaseRequest::EnsureConnection()
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
 
-  if (Connection()) {
-    return NS_OK;
-  }
-
-  nsCOMPtr<nsIFile> dbFile;
-  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
-                                       getter_AddRefs(dbFile));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = dbFile->Append(NS_LITERAL_STRING("indexedDB"));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  PRBool exists;
-  rv = dbFile->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (exists) {
-    PRBool isDirectory;
-    rv = dbFile->IsDirectory(&isDirectory);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(isDirectory, NS_ERROR_UNEXPECTED);
-  }
-  else {
-    rv = dbFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  nsAutoString filename;
-  filename.AppendInt(HashString(mASCIIOrigin));
-
-  rv = dbFile->Append(filename);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = dbFile->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (exists) {
-    PRBool isDirectory;
-    rv = dbFile->IsDirectory(&isDirectory);
-    NS_ENSURE_SUCCESS(rv, rv);
-    NS_ENSURE_TRUE(isDirectory, NS_ERROR_UNEXPECTED);
-  }
-  else {
-    rv = dbFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
-    NS_ENSURE_SUCCESS(rv, rv);
+  if (!mConnection) {
+    mConnection = IndexedDatabaseRequest::GetConnection(mDatabaseFilePath);
+    NS_ENSURE_TRUE(mConnection, NS_ERROR_FAILURE);
   }
 
-  filename.Truncate();
-  filename.AppendInt(HashString(mName));
-  filename.AppendLiteral(".sqlite");
-
-  rv = dbFile->Append(filename);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = dbFile->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsCOMPtr<mozIStorageService> ss =
-    do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
-
-  nsCOMPtr<mozIStorageConnection> connection;
-  rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
-  if (rv == NS_ERROR_FILE_CORRUPTED) {
-    // Nuke the database file.  The web services can recreate their data.
-    rv = dbFile->Remove(PR_FALSE);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    exists = PR_FALSE;
-
-    rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
-  }
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Check to make sure that the database schema is correct.
-  PRInt32 schemaVersion;
-  rv = connection->GetSchemaVersion(&schemaVersion);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (schemaVersion != DB_SCHEMA_VERSION) {
-    if (exists) {
-      // If the connection is not at the right schema version, nuke it.
-      rv = dbFile->Remove(PR_FALSE);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-
-    rv = CreateTables(connection);
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-#ifdef DEBUG
-  // Check to make sure that the database schema is correct again.
-  NS_ASSERTION(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)) &&
-               schemaVersion == DB_SCHEMA_VERSION,
-               "CreateTables failed!");
-
-  // Turn on foreign key constraints in debug builds to catch bugs!
-  (void)connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "PRAGMA foreign_keys = ON;"
-  ));
-#endif
-
-  connection.swap(mConnection);
   return NS_OK;
 }
 
 already_AddRefed<mozIStorageStatement>
 IDBDatabaseRequest::PutStatement(bool aOverwrite,
                                  bool aAutoIncrement)
 {
   NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
--- a/dom/indexedDB/IDBDatabaseRequest.h
+++ b/dom/indexedDB/IDBDatabaseRequest.h
@@ -64,17 +64,23 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIIDBDATABASE
   NS_DECL_NSIIDBDATABASEREQUEST
   NS_DECL_NSIOBSERVER
 
   static already_AddRefed<IDBDatabaseRequest>
   Create(const nsAString& aName,
          const nsAString& aDescription,
-         PRBool aReadOnly);
+         PRBool aReadOnly,
+         nsTArray<nsString>& aObjectStoreNames,
+         nsTArray<nsString>& aIndexNames,
+         const nsAString& aVersion,
+         LazyIdleThread* aThread,
+         const nsAString& aDatabaseFilePath,
+         nsCOMPtr<mozIStorageConnection>& aConnection);
 
   // Only meant to be called on mStorageThread!
   nsCOMPtr<mozIStorageConnection>& Connection();
 
   // Only meant to be called on mStorageThread!
   nsresult EnsureConnection();
 
   /**
@@ -114,21 +120,21 @@ public:
   void OnIndexCreated(const nsAString& aName);
   void OnObjectStoreRemoved(const nsAString& aName);
 
 protected:
   IDBDatabaseRequest();
   ~IDBDatabaseRequest();
 
 private:
-  nsCString mASCIIOrigin;
   nsString mName;
   nsString mDescription;
   PRBool mReadOnly;
   nsString mVersion;
+  nsString mDatabaseFilePath;
 
   nsTArray<nsString> mObjectStoreNames;
   nsTArray<nsString> mIndexNames;
 
   nsCOMPtr<nsIIDBTransaction> mCurrentTransaction;
 
   nsRefPtr<LazyIdleThread> mConnectionThread;
 
--- a/dom/indexedDB/IndexedDatabaseRequest.cpp
+++ b/dom/indexedDB/IndexedDatabaseRequest.cpp
@@ -34,56 +34,427 @@
  * 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 "IndexedDatabaseRequest.h"
 
-#include "nsDOMClassInfo.h"
-#include "nsThreadUtils.h"
+#include "nsIIDBDatabaseException.h"
+#include "nsILocalFile.h"
 
+#include "mozilla/Storage.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "nsComponentManagerUtils.h"
+#include "nsContentUtils.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsDOMClassInfo.h"
+#include "nsHashKeys.h"
+#include "nsServiceManagerUtils.h"
+#include "nsThreadUtils.h"
+#include "nsXPCOMCID.h"
+
+#include "AsyncConnectionHelper.h"
 #include "IDBDatabaseRequest.h"
-#include "IDBRequest.h"
+#include "LazyIdleThread.h"
+
+#define DB_SCHEMA_VERSION 1
 
 USING_INDEXEDDB_NAMESPACE
 
+namespace {
+
+const PRUint32 kDefaultThreadTimeoutMS = 30000;
+
+class OpenDatabaseHelper : public AsyncConnectionHelper
+{
+public:
+  OpenDatabaseHelper(IDBRequest* aRequest,
+                     const nsAString& aName,
+                     const nsAString& aDescription,
+                     PRBool aReadOnly,
+                     const nsACString& aASCIIOrigin,
+                     LazyIdleThread* aThread)
+  : AsyncConnectionHelper(nsnull, aRequest), mName(aName),
+    mDescription(aDescription), mReadOnly(aReadOnly),
+    mASCIIOrigin(aASCIIOrigin), mThread(aThread)
+  { }
+
+  PRUint16 DoDatabaseWork();
+  void GetSuccessResult(nsIWritableVariant* aResult);
+
+private:
+  // In-params.
+  nsString mName;
+  nsString mDescription;
+  PRBool mReadOnly;
+  nsCString mASCIIOrigin;
+  nsRefPtr<LazyIdleThread> mThread;
+
+  // Out-params.
+  nsTArray<nsString> mObjectStoreNames;
+  nsTArray<nsString> mIndexNames;
+  nsString mVersion;
+
+  nsCOMPtr<mozIStorageConnection> mConnection;
+  nsString mDatabaseFilePath;
+};
+
+nsresult
+CreateTables(mozIStorageConnection* aDBConn)
+{
+  NS_PRECONDITION(!NS_IsMainThread(),
+                  "Creating tables on the main thread!");
+  NS_PRECONDITION(aDBConn, "Passing a null database connection!");
+
+  // Table `database`
+  nsresult rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TABLE database ("
+      "name TEXT NOT NULL, "
+      "description TEXT NOT NULL, "
+      "version TEXT DEFAULT NULL, "
+      "UNIQUE (name)"
+    ");"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Table `object_store`
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TABLE object_store ("
+      "id INTEGER, "
+      "name TEXT NOT NULL, "
+      "key_path TEXT DEFAULT NULL, "
+      "auto_increment INTEGER NOT NULL DEFAULT 0, "
+      "readers INTEGER NOT NULL DEFAULT 0, "
+      "is_writing INTEGER NOT NULL DEFAULT 0, "
+      "PRIMARY KEY (id), "
+      "UNIQUE (name)"
+    ");"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Table `object_data`
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TABLE object_data ("
+      "id INTEGER, "
+      "object_store_id INTEGER NOT NULL, "
+      "data TEXT NOT NULL, "
+      "key_value TEXT DEFAULT NULL, "
+      "PRIMARY KEY (id), "
+      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
+        "CASCADE"
+    ");"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE INDEX key_index "
+    "ON object_data (id, object_store_id);"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Table `ai_object_data`
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TABLE ai_object_data ("
+      "id INTEGER, "
+      "object_store_id INTEGER NOT NULL, "
+      "data TEXT NOT NULL, "
+      "PRIMARY KEY (id), "
+      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
+        "CASCADE"
+    ");"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE INDEX ai_key_index "
+    "ON ai_object_data (id, object_store_id);"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aDBConn->SetSchemaVersion(DB_SCHEMA_VERSION);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+CreateDatabaseConnection(const nsACString& aASCIIOrigin,
+                         const nsAString& aName,
+                         nsAString& aDatabaseFilePath,
+                         mozIStorageConnection** aConnection)
+{
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!aASCIIOrigin.IsEmpty() && !aName.IsEmpty(), "Bad arguments!");
+
+  aDatabaseFilePath.Truncate();
+
+  nsCOMPtr<nsIFile> dbFile;
+  nsresult rv = NS_GetSpecialDirectory(NS_APP_USER_PROFILE_50_DIR,
+                                       getter_AddRefs(dbFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = dbFile->Append(NS_LITERAL_STRING("indexedDB"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRBool exists;
+  rv = dbFile->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (exists) {
+    PRBool isDirectory;
+    rv = dbFile->IsDirectory(&isDirectory);
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_TRUE(isDirectory, NS_ERROR_UNEXPECTED);
+  }
+  else {
+    rv = dbFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  nsAutoString filename;
+  filename.AppendInt(HashString(aASCIIOrigin));
+
+  rv = dbFile->Append(filename);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = dbFile->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (exists) {
+    PRBool isDirectory;
+    rv = dbFile->IsDirectory(&isDirectory);
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_TRUE(isDirectory, NS_ERROR_UNEXPECTED);
+  }
+  else {
+    rv = dbFile->Create(nsIFile::DIRECTORY_TYPE, 0755);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  filename.Truncate();
+  filename.AppendInt(HashString(aName));
+  filename.AppendLiteral(".sqlite");
+
+  rv = dbFile->Append(filename);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = dbFile->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsCOMPtr<mozIStorageService> ss =
+    do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
+
+  nsCOMPtr<mozIStorageConnection> connection;
+  rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
+  if (rv == NS_ERROR_FILE_CORRUPTED) {
+    // Nuke the database file.  The web services can recreate their data.
+    rv = dbFile->Remove(PR_FALSE);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    exists = PR_FALSE;
+
+    rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
+  }
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Check to make sure that the database schema is correct.
+  PRInt32 schemaVersion;
+  rv = connection->GetSchemaVersion(&schemaVersion);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (schemaVersion != DB_SCHEMA_VERSION) {
+    if (exists) {
+      // If the connection is not at the right schema version, nuke it.
+      rv = dbFile->Remove(PR_FALSE);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+
+    rv = CreateTables(connection);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+#ifdef DEBUG
+  // Check to make sure that the database schema is correct again.
+  NS_ASSERTION(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)) &&
+               schemaVersion == DB_SCHEMA_VERSION,
+               "CreateTables failed!");
+
+  // Turn on foreign key constraints in debug builds to catch bugs!
+  (void)connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "PRAGMA foreign_keys = ON;"
+  ));
+#endif
+
+  rv = dbFile->GetPath(aDatabaseFilePath);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  connection.forget(aConnection);
+  return NS_OK;
+}
+
+} // anonyomous namespace
+
 // static
 already_AddRefed<nsIIndexedDatabaseRequest>
 IndexedDatabaseRequest::Create()
 {
   nsCOMPtr<nsIIndexedDatabaseRequest> request(new IndexedDatabaseRequest());
   return request.forget();
 }
 
+// static
+already_AddRefed<mozIStorageConnection>
+IndexedDatabaseRequest::GetConnection(const nsAString& aDatabaseFilePath)
+{
+  NS_ASSERTION(StringEndsWith(aDatabaseFilePath, NS_LITERAL_STRING(".sqlite")),
+               "Bad file path!");
+
+  nsCOMPtr<nsILocalFile> dbFile(do_CreateInstance(NS_LOCAL_FILE_CONTRACTID));
+  NS_ENSURE_TRUE(dbFile, nsnull);
+
+  nsresult rv = dbFile->InitWithPath(aDatabaseFilePath);
+  NS_ENSURE_SUCCESS(rv, nsnull);
+
+  PRBool exists;
+  rv = dbFile->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, nsnull);
+  NS_ENSURE_TRUE(exists, nsnull);
+
+  nsCOMPtr<mozIStorageService> ss =
+    do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(ss, nsnull);
+
+  nsCOMPtr<mozIStorageConnection> connection;
+  rv = ss->OpenDatabase(dbFile, getter_AddRefs(connection));
+  NS_ENSURE_TRUE(ss, nsnull);
+
+#ifdef DEBUG
+  {
+    // Check to make sure that the database schema is correct again.
+    PRInt32 schemaVersion;
+    NS_ASSERTION(NS_SUCCEEDED(connection->GetSchemaVersion(&schemaVersion)) &&
+                 schemaVersion == DB_SCHEMA_VERSION,
+                 "Wrong schema!");
+
+    // Turn on foreign key constraints in debug builds to catch bugs!
+    (void)connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+      "PRAGMA foreign_keys = ON;"
+    ));
+  }
+#endif
+
+  return connection.forget();
+}
+
 NS_IMPL_ADDREF(IndexedDatabaseRequest)
 NS_IMPL_RELEASE(IndexedDatabaseRequest)
 
 NS_INTERFACE_MAP_BEGIN(IndexedDatabaseRequest)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIIndexedDatabaseRequest)
   NS_INTERFACE_MAP_ENTRY(nsIIndexedDatabaseRequest)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IndexedDatabaseRequest)
 NS_INTERFACE_MAP_END
 
 DOMCI_DATA(IndexedDatabaseRequest, IndexedDatabaseRequest)
 
 NS_IMETHODIMP
 IndexedDatabaseRequest::Open(const nsAString& aName,
                              const nsAString& aDescription,
                              PRBool aModifyDatabase,
                              PRUint8 aOptionalArgCount,
-                             nsIIDBDatabaseRequest** _retval)
+                             nsIIDBRequest** _retval)
 {
   if (aName.IsEmpty()) {
     return NS_ERROR_INVALID_ARG;
   }
 
   if (!aOptionalArgCount) {
     // aModifyDatabase defaults to true.
     aModifyDatabase = PR_TRUE;
   }
 
-  nsRefPtr<IDBDatabaseRequest> database =
-    IDBDatabaseRequest::Create(aName, aDescription, !aModifyDatabase);
-  database.forget(_retval);
+  nsCOMPtr<nsIPrincipal> principal;
+  nsresult rv = nsContentUtils::GetSecurityManager()->
+    GetSubjectPrincipal(getter_AddRefs(principal));
+  NS_ENSURE_SUCCESS(rv, nsnull);
+
+  nsCString origin;
+  if (nsContentUtils::IsSystemPrincipal(principal)) {
+    origin.AssignLiteral("chrome");
+  }
+  else {
+    rv = nsContentUtils::GetASCIIOrigin(principal, origin);
+    NS_ENSURE_SUCCESS(rv, nsnull);
+  }
+
+  nsRefPtr<IDBRequest> request = GenerateRequest();
+  nsRefPtr<LazyIdleThread> thread(new LazyIdleThread(kDefaultThreadTimeoutMS,
+                                                     nsnull));
+
+  nsRefPtr<OpenDatabaseHelper> runnable =
+    new OpenDatabaseHelper(request, aName, aDescription, !aModifyDatabase,
+                           origin, thread);
+
+  rv = runnable->Dispatch(thread);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  request.forget(_retval);
   return NS_OK;
 }
+
+PRUint16
+OpenDatabaseHelper::DoDatabaseWork()
+{
+#ifdef DEBUG
+  {
+    PRBool correctThread;
+    NS_ASSERTION(NS_SUCCEEDED(mThread->IsOnCurrentThread(&correctThread)) &&
+                 correctThread,
+                 "Running on the wrong thread!");
+  }
+#endif
+  nsresult rv = CreateDatabaseConnection(mASCIIOrigin, mName, mDatabaseFilePath,
+                                         getter_AddRefs(mConnection));
+  NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
+
+  nsCOMPtr<mozIStorageStatement> stmt;
+  rv = mConnection->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT name "
+    "FROM object_store"
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
+
+  PRBool hasResult;
+  while (NS_SUCCEEDED(stmt->ExecuteStep(&hasResult)) && hasResult) {
+    nsString* name = mObjectStoreNames.AppendElement();
+    NS_ENSURE_TRUE(name, nsIIDBDatabaseException::UNKNOWN_ERR);
+
+    rv = stmt->GetString(0, *name);
+    NS_ENSURE_SUCCESS(rv, nsIIDBDatabaseException::UNKNOWN_ERR);
+  }
+
+  NS_WARNING("Need to load index names here!");
+  NS_WARNING("Need to load version here!");
+
+  return OK;
+}
+
+void
+OpenDatabaseHelper::GetSuccessResult(nsIWritableVariant* aResult)
+{
+  NS_ASSERTION(mConnection, "Should have a connection!");
+
+  nsRefPtr<IDBDatabaseRequest> db =
+    IDBDatabaseRequest::Create(mName, mDescription, mReadOnly,
+                               mObjectStoreNames, mIndexNames, mVersion,
+                               mThread, mDatabaseFilePath, mConnection);
+  NS_ASSERTION(db, "This can't fail!");
+
+  NS_ASSERTION(!mConnection, "Should have swapped out!");
+
+  aResult->SetAsISupports(static_cast<IDBRequest::Generator*>(db));
+}
--- a/dom/indexedDB/IndexedDatabaseRequest.h
+++ b/dom/indexedDB/IndexedDatabaseRequest.h
@@ -35,29 +35,37 @@
  * 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 ***** */
 
 #ifndef mozilla_dom_indexeddb_indexeddatabaserequest_h__
 #define mozilla_dom_indexeddb_indexeddatabaserequest_h__
 
-#include "mozilla/dom/indexedDB/IndexedDatabase.h"
+#include "mozilla/dom/indexedDB/IDBRequest.h"
 
+#include "mozIStorageConnection.h"
 #include "nsIIndexedDatabaseRequest.h"
 
 BEGIN_INDEXEDDB_NAMESPACE
 
-class IndexedDatabaseRequest : public nsIIndexedDatabaseRequest
+class IndexedDatabaseRequest : public IDBRequest::Generator,
+                               public nsIIndexedDatabaseRequest
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIINDEXEDDATABASEREQUEST
 
-  static already_AddRefed<nsIIndexedDatabaseRequest> Create();
+  static
+  already_AddRefed<nsIIndexedDatabaseRequest>
+  Create();
+
+  static
+  already_AddRefed<mozIStorageConnection>
+  GetConnection(const nsAString& aDatabaseFilePath);
 
 protected:
   // Only called by Create().
   IndexedDatabaseRequest() { }
 };
 
 END_INDEXEDDB_NAMESPACE
 
--- a/dom/indexedDB/nsIIndexedDatabaseRequest.idl
+++ b/dom/indexedDB/nsIIndexedDatabaseRequest.idl
@@ -35,24 +35,24 @@
  * 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 "nsISupports.idl"
 
-interface nsIIDBDatabaseRequest;
+interface nsIIDBRequest;
 
 /**
  * Interface that defines the indexedDB property on a window.  See
  * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IndexedDatabaseRequest
  * for more information.
  */
 [scriptable, uuid(043161e0-93b8-43b4-94d8-f34046d679b4)]
 interface nsIIndexedDatabaseRequest : nsISupports
 {
   [optional_argc]
-  nsIIDBDatabaseRequest
+  nsIIDBRequest
   open(in AString name,
        in AString description,
        [optional /* true */] in boolean modifyDatabase);
 };
--- a/dom/indexedDB/test/test_create_objectStore.html
+++ b/dom/indexedDB/test/test_create_objectStore.html
@@ -14,46 +14,50 @@
     function run_test()
     {
       const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
       const name = window.location.pathname;
       const description = "My Test Database";
       const objectStoreName = "Objects";
 
       function errorHandler(event) {
-        ok(false, "indexedDB error (" + event.error.code + "): " +
-           event.error.message);
+        ok(false, "indexedDB error (" + event.code + "): " + event.message);
         SimpleTest.finish();
       }
 
-      var db = indexedDB.open(name, description);
-
-      var count = db.objectStores.length;
-      is(count, 0, "Bad objectStores list");
-
-      var request;
-
-      try {
-        request = db.createObjectStore(null, null);
-        ok(false, "createObjectStore with null name should have thrown!");
-      }
-      catch(e) {
-        is(request, undefined, "Shouldn't be set to anything");
-      }
-
-      request = db.createObjectStore(objectStoreName, null);
+      var request = indexedDB.open(name, description);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        var objectStore = event.result;
-        is(objectStore.name, objectStoreName, "Bad name");
-        is(objectStore.mode, nsIIDBObjectStore.READ_WRITE, "Bad mode");
-        is(objectStore.keyPath, null, "Bad keyPath");
-        if(objectStore.indexNames.length, 0, "Bad indexNames");
-        is(db.objectStores.length, 1, "Bad objectStores list");
-        SimpleTest.finish();
+        ok(event.source === indexedDB, "correct event.source");
+        var db = event.result;
+
+        var count = db.objectStores.length;
+        is(count, 0, "correct objectStores list");
+
+        try {
+          request = db.createObjectStore(null, null);
+          ok(false, "createObjectStore with null name should throw");
+        }
+        catch(e) {
+          ok(true, "createObjectStore with null name should throw");
+        }
+
+        request = db.createObjectStore(objectStoreName, null);
+        request.onerror = errorHandler;
+        request.onsuccess = function(event) {
+          ok(event.source === db, "correct event.source");
+          var objectStore = event.result;
+
+          is(objectStore.name, objectStoreName, "Bad name");
+          is(objectStore.mode, nsIIDBObjectStore.READ_WRITE, "Bad mode");
+          is(objectStore.keyPath, null, "Bad keyPath");
+          if(objectStore.indexNames.length, 0, "Bad indexNames");
+          is(db.objectStores.length, 1, "Bad objectStores list");
+          SimpleTest.finish();
+        }
       }
     }
 
     SimpleTest.waitForExplicitFinish();
   </script>
 
 </head>
 
--- a/dom/indexedDB/test/test_event_source.html
+++ b/dom/indexedDB/test/test_event_source.html
@@ -20,27 +20,32 @@
       function errorHandler(event) {
         ok(false, "indexedDB error (" + event.code + "): " + event.message);
         SimpleTest.finish();
       }
 
       var db;
       var objectStore;
 
-      db = indexedDB.open(name, description);
-      var request = db.createObjectStore(objectStoreName, null, true);
+      var request = indexedDB.open(name, description);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        ok(event.source === db, "correct event.source");
-        objectStore = event.result;
-        request = objectStore.put({});
+        ok(event.source === indexedDB, "correct event.source");
+        db = event.result;
+        request = db.createObjectStore(objectStoreName, null, true);
         request.onerror = errorHandler;
         request.onsuccess = function(event) {
-          ok(event.source === objectStore, "correct event.source");
-          SimpleTest.finish();
+          ok(event.source === db, "correct event.source");
+          objectStore = event.result;
+          request = objectStore.put({});
+          request.onerror = errorHandler;
+          request.onsuccess = function(event) {
+            ok(event.source === objectStore, "correct event.source");
+            SimpleTest.finish();
+          };
         };
       };
     }
 
     SimpleTest.waitForExplicitFinish();
   </script>
 
 </head>
--- a/dom/indexedDB/test/test_objectStore_remove_values.html
+++ b/dom/indexedDB/test/test_objectStore_remove_values.html
@@ -47,17 +47,22 @@ ExpectError.prototype = {
 
 function testSteps()
 {
   const IDBObjectStore = Components.interfaces.nsIIDBObjectStore;
   const IDBDatabaseException = Components.interfaces.nsIIDBDatabaseException;
   const name = window.location.pathname;
   const description = "My Test Database";
 
-  var db = indexedDB.open(name, description);
+  var request = indexedDB.open(name, description);
+  request.onerror = errorHandler;
+  request.onsuccess = continueTest;
+  yield;
+
+  var db = event.result;
 
   // Check removal for inline keys, with a key generator.
   var objectStoreName = "inline key; key generator";
   var request = db.createObjectStore(objectStoreName, "id", true);
   request.onerror = errorHandler;
   request.onsuccess = continueTest;
   yield;
 
--- a/dom/indexedDB/test/test_open_empty_db.html
+++ b/dom/indexedDB/test/test_open_empty_db.html
@@ -11,48 +11,58 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript">
     function run_test()
     {
       const name = window.location.pathname;
       const description = "My Test Database";
 
-      var db;
+      function errorHandler(event) {
+        ok(false, "indexedDB error (" + event.code + "): " + event.message);
+        SimpleTest.finish();
+      }
+
+      var request;
 
       try {
-        db = indexedDB.open("", "");
+        request = indexedDB.open("", "");
         ok(false, "Open with empty name should have thrown!");
       }
       catch(e) {
-        is(db, undefined, "Shouldn't be set to anything");
+        is(request, undefined, "Shouldn't be set to anything");
       }
 
       try {
-        db = indexedDB.open(null, "");
+        request = indexedDB.open(null, "");
         ok(false, "Open with null name should have thrown!");
       }
       catch(e) {
-        is(db, undefined, "Shouldn't be set to anything");
+        is(request, undefined, "Shouldn't be set to anything");
       }
 
-      db = indexedDB.open(name, description);
-      is(db.name, name, "Bad name");
-      is(db.description, description, "Bad description");
-      is(db.version, "", "Bad version");
+      request = indexedDB.open(name, description);
+      request.onerror = errorHandler;
+      request.onsuccess = function(event) {
+        ok(event.source == indexedDB, "event.source is correct");
+        var db = event.result;
+        is(db.name, name, "Bad name");
+        is(db.description, description, "Bad description");
+        is(db.version, "", "Bad version");
 
-      var count = db.objectStores.length;
-      is(count, 0, "Bad objectStores list");
+        var count = db.objectStores.length;
+        is(count, 0, "Bad objectStores list");
 
-      count = db.indexes.length;
-      is(count, 0, "Bad indexes list");
+        count = db.indexes.length;
+        is(count, 0, "Bad indexes list");
 
-      is(db.currentTransaction, null, "Bad transaction");
+        is(db.currentTransaction, null, "Bad transaction");
 
-      SimpleTest.finish();
+        SimpleTest.finish();
+      };
     }
 
     SimpleTest.waitForExplicitFinish();
   </script>
 
 </head>
 
 <body onload="run_test();">
--- a/dom/indexedDB/test/test_open_objectStore.html
+++ b/dom/indexedDB/test/test_open_objectStore.html
@@ -18,36 +18,39 @@
       const description = "My Test Database";
       const objectStoreName = "Objects";
 
       function errorHandler(event) {
         ok(false, "indexedDB error (" + event.code + "): " + event.message);
         SimpleTest.finish();
       }
 
-      var db = indexedDB.open(name, description);
-
-      var count = db.objectStores.length;
-      is(count, 0, "Bad objectStores list");
-
-      var request = db.createObjectStore(objectStoreName, "foo");
+      var request = indexedDB.open(name, description);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        is(db.objectStores.length, 1, "Bad objectStores list");
-        request = db.openObjectStore(objectStoreName,
-                                     nsIIDBObjectStore.READ_ONLY);
+        var db = event.result;
+        var count = db.objectStores.length;
+        is(count, 0, "Bad objectStores list");
+
+        request = db.createObjectStore(objectStoreName, "foo");
         request.onerror = errorHandler;
         request.onsuccess = function(event) {
-          var objectStore = event.result;
-          is(objectStore.name, objectStoreName, "Bad name");
-          is(objectStore.mode, nsIIDBObjectStore.READ_ONLY, "Bad mode");
-          is(objectStore.keyPath, "foo", "Bad keyPath");
-          if(objectStore.indexNames.length, 0, "Bad indexNames");
           is(db.objectStores.length, 1, "Bad objectStores list");
-          SimpleTest.finish();
+          request = db.openObjectStore(objectStoreName,
+                                       nsIIDBObjectStore.READ_ONLY);
+          request.onerror = errorHandler;
+          request.onsuccess = function(event) {
+            var objectStore = event.result;
+            is(objectStore.name, objectStoreName, "Bad name");
+            is(objectStore.mode, nsIIDBObjectStore.READ_ONLY, "Bad mode");
+            is(objectStore.keyPath, "foo", "Bad keyPath");
+            if(objectStore.indexNames.length, 0, "Bad indexNames");
+            is(db.objectStores.length, 1, "Bad objectStores list");
+            SimpleTest.finish();
+          };
         };
       };
     }
 
     SimpleTest.waitForExplicitFinish();
   </script>
 
 </head>
--- a/dom/indexedDB/test/test_put_get_values.html
+++ b/dom/indexedDB/test/test_put_get_values.html
@@ -20,41 +20,45 @@
       var testString = { key: 0, value: "testString" };
       var testInt = { key: 1, value: 1002 };
 
       function errorHandler(event) {
         ok(false, "indexedDB error (" + event.code + "): " + event.message);
         SimpleTest.finish();
       }
 
-      var objectStore;
-      var db = indexedDB.open(name, description);
-      var request = db.createObjectStore(objectStoreName, null);
+      var db, objectStore;
+      var request = indexedDB.open(name, description);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        objectStore = event.result;
-        request = objectStore.put(testString.value, testString.key);
+        db = event.result;
+        request = db.createObjectStore(objectStoreName, null);
         request.onerror = errorHandler;
         request.onsuccess = function(event) {
-          is(event.result, testString.key, "Bad key");
-          request = objectStore.get(testString.key);
+          objectStore = event.result;
+          request = objectStore.put(testString.value, testString.key);
           request.onerror = errorHandler;
           request.onsuccess = function(event) {
-            is(event.result, testString.value, "Bad value");
+            is(event.result, testString.key, "Bad key");
+            request = objectStore.get(testString.key);
+            request.onerror = errorHandler;
+            request.onsuccess = function(event) {
+              is(event.result, testString.value, "Bad value");
+            };
           };
-        };
-        request = objectStore.put(testInt.value, testInt.key);
-        request.onerror = errorHandler;
-        request.onsuccess = function(event) {
-          is(event.result, testInt.key, "Bad key");
-          request = objectStore.get(testInt.key);
+          request = objectStore.put(testInt.value, testInt.key);
           request.onerror = errorHandler;
           request.onsuccess = function(event) {
-            is(event.result, testInt.value, "Bad value");
-            SimpleTest.finish();
+            is(event.result, testInt.key, "Bad key");
+            request = objectStore.get(testInt.key);
+            request.onerror = errorHandler;
+            request.onsuccess = function(event) {
+              is(event.result, testInt.value, "Bad value");
+              SimpleTest.finish();
+            };
           };
         };
       };
     }
 
     SimpleTest.waitForExplicitFinish();
   </script>
 
--- a/dom/indexedDB/test/test_put_get_values_autoIncrement.html
+++ b/dom/indexedDB/test/test_put_get_values_autoIncrement.html
@@ -20,43 +20,47 @@
       var testString = { key: -1, value: "testString" };
       var testInt = { key: -1, value: 1002 };
 
       function errorHandler(event) {
         ok(false, "indexedDB error (" + event.code + "): " + event.message);
         SimpleTest.finish();
       }
 
-      var objectStore;
-      var db = indexedDB.open(name, description);
-      var request = db.createObjectStore(objectStoreName, null, true);
+      var db, objectStore;
+      var request = indexedDB.open(name, description);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        objectStore = event.result;
-        request = objectStore.put(testString.value);
+        db = event.result;
+        request = db.createObjectStore(objectStoreName, null, true);
         request.onerror = errorHandler;
         request.onsuccess = function(event) {
-          testString.key = event.result;
-          ok(testString.key != -1, "Bad key");
-          request = objectStore.get(testString.key);
+          objectStore = event.result;
+          request = objectStore.put(testString.value);
           request.onerror = errorHandler;
           request.onsuccess = function(event) {
-            is(event.result, testString.value, "Bad value");
+            testString.key = event.result;
+            ok(testString.key != -1, "Bad key");
+            request = objectStore.get(testString.key);
+            request.onerror = errorHandler;
+            request.onsuccess = function(event) {
+              is(event.result, testString.value, "Bad value");
+            };
           };
-        };
-        request = objectStore.put(testInt.value);
-        request.onerror = errorHandler;
-        request.onsuccess = function(event) {
-          testInt.key = event.result;
-          ok(testInt.key != -1, "Bad key");
-          request = objectStore.get(testInt.key);
+          request = objectStore.put(testInt.value);
           request.onerror = errorHandler;
           request.onsuccess = function(event) {
-            is(event.result, testInt.value, "Bad value");
-            SimpleTest.finish();
+            testInt.key = event.result;
+            ok(testInt.key != -1, "Bad key");
+            request = objectStore.get(testInt.key);
+            request.onerror = errorHandler;
+            request.onsuccess = function(event) {
+              is(event.result, testInt.value, "Bad value");
+              SimpleTest.finish();
+            };
           };
         };
       };
     }
 
     SimpleTest.waitForExplicitFinish();
   </script>
 
--- a/dom/indexedDB/test/test_remove_objectStore.html
+++ b/dom/indexedDB/test/test_remove_objectStore.html
@@ -18,41 +18,45 @@
       const description = "My Test Database";
       const objectStoreName = "Objects";
 
       function errorHandler(event) {
         ok(false, "indexedDB error (" + event.code + "): " + event.message);
         SimpleTest.finish();
       }
 
-      var db = indexedDB.open(name, description);
-
-      var count = db.objectStores.length;
-      is(count, 0, "Bad objectStores list");
-
-      var request = db.createObjectStore(objectStoreName, "foo");
+      var db;
+      var request = indexedDB.open(name, description);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
-        is(db.objectStores.length, 1, "Bad objectStores list");
-        request = db.openObjectStore(objectStoreName,
-                                     nsIIDBObjectStore.READ_ONLY);
+        db = event.result;
+        var count = db.objectStores.length;
+        is(count, 0, "Bad objectStores list");
+
+        request = db.createObjectStore(objectStoreName, "foo");
         request.onerror = errorHandler;
         request.onsuccess = function(event) {
-          var objectStore = event.result;
-          is(objectStore.name, objectStoreName, "Bad name");
-          is(objectStore.mode, nsIIDBObjectStore.READ_ONLY, "Bad mode");
-          is(objectStore.keyPath, "foo", "Bad keyPath");
-          if(objectStore.indexNames.length, 0, "Bad indexNames");
           is(db.objectStores.length, 1, "Bad objectStores list");
-          request = db.removeObjectStore(objectStoreName);
+          request = db.openObjectStore(objectStoreName,
+                                       nsIIDBObjectStore.READ_ONLY);
           request.onerror = errorHandler;
           request.onsuccess = function(event) {
-            is(event.result, undefined, "Bad result");
-            is(db.objectStores.length, 0, "Bad objectStores list");
-            SimpleTest.finish();
+            var objectStore = event.result;
+            is(objectStore.name, objectStoreName, "Bad name");
+            is(objectStore.mode, nsIIDBObjectStore.READ_ONLY, "Bad mode");
+            is(objectStore.keyPath, "foo", "Bad keyPath");
+            if(objectStore.indexNames.length, 0, "Bad indexNames");
+            is(db.objectStores.length, 1, "Bad objectStores list");
+            request = db.removeObjectStore(objectStoreName);
+            request.onerror = errorHandler;
+            request.onsuccess = function(event) {
+              is(event.result, undefined, "Bad result");
+              is(db.objectStores.length, 0, "Bad objectStores list");
+              SimpleTest.finish();
+            };
           };
         };
       };
     }
 
     SimpleTest.waitForExplicitFinish();
   </script>