Merge mozilla-central to mozilla-inbound
authorMarco Bonardo <mbonardo@mozilla.com>
Fri, 21 Oct 2011 10:02:30 +0200
changeset 79073 aedcc358e4a98bb3cec1e32f0cfb6bb6dff6fca0
parent 79072 fb302f2dd9c29f48891c9493054f1978780fb4f8 (current diff)
parent 79056 edcd501674466d546fb08e96068212830e10e375 (diff)
child 79074 97437826246d06390217c4d4328b6ea72af332ad
push id247
push usertim.taubert@gmx.de
push dateSat, 22 Oct 2011 19:08:15 +0000
treeherderfx-team@72bb20c484a2 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone10.0a1
Merge mozilla-central to mozilla-inbound
dom/indexedDB/nsIIDBVersionChangeRequest.idl
--- a/content/base/src/nsGkAtomList.h
+++ b/content/base/src/nsGkAtomList.h
@@ -641,16 +641,17 @@ GK_ATOM(onanimationiteration, "onanimati
 GK_ATOM(onanimationstart, "onanimationstart")
 GK_ATOM(onAppCommand, "onAppCommand")
 GK_ATOM(onbeforecopy, "onbeforecopy")
 GK_ATOM(onbeforecut, "onbeforecut")
 GK_ATOM(onbeforepaste, "onbeforepaste")
 GK_ATOM(onbeforeprint, "onbeforeprint")
 GK_ATOM(onbeforescriptexecute, "onbeforescriptexecute")
 GK_ATOM(onbeforeunload, "onbeforeunload")
+GK_ATOM(onblocked, "onblocked")
 GK_ATOM(onblur, "onblur")
 GK_ATOM(onbroadcast, "onbroadcast")
 GK_ATOM(onchange, "onchange")
 GK_ATOM(onclick, "onclick")
 GK_ATOM(onclose, "onclose")
 GK_ATOM(oncommand, "oncommand")
 GK_ATOM(oncommandupdate, "oncommandupdate")
 GK_ATOM(oncompositionend, "oncompositionend")
@@ -736,16 +737,17 @@ GK_ATOM(ontouchstart, "ontouchstart")
 GK_ATOM(ontouchend, "ontouchend")
 GK_ATOM(ontouchmove, "ontouchmove")
 GK_ATOM(ontouchenter, "ontouchenter")
 GK_ATOM(ontouchleave, "ontouchleave")
 GK_ATOM(ontouchcancel, "ontouchcancel")
 GK_ATOM(ontransitionend, "ontransitionend")
 GK_ATOM(onunderflow, "onunderflow")
 GK_ATOM(onunload, "onunload")
+GK_ATOM(onupgradeneeded, "onupgradeneeded")
 GK_ATOM(open, "open")
 GK_ATOM(optgroup, "optgroup")
 GK_ATOM(optimum, "optimum")
 GK_ATOM(option, "option")
 GK_ATOM(_or, "or")
 GK_ATOM(order, "order")
 GK_ATOM(ordinal, "ordinal")
 GK_ATOM(orient, "orient")
--- a/content/events/src/nsEventStateManager.cpp
+++ b/content/events/src/nsEventStateManager.cpp
@@ -1670,17 +1670,18 @@ nsEventStateManager::DispatchCrossProces
     nsMouseScrollEvent* scrollEvent = static_cast<nsMouseScrollEvent*>(aEvent);
     remote->SendMouseScrollEvent(*scrollEvent);
   }
 }
 
 bool
 nsEventStateManager::IsRemoteTarget(nsIContent* target) {
   return target &&
-         target->Tag() == nsGkAtoms::browser &&
+         (target->Tag() == nsGkAtoms::browser ||
+          target->Tag() == nsGkAtoms::iframe) &&
          target->IsXUL() &&
          target->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote,
                              nsGkAtoms::_true, eIgnoreCase);
 }
 
 
 bool
 nsEventStateManager::HandleCrossProcessEvent(nsEvent *aEvent,
--- a/dom/base/domerr.msg
+++ b/dom/base/domerr.msg
@@ -90,19 +90,21 @@ DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_UNKNO
 DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR, "This error occurred because an operation was not allowed on an object. A retry of the same operation would fail unless the cause of the error is corrected.")
 DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR, "The operation failed because the requested database object could not be found. For example, an object store did not exist but was being opened.")
 DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR, "A mutation operation in the transaction failed because a constraint was not satisfied. For example, an object such as an object store or index already exists and a new one was being attempted to be created.")
 DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_DATA_ERR, "Data provided to an operation does not meet requirements.")
 DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR, "A mutation operation was attempted on a database that did not allow mutations.")
 DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR, "A request was placed against a transaction which is currently not active, or which is finished.")
 DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR, "A request was aborted, for example through a call to IDBTransaction.abort.")
 DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR, "A mutation operation was attempted in a READ_ONLY transaction.")
+DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR, "A lock for the transaction could not be obtained in a reasonable time.")
+DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR, "The current transaction exceeded its quota limitations.")
+DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_VERSION_ERR, "The operation failed because the stored database is a higher version than the version requested.")
+
 DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR, "The operation failed because the database was prevented from taking an action. The operation might be able to succeed if the application performs some recovery steps and retries the entire transaction. For example, there was not enough remaining storage space, or the storage quota was reached and the user declined to give more space to the database.")
-DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_TRANSIENT_ERR, "The operation failed because of some temporary problems. The failed operation might be able to succeed when the operation is retried without any intervention by application-level functionality.")
-DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR, "A lock for the transaction could not be obtained in a reasonable time.")
 DOM_MSG_DEF(NS_ERROR_DOM_INDEXEDDB_DEADLOCK_ERR, "The current transaction was automatically rolled back by the database because of deadlock or other transaction serialization failures.")
 
 /* DOM error codes defined by us */
 
 /* XXX string should be specified by norris */
 DOM_MSG_DEF(NS_ERROR_DOM_SECURITY_ERR, "Security error")
 DOM_MSG_DEF(NS_ERROR_DOM_SECMAN_ERR, "Unable to obtain security manager")
 DOM_MSG_DEF(NS_ERROR_DOM_WRONG_TYPE_ERR, "Object is of wrong type")
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -1500,17 +1500,17 @@ static nsDOMClassInfoData sClassInfoData
   NS_DEFINE_CLASSINFO_DATA(IDBCursorWithValue, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBKeyRange, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBIndex, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeEvent, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
-  NS_DEFINE_CLASSINFO_DATA(IDBVersionChangeRequest, nsDOMGenericSH,
+  NS_DEFINE_CLASSINFO_DATA(IDBOpenDBRequest, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(IDBDatabaseException, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
 
   NS_DEFINE_CLASSINFO_DATA(Touch, nsDOMGenericSH,
                            DOM_DEFAULT_SCRIPTABLE_FLAGS)
   NS_DEFINE_CLASSINFO_DATA(TouchList, nsDOMTouchListSH,
                            ARRAY_SCRIPTABLE_FLAGS)
@@ -4082,18 +4082,18 @@ nsDOMClassInfo::Init()
     DOM_CLASSINFO_MAP_ENTRY(nsIIDBIndex)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(IDBVersionChangeEvent, nsIIDBVersionChangeEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIIDBVersionChangeEvent)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEvent)
   DOM_CLASSINFO_MAP_END
 
-  DOM_CLASSINFO_MAP_BEGIN(IDBVersionChangeRequest, nsIIDBVersionChangeRequest)
-    DOM_CLASSINFO_MAP_ENTRY(nsIIDBVersionChangeRequest)
+  DOM_CLASSINFO_MAP_BEGIN(IDBOpenDBRequest, nsIIDBOpenDBRequest)
+    DOM_CLASSINFO_MAP_ENTRY(nsIIDBOpenDBRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIIDBRequest)
     DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
   DOM_CLASSINFO_MAP_END
 
   DOM_CLASSINFO_MAP_BEGIN(IDBDatabaseException, nsIIDBDatabaseException)
     DOM_CLASSINFO_MAP_ENTRY(nsIIDBDatabaseException)
     DOM_CLASSINFO_MAP_ENTRY(nsIException)
   DOM_CLASSINFO_MAP_END
--- a/dom/base/nsDOMClassInfoClasses.h
+++ b/dom/base/nsDOMClassInfoClasses.h
@@ -501,17 +501,17 @@ DOMCI_CLASS(IDBRequest)
 DOMCI_CLASS(IDBDatabase)
 DOMCI_CLASS(IDBObjectStore)
 DOMCI_CLASS(IDBTransaction)
 DOMCI_CLASS(IDBCursor)
 DOMCI_CLASS(IDBCursorWithValue)
 DOMCI_CLASS(IDBKeyRange)
 DOMCI_CLASS(IDBIndex)
 DOMCI_CLASS(IDBVersionChangeEvent)
-DOMCI_CLASS(IDBVersionChangeRequest)
+DOMCI_CLASS(IDBOpenDBRequest)
 DOMCI_CLASS(IDBDatabaseException)
 
 DOMCI_CLASS(Touch)
 DOMCI_CLASS(TouchList)
 DOMCI_CLASS(TouchEvent)
 
 DOMCI_CLASS(MozCSSKeyframeRule)
 DOMCI_CLASS(MozCSSKeyframesRule)
--- a/dom/base/nsDOMError.h
+++ b/dom/base/nsDOMError.h
@@ -95,20 +95,22 @@
 #define NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR     NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,3)
 #define NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR    NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,4)
 #define NS_ERROR_DOM_INDEXEDDB_DATA_ERR          NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,5)
 #define NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR   NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,6)
 #define NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR \
                                                  NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,7)
 #define NS_ERROR_DOM_INDEXEDDB_ABORT_ERR         NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,8)
 #define NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR     NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,9)
-#define NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR   NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,10)
-#define NS_ERROR_DOM_INDEXEDDB_TRANSIENT_ERR     NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,11)
-#define NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR       NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,12)
-#define NS_ERROR_DOM_INDEXEDDB_DEADLOCK_ERR      NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,13)
+#define NS_ERROR_DOM_INDEXEDDB_TIMEOUT_ERR       NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,10)
+#define NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR         NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,11)
+#define NS_ERROR_DOM_INDEXEDDB_VERSION_ERR       NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,12)
+
+#define NS_ERROR_DOM_INDEXEDDB_RECOVERABLE_ERR   NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,1001)
+#define NS_ERROR_DOM_INDEXEDDB_DEADLOCK_ERR   NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM_INDEXEDDB,1002)
 
 /* DOM error codes defined by us */
 
 #define NS_ERROR_DOM_SECURITY_ERR                NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM,1000)
 #define NS_ERROR_DOM_SECMAN_ERR                  NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM,1001)
 #define NS_ERROR_DOM_WRONG_TYPE_ERR              NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM,1002)
 #define NS_ERROR_DOM_NOT_OBJECT_ERR              NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM,1003)
 #define NS_ERROR_DOM_NOT_XPC_OBJECT_ERR          NS_ERROR_GENERATE_FAILURE(NS_ERROR_MODULE_DOM,1004)
--- a/dom/base/nsFocusManager.cpp
+++ b/dom/base/nsFocusManager.cpp
@@ -2975,17 +2975,18 @@ nsFocusManager::GetRootForFocus(nsPIDOMW
   }
 
   return rootElement;
 }
 
 TabParent*
 nsFocusManager::GetRemoteForContent(nsIContent* aContent) {
   if (!aContent ||
-      aContent->Tag() != nsGkAtoms::browser ||
+      (aContent->Tag() != nsGkAtoms::browser &&
+       aContent->Tag() != nsGkAtoms::iframe) ||
       !aContent->IsXUL() ||
       !aContent->AttrValueIs(kNameSpaceID_None, nsGkAtoms::Remote,
                              nsGkAtoms::_true, eIgnoreCase))
     return nsnull;
 
   nsCOMPtr<nsIFrameLoaderOwner> loaderOwner = do_QueryInterface(aContent);
   if (!loaderOwner)
     return nsnull;
--- a/dom/indexedDB/AsyncConnectionHelper.cpp
+++ b/dom/indexedDB/AsyncConnectionHelper.cpp
@@ -115,32 +115,53 @@ ConvertCloneBuffersToArrayInternal(
   }
 
   *aResult = OBJECT_TO_JSVAL(array);
   return NS_OK;
 }
 
 } // anonymous namespace
 
+nsresult
+HelperBase::WrapNative(JSContext* aCx,
+                       nsISupports* aNative,
+                       jsval* aResult)
+{
+  NS_ASSERTION(aCx, "Null context!");
+  NS_ASSERTION(aNative, "Null pointer!");
+  NS_ASSERTION(aResult, "Null pointer!");
+  NS_ASSERTION(mRequest, "Null request!");
+
+  JSObject* global =
+    static_cast<JSObject*>(mRequest->ScriptContext()->GetNativeGlobal());
+  NS_ENSURE_TRUE(global, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  nsresult rv =
+    nsContentUtils::WrapNative(aCx, global, aNative, aResult);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  return NS_OK;
+}
+
 AsyncConnectionHelper::AsyncConnectionHelper(IDBDatabase* aDatabase,
                                              IDBRequest* aRequest)
-: mDatabase(aDatabase),
-  mRequest(aRequest),
+: HelperBase(aRequest),
+  mDatabase(aDatabase),
   mTimeoutDuration(TimeDuration::FromMilliseconds(kDefaultTimeoutMS)),
   mResultCode(NS_OK),
   mDispatched(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 AsyncConnectionHelper::AsyncConnectionHelper(IDBTransaction* aTransaction,
                                              IDBRequest* aRequest)
-: mDatabase(aTransaction->mDatabase),
+: HelperBase(aRequest),
+  mDatabase(aTransaction->mDatabase),
   mTransaction(aTransaction),
-  mRequest(aRequest),
   mTimeoutDuration(TimeDuration::FromMilliseconds(kDefaultTimeoutMS)),
   mResultCode(NS_OK),
   mDispatched(false)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 }
 
 AsyncConnectionHelper::~AsyncConnectionHelper()
@@ -190,17 +211,17 @@ AsyncConnectionHelper::Run()
       // Instead convert to an error event.
       mResultCode = NS_ERROR_DOM_INDEXEDDB_ABORT_ERR;
     }
 
     IDBTransaction* oldTransaction = gCurrentTransaction;
     gCurrentTransaction = mTransaction;
 
     if (mRequest) {
-      nsresult rv = mRequest->SetDone(this);
+      nsresult rv = mRequest->NotifyHelperCompleted(this);
       if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
         mResultCode = rv;
       }
     }
 
     // Call OnError if the database had an error or if the OnSuccess handler
     // has an error.
     if (NS_FAILED(mResultCode) ||
@@ -374,24 +395,29 @@ AsyncConnectionHelper::GetCurrentTransac
 nsresult
 AsyncConnectionHelper::Init()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   return NS_OK;
 }
 
+already_AddRefed<nsDOMEvent>
+AsyncConnectionHelper::CreateSuccessEvent()
+{
+  return CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR));
+}
+
 nsresult
 AsyncConnectionHelper::OnSuccess()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(mRequest, "Null request!");
 
-  nsRefPtr<nsDOMEvent> event =
-    CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR));
+  nsRefPtr<nsDOMEvent> event = CreateSuccessEvent();
   if (!event) {
     NS_ERROR("Failed to create event!");
     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
   }
 
   bool dummy;
   nsresult rv = mRequest->DispatchEvent(event, &dummy);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
@@ -463,37 +489,16 @@ AsyncConnectionHelper::ReleaseMainThread
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   mDatabase = nsnull;
   mTransaction = nsnull;
   mRequest = nsnull;
 }
 
-nsresult
-AsyncConnectionHelper::WrapNative(JSContext* aCx,
-                                  nsISupports* aNative,
-                                  jsval* aResult)
-{
-  NS_ASSERTION(aCx, "Null context!");
-  NS_ASSERTION(aNative, "Null pointer!");
-  NS_ASSERTION(aResult, "Null pointer!");
-  NS_ASSERTION(mRequest, "Null request!");
-
-  JSObject* global =
-    static_cast<JSObject*>(mRequest->ScriptContext()->GetNativeGlobal());
-  NS_ENSURE_TRUE(global, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsresult rv =
-    nsContentUtils::WrapNative(aCx, global, aNative, aResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  return NS_OK;
-}
-
 // static
 nsresult
 AsyncConnectionHelper::ConvertCloneBuffersToArray(
                                 JSContext* aCx,
                                 nsTArray<JSAutoStructuredCloneBuffer>& aBuffers,
                                 jsval* aResult)
 {
   NS_ASSERTION(aCx, "Null context!");
--- a/dom/indexedDB/AsyncConnectionHelper.h
+++ b/dom/indexedDB/AsyncConnectionHelper.h
@@ -44,38 +44,65 @@
 #include "IndexedDatabase.h"
 #include "IDBDatabase.h"
 #include "IDBRequest.h"
 
 #include "mozIStorageProgressHandler.h"
 #include "nsIRunnable.h"
 #include "nsIThread.h"
 
+#include "nsDOMEvent.h"
+
 #include "mozilla/TimeStamp.h"
 
 class mozIStorageConnection;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class IDBTransaction;
 
+// A common base class for AsyncConnectionHelper and OpenDatabaseHelper that
+// IDBRequest can use.
+class HelperBase : public nsIRunnable
+{
+  friend class IDBRequest;
+public:
+  virtual nsresult GetResultCode() = 0;
+
+  virtual nsresult GetSuccessResult(JSContext* aCx,
+                                    jsval* aVal) = 0;
+
+protected:
+  HelperBase(IDBRequest* aRequest)
+    : mRequest(aRequest)
+  { }
+
+  /**
+   * Helper to wrap a native into a jsval. Uses the global object of the request
+   * to parent the native.
+   */
+  nsresult WrapNative(JSContext* aCx,
+                      nsISupports* aNative,
+                      jsval* aResult);
+
+  nsRefPtr<IDBRequest> mRequest;
+};
+
 /**
  * Must be subclassed. The subclass must implement DoDatabaseWork. It may then
  * choose to implement OnSuccess and OnError depending on the needs of the
  * subclass. If the default implementation of OnSuccess is desired then the
  * subclass can implement GetSuccessResult to properly set the result of the
  * success event. Call Dispatch to start the database operation. Must be created
  * and Dispatched from the main thread only. Target thread may not be the main
  * thread.
  */
-class AsyncConnectionHelper : public nsIRunnable,
+class AsyncConnectionHelper : public HelperBase,
                               public mozIStorageProgressHandler
 {
-  friend class IDBRequest;
-
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_MOZISTORAGEPROGRESSHANDLER
 
   nsresult Dispatch(nsIEventTarget* aDatabaseThread);
 
   // Only for transactions!
@@ -124,16 +151,23 @@ protected:
   virtual nsresult Init();
 
   /**
    * This callback is run on the database thread.
    */
   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) = 0;
 
   /**
+   * This function returns the event to be dispatched at the request when
+   * OnSuccess is called.  A subclass can override this to fire an event other
+   * than "success" at the request.
+   */
+  virtual already_AddRefed<nsDOMEvent> CreateSuccessEvent();
+
+  /**
    * This callback is run on the main thread if DoDatabaseWork returned NS_OK.
    * The default implementation fires a "success" DOM event with its target set
    * to the request. Returning anything other than NS_OK from the OnSuccess
    * callback will trigger the OnError callback.
    */
   virtual nsresult OnSuccess();
 
   /**
@@ -153,35 +187,26 @@ protected:
   /**
    * Gives the subclass a chance to release any objects that must be released
    * on the main thread, regardless of success or failure. Subclasses that
    * implement this method *MUST* call the base class implementation as well.
    */
   virtual void ReleaseMainThreadObjects();
 
   /**
-   * Helper to wrap a native into a jsval. Uses the global object of the request
-   * to parent the native.
-   */
-  nsresult WrapNative(JSContext* aCx,
-                      nsISupports* aNative,
-                      jsval* aResult);
-
-  /**
    * Helper to make a JS array object out of an array of clone buffers.
    */
   static nsresult ConvertCloneBuffersToArray(
                                 JSContext* aCx,
                                 nsTArray<JSAutoStructuredCloneBuffer>& aBuffers,
                                 jsval* aResult);
 
 protected:
   nsRefPtr<IDBDatabase> mDatabase;
   nsRefPtr<IDBTransaction> mTransaction;
-  nsRefPtr<IDBRequest> mRequest;
 
 private:
   nsCOMPtr<mozIStorageProgressHandler> mOldProgressHandler;
 
   mozilla::TimeStamp mStartTime;
   mozilla::TimeDuration mTimeoutDuration;
 
   nsresult mResultCode;
--- a/dom/indexedDB/CheckPermissionsHelper.cpp
+++ b/dom/indexedDB/CheckPermissionsHelper.cpp
@@ -145,17 +145,17 @@ CheckPermissionsHelper::Run()
     nsCOMPtr<nsIObserverService> obs = GetObserverService();
     rv = obs->NotifyObservers(static_cast<nsIRunnable*>(this),
                               TOPIC_PERMISSIONS_PROMPT, nsnull);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
-  nsRefPtr<AsyncConnectionHelper> helper;
+  nsRefPtr<OpenDatabaseHelper> helper;
   helper.swap(mHelper);
 
   nsCOMPtr<nsIDOMWindow> window;
   window.swap(mWindow);
 
   if (permission == nsIPermissionManager::ALLOW_ACTION) {
     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     NS_ASSERTION(mgr, "This should never be null!");
@@ -163,17 +163,18 @@ CheckPermissionsHelper::Run()
     return helper->Dispatch(mgr->IOThread());
   }
 
   NS_ASSERTION(permission == nsIPermissionManager::UNKNOWN_ACTION ||
                permission == nsIPermissionManager::DENY_ACTION,
                "Unknown permission!");
 
   helper->SetError(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
-  return helper->Run();
+
+  return helper->RunImmediately();
 }
 
 NS_IMETHODIMP
 CheckPermissionsHelper::GetInterface(const nsIID& aIID,
                                      void** aResult)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   if (aIID.Equals(NS_GET_IID(nsIObserver))) {
--- a/dom/indexedDB/CheckPermissionsHelper.h
+++ b/dom/indexedDB/CheckPermissionsHelper.h
@@ -36,17 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_indexeddb_checkpermissionshelper_h__
 #define mozilla_dom_indexeddb_checkpermissionshelper_h__
 
 // Only meant to be included in IndexedDB source files, not exported.
-#include "AsyncConnectionHelper.h"
+#include "OpenDatabaseHelper.h"
 
 #include "nsIInterfaceRequestor.h"
 #include "nsIObserver.h"
 #include "nsIRunnable.h"
 
 class nsIDOMWindow;
 class nsIThread;
 
@@ -57,17 +57,17 @@ class CheckPermissionsHelper : public ns
                                public nsIObserver
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_NSIINTERFACEREQUESTOR
   NS_DECL_NSIOBSERVER
 
-  CheckPermissionsHelper(AsyncConnectionHelper* aHelper,
+  CheckPermissionsHelper(OpenDatabaseHelper* aHelper,
                          nsIDOMWindow* aWindow,
                          const nsAString& aName,
                          const nsACString& aASCIIOrigin)
   : mHelper(aHelper),
     mWindow(aWindow),
     mName(aName),
     mASCIIOrigin(aASCIIOrigin),
     mHasPrompted(false),
@@ -75,17 +75,17 @@ public:
   {
     NS_ASSERTION(aHelper, "Null pointer!");
     NS_ASSERTION(aWindow, "Null pointer!");
     NS_ASSERTION(!aName.IsEmpty(), "Empty name!");
     NS_ASSERTION(!aASCIIOrigin.IsEmpty(), "Empty origin!");
   }
 
 private:
-  nsRefPtr<AsyncConnectionHelper> mHelper;
+  nsRefPtr<OpenDatabaseHelper> mHelper;
   nsCOMPtr<nsIDOMWindow> mWindow;
   nsString mName;
   nsCString mASCIIOrigin;
   bool mHasPrompted;
   PRUint32 mPromptResult;
 };
 
 END_INDEXEDDB_NAMESPACE
--- a/dom/indexedDB/DatabaseInfo.h
+++ b/dom/indexedDB/DatabaseInfo.h
@@ -63,17 +63,17 @@ struct DatabaseInfo
   static bool Put(DatabaseInfo* aInfo);
 
   static void Remove(PRUint32 aId);
 
   bool GetObjectStoreNames(nsTArray<nsString>& aNames);
   bool ContainsStoreName(const nsAString& aName);
 
   nsString name;
-  nsString version;
+  PRUint64 version;
   PRUint32 id;
   nsString filePath;
   PRInt64 nextObjectStoreId;
   PRInt64 nextIndexId;
 
   nsAutoRefCnt referenceCount;
 };
 
--- a/dom/indexedDB/IDBDatabase.cpp
+++ b/dom/indexedDB/IDBDatabase.cpp
@@ -67,34 +67,16 @@ namespace {
 const PRUint32 kDefaultDatabaseTimeoutSeconds = 30;
 
 PRUint32 gDatabaseInstanceCount = 0;
 mozilla::Mutex* gPromptHelpersMutex = nsnull;
 
 // Protected by gPromptHelpersMutex.
 nsTArray<nsRefPtr<CheckQuotaHelper> >* gPromptHelpers = nsnull;
 
-class SetVersionHelper : public AsyncConnectionHelper
-{
-public:
-  SetVersionHelper(IDBTransaction* aTransaction,
-                   IDBRequest* aRequest,
-                   const nsAString& aVersion)
-  : AsyncConnectionHelper(aTransaction, aRequest), mVersion(aVersion)
-  { }
-
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-private:
-  // In-params
-  nsString mVersion;
-};
-
 class CreateObjectStoreHelper : public AsyncConnectionHelper
 {
 public:
   CreateObjectStoreHelper(IDBTransaction* aTransaction,
                           IDBObjectStore* aObjectStore)
   : AsyncConnectionHelper(aTransaction, nsnull), mObjectStore(aObjectStore)
   { }
 
@@ -497,24 +479,24 @@ NS_IMETHODIMP
 IDBDatabase::GetName(nsAString& aName)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   aName.Assign(mName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBDatabase::GetVersion(nsAString& aVersion)
+IDBDatabase::GetVersion(PRUint64* aVersion)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   DatabaseInfo* info;
   if (!DatabaseInfo::Get(mDatabaseId, &info)) {
     NS_ERROR("This should never fail!");
   }
-  aVersion.Assign(info->version);
+  *aVersion = info->version;
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBDatabase::GetObjectStoreNames(nsIDOMDOMStringList** aObjectStores)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
@@ -683,58 +665,16 @@ IDBDatabase::DeleteObjectStore(const nsA
   nsresult rv = helper->DispatchToTransactionPool();
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   ObjectStoreInfo::Remove(mDatabaseId, aName);
   return NS_OK;
 }
 
 NS_IMETHODIMP
-IDBDatabase::SetVersion(const nsAString& aVersion,
-                        JSContext* aCx,
-                        nsIIDBRequest** _retval)
-{
-  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
-
-  if (mClosed) {
-    // XXX Update spec for a real error code here.
-    return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
-  }
-
-  DatabaseInfo* info;
-  if (!DatabaseInfo::Get(mDatabaseId, &info)) {
-    NS_ERROR("This should never fail!");
-  }
-
-  // Lock the whole database.
-  nsTArray<nsString> storesToOpen;
-  nsRefPtr<IDBTransaction> transaction =
-    IDBTransaction::Create(this, storesToOpen, IDBTransaction::VERSION_CHANGE,
-                           kDefaultDatabaseTimeoutSeconds, true);
-  NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<IDBVersionChangeRequest> request =
-    IDBVersionChangeRequest::Create(static_cast<nsIDOMEventTarget*>(this),
-                                    ScriptContext(), Owner(), transaction);
-  NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsRefPtr<SetVersionHelper> helper =
-    new SetVersionHelper(transaction, request, aVersion);
-
-  IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
-  NS_ASSERTION(mgr, "This should never be null!");
-
-  nsresult rv = mgr->SetDatabaseVersion(this, request, aVersion, helper);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  request.forget(_retval);
-  return NS_OK;
-}
-
-NS_IMETHODIMP
 IDBDatabase::Transaction(nsIVariant* aStoreNames,
                          PRUint16 aMode,
                          PRUint32 aTimeout,
                          JSContext* aCx,
                          PRUint8 aOptionalArgCount,
                          nsIIDBTransaction** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
@@ -929,57 +869,16 @@ IDBDatabase::PostHandleEvent(nsEventChai
       NS_ENSURE_SUCCESS(rv, rv);
     }
   }
 
   return NS_OK;
 }
 
 nsresult
-SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
-{
-  NS_PRECONDITION(aConnection, "Passing a null connection!");
-
-  nsCOMPtr<mozIStorageStatement> stmt;
-  nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
-    "UPDATE database "
-    "SET version = :version"
-  ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  rv = stmt->BindStringByName(NS_LITERAL_CSTRING("version"), mVersion);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  if (NS_FAILED(stmt->Execute())) {
-    return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
-  }
-
-  return NS_OK;
-}
-
-nsresult
-SetVersionHelper::GetSuccessResult(JSContext* aCx,
-                                   jsval* aVal)
-{
-  DatabaseInfo* info;
-  if (!DatabaseInfo::Get(mDatabase->Id(), &info)) {
-    NS_ERROR("This should never fail!");
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
-  info->version = mVersion;
-
-  nsresult rv = WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*,
-                                                  mTransaction),
-                           aVal);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-nsresult
 CreateObjectStoreHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
 {
   nsCOMPtr<mozIStorageStatement> stmt =
     mTransaction->GetCachedStatement(NS_LITERAL_CSTRING(
     "INSERT INTO object_store (id, name, key_path, auto_increment) "
     "VALUES (:id, :name, :key_path, :auto_increment)"
   ));
   NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
--- a/dom/indexedDB/IDBEvents.cpp
+++ b/dom/indexedDB/IDBEvents.cpp
@@ -98,42 +98,46 @@ mozilla::dom::indexedDB::CreateGenericEv
   nsCOMPtr<nsIDOMEvent> event(CreateGenericEvent(aType));
   NS_ENSURE_TRUE(event, nsnull);
 
   nsCOMPtr<nsIRunnable> runnable(new EventFiringRunnable(aTarget, event));
   return runnable.forget();
 }
 
 // static
-already_AddRefed<nsIDOMEvent>
+already_AddRefed<nsDOMEvent>
 IDBVersionChangeEvent::CreateInternal(const nsAString& aType,
-                                      const nsAString& aVersion)
+                                      PRUint64 aOldVersion,
+                                      PRUint64 aNewVersion)
 {
   nsRefPtr<IDBVersionChangeEvent> event(new IDBVersionChangeEvent());
 
   nsresult rv = event->InitEvent(aType, false, false);
   NS_ENSURE_SUCCESS(rv, nsnull);
 
   rv = event->SetTrusted(true);
   NS_ENSURE_SUCCESS(rv, nsnull);
 
-  event->mVersion = aVersion;
+  event->mOldVersion = aOldVersion;
+  event->mNewVersion = aNewVersion;
 
   nsDOMEvent* result;
   event.forget(&result);
   return result;
 }
 
 // static
 already_AddRefed<nsIRunnable>
 IDBVersionChangeEvent::CreateRunnableInternal(const nsAString& aType,
-                                              const nsAString& aVersion,
+                                              PRUint64 aOldVersion,
+                                              PRUint64 aNewVersion,
                                               nsIDOMEventTarget* aTarget)
 {
-  nsCOMPtr<nsIDOMEvent> event = CreateInternal(aType, aVersion);
+  nsRefPtr<nsDOMEvent> event =
+    CreateInternal(aType, aOldVersion, aNewVersion);
   NS_ENSURE_TRUE(event, nsnull);
 
   nsCOMPtr<nsIRunnable> runnable(new EventFiringRunnable(aTarget, event));
   return runnable.forget();
 }
 
 NS_IMPL_ADDREF_INHERITED(IDBVersionChangeEvent, nsDOMEvent)
 NS_IMPL_RELEASE_INHERITED(IDBVersionChangeEvent, nsDOMEvent)
@@ -141,13 +145,22 @@ NS_IMPL_RELEASE_INHERITED(IDBVersionChan
 NS_INTERFACE_MAP_BEGIN(IDBVersionChangeEvent)
   NS_INTERFACE_MAP_ENTRY(nsIIDBVersionChangeEvent)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBVersionChangeEvent)
 NS_INTERFACE_MAP_END_INHERITING(nsDOMEvent)
 
 DOMCI_DATA(IDBVersionChangeEvent, IDBVersionChangeEvent)
 
 NS_IMETHODIMP
-IDBVersionChangeEvent::GetVersion(nsAString& aVersion)
+IDBVersionChangeEvent::GetOldVersion(PRUint64* aOldVersion)
 {
-  aVersion.Assign(mVersion);
+  NS_ENSURE_ARG_POINTER(aOldVersion);
+  *aOldVersion = mOldVersion;
   return NS_OK;
 }
+
+NS_IMETHODIMP
+IDBVersionChangeEvent::GetNewVersion(PRUint64* aNewVersion)
+{
+  NS_ENSURE_ARG_POINTER(aNewVersion);
+  *aNewVersion = mNewVersion;
+  return NS_OK;
+}
--- a/dom/indexedDB/IDBEvents.h
+++ b/dom/indexedDB/IDBEvents.h
@@ -51,16 +51,17 @@
 
 #define SUCCESS_EVT_STR "success"
 #define ERROR_EVT_STR "error"
 #define COMPLETE_EVT_STR "complete"
 #define ABORT_EVT_STR "abort"
 #define TIMEOUT_EVT_STR "timeout"
 #define VERSIONCHANGE_EVT_STR "versionchange"
 #define BLOCKED_EVT_STR "blocked"
+#define UPGRADENEEDED_EVT_STR "upgradeneeded"
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 already_AddRefed<nsDOMEvent>
 CreateGenericEvent(const nsAString& aType,
                    bool aBubblesAndCancelable = false);
 
 already_AddRefed<nsIRunnable>
@@ -70,55 +71,72 @@ CreateGenericEventRunnable(const nsAStri
 class IDBVersionChangeEvent : public nsDOMEvent,
                               public nsIIDBVersionChangeEvent
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_TO_NSDOMEVENT
   NS_DECL_NSIIDBVERSIONCHANGEEVENT
 
-  inline static already_AddRefed<nsIDOMEvent>
-  Create(const nsAString& aVersion)
+  inline static already_AddRefed<nsDOMEvent>
+  Create(PRInt64 aOldVersion,
+         PRInt64 aNewVersion)
   {
-    return CreateInternal(NS_LITERAL_STRING(VERSIONCHANGE_EVT_STR), aVersion);
+    return CreateInternal(NS_LITERAL_STRING(VERSIONCHANGE_EVT_STR),
+                          aOldVersion, aNewVersion);
   }
 
-  inline static already_AddRefed<nsIDOMEvent>
-  CreateBlocked(const nsAString& aVersion)
+  inline static already_AddRefed<nsDOMEvent>
+  CreateBlocked(PRUint64 aOldVersion,
+                PRUint64 aNewVersion)
   {
-    return CreateInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR), aVersion);
+    return CreateInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR),
+                          aOldVersion, aNewVersion);
+  }
+
+  inline static already_AddRefed<nsDOMEvent>
+  CreateUpgradeNeeded(PRUint64 aOldVersion,
+                      PRUint64 aNewVersion)
+  {
+    return CreateInternal(NS_LITERAL_STRING(UPGRADENEEDED_EVT_STR),
+                          aOldVersion, aNewVersion);
   }
 
   inline static already_AddRefed<nsIRunnable>
-  CreateRunnable(const nsAString& aVersion,
+  CreateRunnable(PRUint64 aOldVersion,
+                 PRUint64 aNewVersion,
                  nsIDOMEventTarget* aTarget)
   {
     return CreateRunnableInternal(NS_LITERAL_STRING(VERSIONCHANGE_EVT_STR),
-                                  aVersion, aTarget);
+                                  aOldVersion, aNewVersion, aTarget);
   }
 
   static already_AddRefed<nsIRunnable>
-  CreateBlockedRunnable(const nsAString& aVersion,
+  CreateBlockedRunnable(PRUint64 aOldVersion,
+                        PRUint64 aNewVersion,
                         nsIDOMEventTarget* aTarget)
   {
-    return CreateRunnableInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR), aVersion,
-                                  aTarget);
+    return CreateRunnableInternal(NS_LITERAL_STRING(BLOCKED_EVT_STR),
+                                  aOldVersion, aNewVersion, aTarget);
   }
 
 protected:
   IDBVersionChangeEvent() : nsDOMEvent(nsnull, nsnull) { }
   virtual ~IDBVersionChangeEvent() { }
 
-  static already_AddRefed<nsIDOMEvent>
+  static already_AddRefed<nsDOMEvent>
   CreateInternal(const nsAString& aType,
-                 const nsAString& aVersion);
+                 PRUint64 aOldVersion,
+                 PRUint64 aNewVersion);
 
   static already_AddRefed<nsIRunnable>
   CreateRunnableInternal(const nsAString& aType,
-                         const nsAString& aVersion,
+                         PRUint64 aOldVersion,
+                         PRUint64 aNewVersion,
                          nsIDOMEventTarget* aTarget);
 
-  nsString mVersion;
+  PRUint64 mOldVersion;
+  PRUint64 mNewVersion;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbevents_h__
--- a/dom/indexedDB/IDBFactory.cpp
+++ b/dom/indexedDB/IDBFactory.cpp
@@ -48,406 +48,50 @@
 #include "mozilla/dom/ContentChild.h"
 #include "nsAppDirectoryServiceDefs.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentUtils.h"
 #include "nsDirectoryServiceUtils.h"
 #include "nsDOMClassInfoID.h"
 #include "nsIPrincipal.h"
-#include "nsEscape.h"
 #include "nsHashKeys.h"
 #include "nsPIDOMWindow.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "nsXPCOMCID.h"
 #include "nsXULAppAPI.h"
 
 #include "AsyncConnectionHelper.h"
 #include "CheckPermissionsHelper.h"
 #include "DatabaseInfo.h"
 #include "IDBDatabase.h"
+#include "IDBEvents.h"
 #include "IDBKeyRange.h"
 #include "IndexedDatabaseManager.h"
 #include "LazyIdleThread.h"
 #include "nsIScriptSecurityManager.h"
 
 using namespace mozilla;
 
-#define DB_SCHEMA_VERSION 4
-
 USING_INDEXEDDB_NAMESPACE
 
 namespace {
 
 GeckoProcessType gAllowedProcessType = GeckoProcessType_Invalid;
 
 struct ObjectStoreInfoMap
 {
   ObjectStoreInfoMap()
   : id(LL_MININT), info(nsnull) { }
 
   PRInt64 id;
   ObjectStoreInfo* info;
 };
 
-class OpenDatabaseHelper : public AsyncConnectionHelper
-{
-public:
-  OpenDatabaseHelper(IDBRequest* aRequest,
-                     const nsAString& aName,
-                     const nsACString& aASCIIOrigin)
-  : AsyncConnectionHelper(static_cast<IDBDatabase*>(nsnull), aRequest),
-    mName(aName), mASCIIOrigin(aASCIIOrigin), mDatabaseId(0),
-    mLastObjectStoreId(0), mLastIndexId(0)
-  { }
-
-  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
-  nsresult GetSuccessResult(JSContext* aCx,
-                            jsval* aVal);
-
-private:
-  // In-params.
-  nsString mName;
-  nsCString mASCIIOrigin;
-
-  // Out-params.
-  nsTArray<nsAutoPtr<ObjectStoreInfo> > mObjectStores;
-  nsString mVersion;
-  PRUint32 mDataVersion;
-  nsString mDatabaseFilePath;
-  PRUint32 mDatabaseId;
-  PRInt64 mLastObjectStoreId;
-  PRInt64 mLastIndexId;
-};
-
-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, "
-      "version TEXT DEFAULT NULL, "
-      "dataVersion INTEGER NOT NULL"
-    ");"
-  ));
-  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 NOT NULL, "
-      "auto_increment 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 BLOB NOT NULL, "
-      "key_value DEFAULT NULL, " // NONE affinity
-      "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 UNIQUE INDEX key_index "
-    "ON object_data (key_value, 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 PRIMARY KEY AUTOINCREMENT, "
-      "object_store_id INTEGER NOT NULL, "
-      "data BLOB NOT NULL, "
-      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
-        "CASCADE"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE UNIQUE INDEX ai_key_index "
-    "ON ai_object_data (id, object_store_id);"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Table `index`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE object_store_index ("
-      "id INTEGER, "
-      "object_store_id INTEGER NOT NULL, "
-      "name TEXT NOT NULL, "
-      "key_path TEXT NOT NULL, "
-      "unique_index INTEGER NOT NULL, "
-      "object_store_autoincrement INTERGER NOT NULL, "
-      "PRIMARY KEY (id), "
-      "UNIQUE (object_store_id, name), "
-      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
-        "CASCADE"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Table `index_data`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE index_data ("
-      "id INTEGER, "
-      "index_id INTEGER NOT NULL, "
-      "object_data_id INTEGER NOT NULL, "
-      "object_data_key NOT NULL, " // NONE affinity
-      "value NOT NULL, "
-      "PRIMARY KEY (id), "
-      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
-        "CASCADE, "
-      "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
-        "CASCADE"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE INDEX value_index "
-    "ON index_data (index_id, value);"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Table `unique_index_data`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE unique_index_data ("
-      "id INTEGER, "
-      "index_id INTEGER NOT NULL, "
-      "object_data_id INTEGER NOT NULL, "
-      "object_data_key NOT NULL, " // NONE affinity
-      "value NOT NULL, "
-      "PRIMARY KEY (id), "
-      "UNIQUE (index_id, value), "
-      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
-        "CASCADE "
-      "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
-        "CASCADE"
-    ");"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Table `ai_index_data`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE ai_index_data ("
-      "id INTEGER, "
-      "index_id INTEGER NOT NULL, "
-      "ai_object_data_id INTEGER NOT NULL, "
-      "value NOT NULL, "
-      "PRIMARY KEY (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);
-
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE INDEX ai_value_index "
-    "ON ai_index_data (index_id, value);"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  // Table `ai_unique_index_data`
-  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "CREATE TABLE ai_unique_index_data ("
-      "id INTEGER, "
-      "index_id INTEGER NOT NULL, "
-      "ai_object_data_id INTEGER NOT NULL, "
-      "value NOT NULL, "
-      "PRIMARY KEY (id), "
-      "UNIQUE (index_id, value), "
-      "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);
-
-  rv = aDBConn->SetSchemaVersion(DB_SCHEMA_VERSION);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return NS_OK;
-}
-
-nsresult
-CreateMetaData(mozIStorageConnection* aConnection,
-               const nsAString& aName)
-{
-  NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
-  NS_PRECONDITION(aConnection, "Null database!");
-
-  nsCOMPtr<mozIStorageStatement> stmt;
-  nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
-    "INSERT OR REPLACE INTO database (name, dataVersion) "
-    "VALUES (:name, :dataVersion)"
-  ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("dataVersion"),
-                             JS_STRUCTURED_CLONE_VERSION);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  return stmt->Execute();
-}
-
-nsresult
-GetDatabaseFile(const nsACString& aASCIIOrigin,
-                const nsAString& aName,
-                nsIFile** aDatabaseFile)
-{
-  NS_ASSERTION(!aASCIIOrigin.IsEmpty() && !aName.IsEmpty(), "Bad arguments!");
-
-  nsCOMPtr<nsIFile> dbFile;
-  nsresult rv = IDBFactory::GetDirectory(getter_AddRefs(dbFile));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin);
-  originSanitized.ReplaceChar(":/", '+');
-
-  rv = dbFile->Append(originSanitized);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  nsAutoString filename;
-  filename.AppendInt(HashString(aName));
-
-  nsCString escapedName;
-  if (!NS_Escape(NS_ConvertUTF16toUTF8(aName), escapedName, url_XPAlphas)) {
-    NS_WARNING("Can't escape database name!");
-    return NS_ERROR_UNEXPECTED;
-  }
-
-  const char* forwardIter = escapedName.BeginReading();
-  const char* backwardIter = escapedName.EndReading() - 1;
-
-  nsCString substring;
-  while (forwardIter <= backwardIter && substring.Length() < 21) {
-    if (substring.Length() % 2) {
-      substring.Append(*backwardIter--);
-    }
-    else {
-      substring.Append(*forwardIter++);
-    }
-  }
-
-  filename.Append(NS_ConvertASCIItoUTF16(substring));
-  filename.AppendLiteral(".sqlite");
-
-  rv = dbFile->Append(filename);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  dbFile.forget(aDatabaseFile);
-  return NS_OK;
-}
-
-nsresult
-CreateDatabaseConnection(const nsAString& aName,
-                         nsIFile* aDBFile,
-                         mozIStorageConnection** aConnection)
-{
-  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
-
-  nsCOMPtr<nsIFile> dbDirectory;
-  nsresult rv = aDBFile->GetParent(getter_AddRefs(dbDirectory));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  bool exists;
-  rv = aDBFile->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota");
-
-  nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
-    do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
-  NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
-
-  nsCOMPtr<mozIStorageConnection> connection;
-  rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
-                               getter_AddRefs(connection));
-  if (rv == NS_ERROR_FILE_CORRUPTED) {
-    // Nuke the database file.  The web services can recreate their data.
-    rv = aDBFile->Remove(false);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    exists = false;
-
-    rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
-                                 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 = aDBFile->Remove(false);
-      NS_ENSURE_SUCCESS(rv, rv);
-
-      rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
-                                   getter_AddRefs(connection));
-      NS_ENSURE_SUCCESS(rv, rv);
-    }
-
-    mozStorageTransaction transaction(connection, false,
-                                      mozIStorageConnection::TRANSACTION_IMMEDIATE);
-
-    rv = CreateTables(connection);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = CreateMetaData(connection, aName);
-    NS_ENSURE_SUCCESS(rv, rv);
-
-    rv = transaction.Commit();
-    NS_ENSURE_SUCCESS(rv, rv);
-  }
-
-  // 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.
-  rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
-    "PRAGMA foreign_keys = ON;"
-  ));
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  connection.forget(aConnection);
-  return NS_OK;
-}
-
 } // anonymous namespace
 
 IDBFactory::IDBFactory()
 {
   IDBFactory::NoteUsedByProcessType(XRE_GetProcessType());
 }
 
 // static
@@ -566,23 +210,22 @@ IDBFactory::GetDirectoryForOrigin(const 
   directory.forget(aDirectory);
   return NS_OK;
 }
 
 // static
 nsresult
 IDBFactory::LoadDatabaseInformation(mozIStorageConnection* aConnection,
                                     PRUint32 aDatabaseId,
-                                    nsAString& aVersion,
+                                    PRUint64* aVersion,
                                     ObjectStoreInfoArray& aObjectStores)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aConnection, "Null pointer!");
 
-  aVersion.Truncate();
   aObjectStores.Clear();
 
    // Load object store names and ids.
   nsCOMPtr<mozIStorageStatement> stmt;
   nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
     "SELECT name, id, key_path, auto_increment "
     "FROM object_store"
   ), getter_AddRefs(stmt));
@@ -667,31 +310,28 @@ IDBFactory::LoadDatabaseInformation(mozI
   rv = stmt->ExecuteStep(&hasResult);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (!hasResult) {
     NS_ERROR("Database has no version!");
     return NS_ERROR_UNEXPECTED;
   }
 
-  nsString version;
-  rv = stmt->GetString(0, version);
-  NS_ENSURE_SUCCESS(rv, rv);
+  PRInt64 version = 0;
+  rv = stmt->GetInt64(0, &version);
 
-  if (version.IsVoid()) {
-    version.SetIsVoid(false);
-  }
-  aVersion = version;
-  return NS_OK;
+  *aVersion = NS_MAX<PRInt64>(version, 0);
+
+  return rv;
 }
 
 // static
 nsresult
 IDBFactory::UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
-                                   const nsAString& aVersion,
+                                   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!");
@@ -734,21 +374,26 @@ NS_INTERFACE_MAP_BEGIN(IDBFactory)
   NS_INTERFACE_MAP_ENTRY(nsIIDBFactory)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBFactory)
 NS_INTERFACE_MAP_END
 
 DOMCI_DATA(IDBFactory, IDBFactory)
 
 NS_IMETHODIMP
 IDBFactory::Open(const nsAString& aName,
+                 PRInt64 aVersion,
                  JSContext* aCx,
-                 nsIIDBRequest** _retval)
+                 nsIIDBOpenDBRequest** _retval)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
+  if (aVersion < 1) {
+    return NS_ERROR_DOM_INDEXEDDB_NON_TRANSIENT_ERR;
+  }
+
   if (XRE_GetProcessType() == GeckoProcessType_Content) {
     // Force ContentChild to cache the path from the parent, so that
     // we do not end up in a side thread that asks for the path (which
     // would make ContentChild try to send a message in a thread other
     // than the main one).
     ContentChild::GetSingleton()->GetIndexedDBPath();
   }
 
@@ -779,224 +424,27 @@ IDBFactory::Open(const nsAString& aName,
     NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
     if (origin.EqualsLiteral("null")) {
       NS_WARNING("IndexedDB databases not allowed for this principal!");
       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
     }
   }
 
-  nsRefPtr<IDBRequest> request = IDBRequest::Create(this, context, window,
-                                                    nsnull);
+  nsRefPtr<IDBOpenDBRequest> request =
+    IDBOpenDBRequest::Create(context, window);
   NS_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   nsRefPtr<OpenDatabaseHelper> openHelper =
-    new OpenDatabaseHelper(request, aName, origin);
+    new OpenDatabaseHelper(request, aName, origin, aVersion);
 
   nsRefPtr<CheckPermissionsHelper> permissionHelper =
     new CheckPermissionsHelper(openHelper, window, aName, origin);
 
   nsRefPtr<IndexedDatabaseManager> mgr = IndexedDatabaseManager::GetOrCreate();
   NS_ENSURE_TRUE(mgr, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   rv = mgr->WaitForOpenAllowed(aName, origin, permissionHelper);
   NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
 
   request.forget(_retval);
   return NS_OK;
 }
-
-nsresult
-OpenDatabaseHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
-{
-#ifdef DEBUG
-  {
-    bool correctThread;
-    NS_ASSERTION(NS_SUCCEEDED(IndexedDatabaseManager::Get()->IOThread()->
-                              IsOnCurrentThread(&correctThread)) &&
-                 correctThread,
-                 "Running on the wrong thread!");
-  }
-#endif
-  NS_ASSERTION(!aConnection, "Huh?!");
-
-  if (IndexedDatabaseManager::IsShuttingDown()) {
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
-
-  nsCOMPtr<nsIFile> dbFile;
-  nsresult rv = GetDatabaseFile(mASCIIOrigin, mName, getter_AddRefs(dbFile));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  rv = dbFile->GetPath(mDatabaseFilePath);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsCOMPtr<nsIFile> dbDirectory;
-  rv = dbFile->GetParent(getter_AddRefs(dbDirectory));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  bool exists;
-  rv = dbDirectory->Exists(&exists);
-  NS_ENSURE_SUCCESS(rv, rv);
-
-  if (exists) {
-    bool isDirectory;
-    rv = dbDirectory->IsDirectory(&isDirectory);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-    NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  }
-  else {
-    rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
-    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-  }
-
-  IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
-  NS_ASSERTION(mgr, "This should never be null!");
-
-  rv = mgr->EnsureQuotaManagementForDirectory(dbDirectory);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  nsCOMPtr<mozIStorageConnection> connection;
-  rv = CreateDatabaseConnection(mName, dbFile, getter_AddRefs(connection));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  // Get the data version.
-  nsCOMPtr<mozIStorageStatement> stmt;
-  rv = connection->CreateStatement(NS_LITERAL_CSTRING(
-    "SELECT dataVersion "
-    "FROM database"
-  ), getter_AddRefs(stmt));
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  bool hasResult;
-  rv = stmt->ExecuteStep(&hasResult);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  if (!hasResult) {
-    NS_ERROR("Database has no dataVersion!");
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
-
-  PRInt64 dataVersion;
-  rv = stmt->GetInt64(0, &dataVersion);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  if (dataVersion > JS_STRUCTURED_CLONE_VERSION) {
-    NS_ERROR("Bad data version!");
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
-
-  if (dataVersion < JS_STRUCTURED_CLONE_VERSION) {
-    // Need to upgrade the database, here, before returning to the main thread.
-    NS_NOTYETIMPLEMENTED("Implement me!");
-  }
-
-  mDatabaseId = HashString(mDatabaseFilePath);
-  NS_ASSERTION(mDatabaseId, "HashString gave us 0?!");
-
-  rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId, mVersion,
-                                           mObjectStores);
-  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
-
-  for (PRUint32 i = 0; i < mObjectStores.Length(); i++) {
-    nsAutoPtr<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);
-  }
-
-  return NS_OK;
-}
-
-nsresult
-OpenDatabaseHelper::GetSuccessResult(JSContext* aCx,
-                                     jsval *aVal)
-{
-  DatabaseInfo* dbInfo;
-  if (DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
-    NS_ASSERTION(dbInfo->referenceCount, "Bad reference count!");
-    ++dbInfo->referenceCount;
-
-#ifdef DEBUG
-    {
-      NS_ASSERTION(dbInfo->name == mName &&
-                   dbInfo->version == mVersion &&
-                   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?!");
-
-        ObjectStoreInfo* otherInfo;
-        NS_ASSERTION(ObjectStoreInfo::Get(mDatabaseId, info->name, &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,
-                     "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++) {
-          const IndexInfo& indexInfo = info->indexes[indexIndex];
-          const IndexInfo& otherIndexInfo = otherInfo->indexes[indexIndex];
-          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 {
-    nsAutoPtr<DatabaseInfo> newInfo(new DatabaseInfo());
-
-    newInfo->name = mName;
-    newInfo->id = mDatabaseId;
-    newInfo->filePath = mDatabaseFilePath;
-    newInfo->referenceCount = 1;
-
-    if (!DatabaseInfo::Put(newInfo)) {
-      NS_ERROR("Failed to add to hash!");
-      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-    }
-
-    dbInfo = newInfo.forget();
-
-    nsresult rv = IDBFactory::UpdateDatabaseMetadata(dbInfo, mVersion,
-                                                     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;
-
-  nsRefPtr<IDBDatabase> database =
-    IDBDatabase::Create(mRequest->ScriptContext(), mRequest->Owner(), dbInfo,
-                        mASCIIOrigin);
-  if (!database) {
-    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
-  }
-
-  return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, database),
-                    aVal);
-}
--- a/dom/indexedDB/IDBFactory.h
+++ b/dom/indexedDB/IDBFactory.h
@@ -80,22 +80,22 @@ public:
 
   static nsresult
   GetDirectoryForOrigin(const nsACString& aASCIIOrigin,
                         nsIFile** aDirectory);
 
   static nsresult
   LoadDatabaseInformation(mozIStorageConnection* aConnection,
                           PRUint32 aDatabaseId,
-                          nsAString& aVersion,
+                          PRUint64* aVersion,
                           ObjectStoreInfoArray& aObjectStores);
 
   static nsresult
   UpdateDatabaseMetadata(DatabaseInfo* aDatabaseInfo,
-                         const nsAString& aVersion,
+                         PRUint64 aVersion,
                          ObjectStoreInfoArray& aObjectStores);
 
 private:
   IDBFactory();
   ~IDBFactory() { }
 
   nsCOMPtr<nsIWeakReference> mWindow;
 };
--- a/dom/indexedDB/IDBRequest.cpp
+++ b/dom/indexedDB/IDBRequest.cpp
@@ -116,17 +116,17 @@ IDBRequest::Reset()
   mHaveResultOrErrorCode = false;
   mErrorCode = 0;
   if (mResultValRooted) {
     UnrootResultVal();
   }
 }
 
 nsresult
-IDBRequest::SetDone(AsyncConnectionHelper* aHelper)
+IDBRequest::NotifyHelperCompleted(HelperBase* aHelper)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!mHaveResultOrErrorCode, "Already called!");
   NS_ASSERTION(!mResultValRooted, "Already rooted?!");
   NS_ASSERTION(JSVAL_IS_VOID(mResultVal), "Should be undefined!");
 
   // See if our window is still valid. If not then we're going to pretend that
   // we never completed.
@@ -198,22 +198,20 @@ IDBRequest::UnrootResultVal()
   mResultValRooted = false;
 }
 
 NS_IMETHODIMP
 IDBRequest::GetReadyState(PRUint16* aReadyState)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
-  if (mHaveResultOrErrorCode) {
-    *aReadyState = nsIIDBRequest::DONE;
-  }
-  else {
-    *aReadyState = nsIIDBRequest::LOADING;
-  }
+  *aReadyState = mHaveResultOrErrorCode ?
+                 nsIIDBRequest::DONE :
+                 nsIIDBRequest::LOADING;
+
   return NS_OK;
 }
 
 NS_IMETHODIMP
 IDBRequest::GetSource(nsISupports** aSource)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
@@ -340,91 +338,85 @@ IDBRequest::PreHandleEvent(nsEventChainP
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   aVisitor.mCanHandle = true;
   aVisitor.mParentTarget = mTransaction;
   return NS_OK;
 }
 
-IDBVersionChangeRequest::~IDBVersionChangeRequest()
+IDBOpenDBRequest::~IDBOpenDBRequest()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (mResultValRooted) {
     UnrootResultVal();
   }
 }
 
 // static
-already_AddRefed<IDBVersionChangeRequest>
-IDBVersionChangeRequest::Create(nsISupports* aSource,
-                                nsIScriptContext* aScriptContext,
-                                nsPIDOMWindow* aOwner,
-                                IDBTransaction* aTransaction)
+already_AddRefed<IDBOpenDBRequest>
+IDBOpenDBRequest::Create(nsIScriptContext* aScriptContext,
+                         nsPIDOMWindow* aOwner)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   if (!aScriptContext || !aOwner) {
     NS_ERROR("Null context and owner!");
     return nsnull;
   }
 
-  nsRefPtr<IDBVersionChangeRequest> request(new IDBVersionChangeRequest());
+  nsRefPtr<IDBOpenDBRequest> request(new IDBOpenDBRequest());
 
-  request->mSource = aSource;
-  request->mTransaction = aTransaction;
   request->mScriptContext = aScriptContext;
   request->mOwner = aOwner;
 
   return request.forget();
 }
 
 void
-IDBVersionChangeRequest::RootResultVal()
+IDBOpenDBRequest::SetTransaction(IDBTransaction* aTransaction)
+{
+  mTransaction = aTransaction;
+}
+
+void
+IDBOpenDBRequest::RootResultVal()
 {
   NS_ASSERTION(!mResultValRooted, "This should be false!");
-  NS_HOLD_JS_OBJECTS(this, IDBVersionChangeRequest);
+  NS_HOLD_JS_OBJECTS(this, IDBOpenDBRequest);
   mResultValRooted = true;
 }
 
 void
-IDBVersionChangeRequest::UnrootResultVal()
+IDBOpenDBRequest::UnrootResultVal()
 {
   NS_ASSERTION(mResultValRooted, "This should be true!");
-  NS_DROP_JS_OBJECTS(this, IDBVersionChangeRequest);
+  NS_DROP_JS_OBJECTS(this, IDBOpenDBRequest);
   mResultValRooted = false;
 }
 
-NS_IMETHODIMP
-IDBVersionChangeRequest::SetOnblocked(nsIDOMEventListener* aBlockedListener)
-{
-  return RemoveAddEventListener(NS_LITERAL_STRING(BLOCKED_EVT_STR),
-                                mOnBlockedListener, aBlockedListener);
-}
+NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, blocked)
+NS_IMPL_EVENT_HANDLER(IDBOpenDBRequest, upgradeneeded)
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(IDBOpenDBRequest)
 
-NS_IMETHODIMP
-IDBVersionChangeRequest::GetOnblocked(nsIDOMEventListener** aBlockedListener)
-{
-  return GetInnerEventListener(mOnBlockedListener, aBlockedListener);
-}
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(IDBVersionChangeRequest)
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBVersionChangeRequest,
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(IDBOpenDBRequest,
                                                   IDBRequest)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnBlockedListener)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnupgradeneededListener)
+  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mOnblockedListener)
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBVersionChangeRequest,
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(IDBOpenDBRequest,
                                                 IDBRequest)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnBlockedListener)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnupgradeneededListener)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mOnblockedListener)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBVersionChangeRequest)
-  NS_INTERFACE_MAP_ENTRY(nsIIDBVersionChangeRequest)
-  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBVersionChangeRequest)
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(IDBOpenDBRequest)
+  NS_INTERFACE_MAP_ENTRY(nsIIDBOpenDBRequest)
+  NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(IDBOpenDBRequest)
 NS_INTERFACE_MAP_END_INHERITING(IDBRequest)
 
-NS_IMPL_ADDREF_INHERITED(IDBVersionChangeRequest, IDBRequest)
-NS_IMPL_RELEASE_INHERITED(IDBVersionChangeRequest, IDBRequest)
+NS_IMPL_ADDREF_INHERITED(IDBOpenDBRequest, IDBRequest)
+NS_IMPL_RELEASE_INHERITED(IDBOpenDBRequest, IDBRequest)
 
-DOMCI_DATA(IDBVersionChangeRequest, IDBVersionChangeRequest)
+DOMCI_DATA(IDBOpenDBRequest, IDBOpenDBRequest)
--- a/dom/indexedDB/IDBRequest.h
+++ b/dom/indexedDB/IDBRequest.h
@@ -39,27 +39,27 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_dom_indexeddb_idbrequest_h__
 #define mozilla_dom_indexeddb_idbrequest_h__
 
 #include "mozilla/dom/indexedDB/IndexedDatabase.h"
 
 #include "nsIIDBRequest.h"
-#include "nsIIDBVersionChangeRequest.h"
+#include "nsIIDBOpenDBRequest.h"
 
-#include "nsDOMEventTargetHelper.h"
+#include "nsDOMEventTargetWrapperCache.h"
 #include "nsCycleCollectionParticipant.h"
 
 class nsIScriptContext;
 class nsPIDOMWindow;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
-class AsyncConnectionHelper;
+class HelperBase;
 class IDBTransaction;
 
 class IDBRequest : public nsDOMEventTargetHelper,
                    public nsIIDBRequest
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIIDBREQUEST
@@ -77,17 +77,25 @@ public:
 
   nsISupports* Source()
   {
     return mSource;
   }
 
   void Reset();
 
-  nsresult SetDone(AsyncConnectionHelper* aHelper);
+  nsresult NotifyHelperCompleted(HelperBase* aHelper);
+
+  void SetError(nsresult rv)
+  {
+    NS_ASSERTION(NS_FAILED(rv), "Er, what?");
+    NS_ASSERTION(mErrorCode == NS_OK, "Already have an error?");
+
+    mErrorCode = rv;
+  }
 
   nsIScriptContext* ScriptContext()
   {
     NS_ASSERTION(mScriptContext, "This should never be null!");
     return mScriptContext;
   }
 
   nsPIDOMWindow* Owner()
@@ -111,37 +119,38 @@ protected:
 
   jsval mResultVal;
 
   PRUint16 mErrorCode;
   bool mResultValRooted;
   bool mHaveResultOrErrorCode;
 };
 
-class IDBVersionChangeRequest : public IDBRequest,
-                                public nsIIDBVersionChangeRequest
+class IDBOpenDBRequest : public IDBRequest,
+                         public nsIIDBOpenDBRequest
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_FORWARD_NSIIDBREQUEST(IDBRequest::)
-  NS_DECL_NSIIDBVERSIONCHANGEREQUEST
-  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBVersionChangeRequest,
+  NS_DECL_NSIIDBOPENDBREQUEST
+  NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(IDBOpenDBRequest,
                                            IDBRequest)
 
-  ~IDBVersionChangeRequest();
+  static
+  already_AddRefed<IDBOpenDBRequest>
+  Create(nsIScriptContext* aScriptContext,
+         nsPIDOMWindow* aOwner);
 
-  static
-  already_AddRefed<IDBVersionChangeRequest>
-  Create(nsISupports* aSource,
-         nsIScriptContext* aScriptContext,
-         nsPIDOMWindow* aOwner,
-         IDBTransaction* aTransaction);
+  void SetTransaction(IDBTransaction* aTransaction);
 
   virtual void RootResultVal();
   virtual void UnrootResultVal();
 
 protected:
-  nsRefPtr<nsDOMEventListenerWrapper> mOnBlockedListener;
+  ~IDBOpenDBRequest();
+
+  nsRefPtr<nsDOMEventListenerWrapper> mOnblockedListener;
+  nsRefPtr<nsDOMEventListenerWrapper> mOnupgradeneededListener;
 };
 
 END_INDEXEDDB_NAMESPACE
 
 #endif // mozilla_dom_indexeddb_idbrequest_h__
--- a/dom/indexedDB/IDBTransaction.cpp
+++ b/dom/indexedDB/IDBTransaction.cpp
@@ -177,25 +177,33 @@ IDBTransaction::OnRequestFinished()
   if (!mPendingRequests) {
     NS_ASSERTION(mAborted || mReadyState == nsIIDBTransaction::LOADING,
                  "Bad state!");
     mReadyState = IDBTransaction::COMMITTING;
     CommitOrRollback();
   }
 }
 
+void
+IDBTransaction::SetTransactionListener(IDBTransactionListener* aListener)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(!mListener, "Shouldn't already have a listener!");
+  mListener = aListener;
+}
+
 nsresult
 IDBTransaction::CommitOrRollback()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
   TransactionThreadPool* pool = TransactionThreadPool::GetOrCreate();
   NS_ENSURE_STATE(pool);
 
-  nsRefPtr<CommitHelper> helper(new CommitHelper(this));
+  nsRefPtr<CommitHelper> helper(new CommitHelper(this, mListener));
 
   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;
@@ -770,18 +778,23 @@ IDBTransaction::Abort()
     return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
   }
 
   bool needToCommitOrRollback = mReadyState == nsIIDBTransaction::INITIAL;
 
   mAborted = true;
   mReadyState = nsIIDBTransaction::DONE;
 
+  if (Mode() == nsIIDBTransaction::VERSION_CHANGE) {
+    // If a version change transaction is aborted, the db must be closed
+    mDatabase->Close();
+  }
+
   // Fire the abort event if there are no outstanding requests. Otherwise the
-  // abort event will be fired when all outdtanding requests finish.
+  // abort event will be fired when all outstanding requests finish.
   if (needToCommitOrRollback) {
     return CommitOrRollback();
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -903,18 +916,20 @@ IDBTransaction::AfterProcessNextEvent(ns
     if(NS_FAILED(aThread->RemoveObserver(this))) {
       NS_ERROR("Failed to remove observer!");
     }
   }
 
   return NS_OK;
 }
 
-CommitHelper::CommitHelper(IDBTransaction* aTransaction)
+CommitHelper::CommitHelper(IDBTransaction* aTransaction,
+                           IDBTransactionListener* aListener)
 : mTransaction(aTransaction),
+  mListener(aListener),
   mAborted(!!aTransaction->mAborted),
   mHaveMetadata(false)
 {
   mConnection.swap(aTransaction->mConnection);
 }
 
 CommitHelper::~CommitHelper()
 {
@@ -960,17 +975,24 @@ CommitHelper::Run()
     bool dummy;
     if (NS_FAILED(mTransaction->DispatchEvent(event, &dummy))) {
       NS_WARNING("Dispatch failed!");
     }
 
 #ifdef DEBUG
     mTransaction->mFiredCompleteOrAbort = true;
 #endif
+
+    // Tell the listener (if we have one) that we're done
+    if (mListener) {
+      mListener->NotifyTransactionComplete(mTransaction);
+    }
+
     mTransaction = nsnull;
+
     return NS_OK;
   }
 
   IDBDatabase* database = mTransaction->Database();
   if (database->IsInvalidated()) {
     mAborted = true;
   }
 
@@ -989,17 +1011,17 @@ CommitHelper::Run()
       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);
+                                              &mOldVersion, mOldObjectStores);
         if (NS_SUCCEEDED(rv)) {
           mHaveMetadata = true;
         }
         else {
           NS_WARNING("Failed to get database information!");
         }
       }
     }
--- a/dom/indexedDB/IDBTransaction.h
+++ b/dom/indexedDB/IDBTransaction.h
@@ -60,16 +60,25 @@ class nsIThread;
 
 BEGIN_INDEXEDDB_NAMESPACE
 
 class AsyncConnectionHelper;
 class CommitHelper;
 struct ObjectStoreInfo;
 class TransactionThreadPool;
 
+class IDBTransactionListener
+{
+public:
+  NS_IMETHOD_(nsrefcnt) AddRef() = 0;
+  NS_IMETHOD_(nsrefcnt) Release() = 0;
+
+  virtual nsresult NotifyTransactionComplete(IDBTransaction* aTransaction) = 0;
+};
+
 class IDBTransaction : public nsDOMEventTargetHelper,
                        public nsIIDBTransaction,
                        public nsIThreadObserver
 {
   friend class AsyncConnectionHelper;
   friend class CommitHelper;
   friend class ThreadObserver;
   friend class TransactionThreadPool;
@@ -90,16 +99,18 @@ public:
          bool aDispatchDelayed = false);
 
   // nsIDOMEventTarget
   virtual nsresult PreHandleEvent(nsEventChainPreVisitor& aVisitor);
 
   void OnNewRequest();
   void OnRequestFinished();
 
+  void SetTransactionListener(IDBTransactionListener* aListener);
+
   bool StartSavepoint();
   nsresult ReleaseSavepoint();
   void RollbackSavepoint();
 
   // Only meant to be called on mStorageThread!
   nsresult GetOrCreateConnection(mozIStorageConnection** aConnection);
 
   already_AddRefed<mozIStorageStatement>
@@ -184,16 +195,18 @@ private:
   nsRefPtr<nsDOMEventListenerWrapper> mOnErrorListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnCompleteListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnAbortListener;
   nsRefPtr<nsDOMEventListenerWrapper> mOnTimeoutListener;
 
   nsInterfaceHashtable<nsCStringHashKey, mozIStorageStatement>
     mCachedStatements;
 
+  nsRefPtr<IDBTransactionListener> mListener;
+
   // Only touched on the database thread.
   nsCOMPtr<mozIStorageConnection> mConnection;
 
   // Only touched on the database thread.
   PRUint32 mSavepointCount;
 
   nsTArray<nsRefPtr<IDBObjectStore> > mCreatedObjectStores;
 
@@ -206,17 +219,18 @@ private:
 };
 
 class CommitHelper : public nsIRunnable
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
 
-  CommitHelper(IDBTransaction* aTransaction);
+  CommitHelper(IDBTransaction* aTransaction,
+               IDBTransactionListener* aListener);
   ~CommitHelper();
 
   template<class T>
   bool AddDoomedObject(nsCOMPtr<T>& aCOMPtr)
   {
     if (aCOMPtr) {
       if (!mDoomedObjects.AppendElement(do_QueryInterface(aCOMPtr))) {
         NS_ERROR("Out of memory!");
@@ -224,20 +238,21 @@ public:
       }
       aCOMPtr = nsnull;
     }
     return true;
   }
 
 private:
   nsRefPtr<IDBTransaction> mTransaction;
+  nsRefPtr<IDBTransactionListener> mListener;
   nsCOMPtr<mozIStorageConnection> mConnection;
   nsAutoTArray<nsCOMPtr<nsISupports>, 10> mDoomedObjects;
 
-  nsString mOldVersion;
+  PRUint64 mOldVersion;
   nsTArray<nsAutoPtr<ObjectStoreInfo> > mOldObjectStores;
 
   bool mAborted;
   bool mHaveMetadata;
 };
 
 END_INDEXEDDB_NAMESPACE
 
--- a/dom/indexedDB/IndexedDatabase.h
+++ b/dom/indexedDB/IndexedDatabase.h
@@ -46,16 +46,18 @@
 #include "jsapi.h"
 #include "nsAutoPtr.h"
 #include "nsCOMPtr.h"
 #include "nsDebug.h"
 #include "nsDOMError.h"
 #include "nsStringGlue.h"
 #include "nsTArray.h"
 
+#define DB_SCHEMA_VERSION 5
+
 #define BEGIN_INDEXEDDB_NAMESPACE \
   namespace mozilla { namespace dom { namespace indexedDB {
 
 #define END_INDEXEDDB_NAMESPACE \
   } /* namespace indexedDB */ } /* namepsace dom */ } /* namespace mozilla */
 
 #define USING_INDEXEDDB_NAMESPACE \
   using namespace mozilla::dom::indexedDB;
--- a/dom/indexedDB/IndexedDatabaseManager.cpp
+++ b/dom/indexedDB/IndexedDatabaseManager.cpp
@@ -144,60 +144,70 @@ EnumerateToTArray(const nsACString& aKey
 }
 
 // Responsible for calling IDBDatabase.setVersion after a pending version change
 // transaction has completed.
 class DelayedSetVersion : public nsRunnable
 {
 public:
   DelayedSetVersion(IDBDatabase* aDatabase,
-                    IDBVersionChangeRequest* aRequest,
-                    const nsAString& aVersion,
+                    IDBOpenDBRequest* aRequest,
+                    PRInt64 aOldVersion,
+                    PRInt64 aNewVersion,
                     AsyncConnectionHelper* aHelper)
   : mDatabase(aDatabase),
     mRequest(aRequest),
-    mVersion(aVersion),
+    mOldVersion(aOldVersion),
+    mNewVersion(aNewVersion),
     mHelper(aHelper)
-  { }
+  {
+    NS_ASSERTION(aDatabase, "Null database!");
+    NS_ASSERTION(aRequest, "Null request!");
+    NS_ASSERTION(aHelper, "Null helper!");
+  }
 
   NS_IMETHOD Run()
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
 
     IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
     NS_ASSERTION(mgr, "This should never be null!");
 
-    nsresult rv = mgr->SetDatabaseVersion(mDatabase, mRequest, mVersion,
+    nsresult rv = mgr->SetDatabaseVersion(mDatabase, mRequest,
+                                          mOldVersion, mNewVersion,
                                           mHelper);
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_OK;
   }
 
 private:
   nsRefPtr<IDBDatabase> mDatabase;
-  nsRefPtr<IDBVersionChangeRequest> mRequest;
-  nsString mVersion;
+  nsRefPtr<IDBOpenDBRequest> mRequest;
+  PRInt64 mOldVersion;
+  PRInt64 mNewVersion;
   nsRefPtr<AsyncConnectionHelper> mHelper;
 };
 
 // Responsible for firing "versionchange" events at all live and non-closed
 // databases, and for firing a "blocked" event at the requesting database if any
 // databases fail to close.
 class VersionChangeEventsRunnable : public nsRunnable
 {
 public:
   VersionChangeEventsRunnable(
                             IDBDatabase* aRequestingDatabase,
-                            IDBVersionChangeRequest* aRequest,
+                            IDBOpenDBRequest* aRequest,
                             nsTArray<nsRefPtr<IDBDatabase> >& aWaitingDatabases,
-                            const nsAString& aVersion)
+                            PRInt64 aOldVersion,
+                            PRInt64 aNewVersion)
   : mRequestingDatabase(aRequestingDatabase),
     mRequest(aRequest),
-    mVersion(aVersion)
+    mOldVersion(aOldVersion),
+    mNewVersion(aNewVersion)
   {
     NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
     NS_ASSERTION(aRequestingDatabase, "Null pointer!");
     NS_ASSERTION(aRequest, "Null pointer!");
 
     if (!mWaitingDatabases.SwapElements(aWaitingDatabases)) {
       NS_ERROR("This should never fail!");
     }
@@ -225,46 +235,48 @@ public:
           sheInternal->RemoveFromBFCacheSync();
         }
         NS_ASSERTION(database->IsClosed(),
                      "Kicking doc out of bfcache should have closed database");
         continue;
       }
 
       // Otherwise fire a versionchange event.
-      nsCOMPtr<nsIDOMEvent> event(IDBVersionChangeEvent::Create(mVersion));
+      nsRefPtr<nsDOMEvent> event = 
+        IDBVersionChangeEvent::Create(mOldVersion, mNewVersion);
       NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
 
       bool dummy;
       database->DispatchEvent(event, &dummy);
     }
 
     // Now check to see if any didn't close. If there are some running still
     // then fire the blocked event.
     for (PRUint32 index = 0; index < mWaitingDatabases.Length(); index++) {
       if (!mWaitingDatabases[index]->IsClosed()) {
-        nsCOMPtr<nsIDOMEvent> event =
-          IDBVersionChangeEvent::CreateBlocked(mVersion);
+        nsRefPtr<nsDOMEvent> event =
+          IDBVersionChangeEvent::CreateBlocked(mOldVersion, mNewVersion);
         NS_ENSURE_TRUE(event, NS_ERROR_FAILURE);
 
         bool dummy;
         mRequest->DispatchEvent(event, &dummy);
 
         break;
       }
     }
 
     return NS_OK;
   }
 
 private:
   nsRefPtr<IDBDatabase> mRequestingDatabase;
-  nsRefPtr<IDBVersionChangeRequest> mRequest;
+  nsRefPtr<IDBOpenDBRequest> mRequest;
   nsTArray<nsRefPtr<IDBDatabase> > mWaitingDatabases;
-  nsString mVersion;
+  PRInt64 mOldVersion;
+  PRInt64 mNewVersion;
 };
 
 } // anonymous namespace
 
 IndexedDatabaseManager::IndexedDatabaseManager()
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(!gInstance, "More than one instance!");
@@ -507,35 +519,37 @@ IndexedDatabaseManager::WaitForOpenAllow
 bool
 IndexedDatabaseManager::IsShuttingDown()
 {
   return !!gShutdown;
 }
 
 nsresult
 IndexedDatabaseManager::SetDatabaseVersion(IDBDatabase* aDatabase,
-                                           IDBVersionChangeRequest* aRequest,
-                                           const nsAString& aVersion,
+                                           IDBOpenDBRequest* aRequest,
+                                           PRInt64 aOldVersion,
+                                           PRInt64 aNewVersion,
                                            AsyncConnectionHelper* aHelper)
 {
   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   NS_ASSERTION(aDatabase, "Null pointer!");
   NS_ASSERTION(aHelper, "Null pointer!");
 
   nsresult rv;
 
   // See if another database has already asked to change the version.
   for (PRUint32 index = 0; index < mSetVersionRunnables.Length(); index++) {
     nsRefPtr<SetVersionRunnable>& runnable = mSetVersionRunnables[index];
     if (runnable->mRequestingDatabase->Id() == aDatabase->Id()) {
       if (runnable->mRequestingDatabase == aDatabase) {
         // Same database, just queue this call to run after the current
         // SetVersion transaction completes.
         nsRefPtr<DelayedSetVersion> delayed =
-          new DelayedSetVersion(aDatabase, aRequest, aVersion, aHelper);
+          new DelayedSetVersion(aDatabase, aRequest, aOldVersion, aNewVersion,
+                                aHelper);
         if (!runnable->mDelayedRunnables.AppendElement(delayed)) {
           NS_WARNING("Out of memory!");
           return NS_ERROR_OUT_OF_MEMORY;
         }
         return NS_OK;
       }
 
       // Different database, we can't let this one succeed.
@@ -595,17 +609,17 @@ IndexedDatabaseManager::SetDatabaseVersi
     nsTArray<nsRefPtr<IDBDatabase> > waitingDatabases;
     if (!waitingDatabases.AppendElements(runnable->mDatabases)) {
       NS_WARNING("Out of memory!");
       return NS_ERROR_OUT_OF_MEMORY;
     }
 
     nsRefPtr<VersionChangeEventsRunnable> eventsRunnable =
       new VersionChangeEventsRunnable(aDatabase, aRequest, waitingDatabases,
-                                      aVersion);
+                                      aOldVersion, aNewVersion);
 
     rv = NS_DispatchToCurrentThread(eventsRunnable);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
--- a/dom/indexedDB/IndexedDatabaseManager.h
+++ b/dom/indexedDB/IndexedDatabaseManager.h
@@ -92,18 +92,19 @@ public:
     return mIOThread;
   }
 
   // Returns true if we've begun the shutdown process.
   static bool IsShuttingDown();
 
   // Begins the process of setting a database version.
   nsresult SetDatabaseVersion(IDBDatabase* aDatabase,
-                              IDBVersionChangeRequest* aRequest,
-                              const nsAString& aVersion,
+                              IDBOpenDBRequest* aRequest,
+                              PRInt64 aOldVersion,
+                              PRInt64 aNewVersion,
                               AsyncConnectionHelper* aHelper);
 
   // Called when a window is being purged from the bfcache or the user leaves
   // a page which isn't going into the bfcache. Forces any live database
   // objects to close themselves and aborts any running transactions.
   void AbortCloseDatabasesForWindow(nsPIDOMWindow* aWindow);
 
   // Used to check if there are running transactions in a given window.
--- a/dom/indexedDB/Makefile.in
+++ b/dom/indexedDB/Makefile.in
@@ -62,16 +62,17 @@ CPPSRCS = \
   IDBIndex.cpp \
   IDBKeyRange.cpp \
   IDBObjectStore.cpp \
   IDBRequest.cpp \
   IDBTransaction.cpp \
   IDBFactory.cpp \
   IndexedDatabaseManager.cpp \
   LazyIdleThread.cpp \
+  OpenDatabaseHelper.cpp \
   TransactionThreadPool.cpp \
   $(NULL)
 
 EXPORTS_mozilla/dom/indexedDB = \
   IDBCursor.h \
   IDBDatabase.h \
   IDBEvents.h \
   IDBIndex.h \
@@ -105,17 +106,17 @@ XPIDLSRCS = \
   nsIIDBDatabaseException.idl \
   nsIIDBFactory.idl \
   nsIIDBIndex.idl \
   nsIIDBKeyRange.idl \
   nsIIDBObjectStore.idl \
   nsIIDBRequest.idl \
   nsIIDBTransaction.idl \
   nsIIDBVersionChangeEvent.idl \
-  nsIIDBVersionChangeRequest.idl \
+  nsIIDBOpenDBRequest.idl \
   nsIIndexedDatabaseManager.idl \
   $(NULL)
 
 ifdef ENABLE_TESTS
 DIRS += test
 endif
 
 include $(topsrcdir)/config/config.mk
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/OpenDatabaseHelper.cpp
@@ -0,0 +1,981 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Indexed Database.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben Turner <bent.mozilla@gmail.com>
+ *   Kyle Huey <me@kylehuey.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 "OpenDatabaseHelper.h"
+#include "IDBEvents.h"
+#include "IDBFactory.h"
+#include "IndexedDatabaseManager.h"
+
+#include "mozilla/storage.h"
+#include "nsIFile.h"
+
+#include "nsContentUtils.h"
+#include "nsEscape.h"
+#include "nsThreadUtils.h"
+
+USING_INDEXEDDB_NAMESPACE
+
+const extern PRUint32 kDefaultDatabaseTimeoutSeconds = 30; 
+
+namespace {
+
+nsresult
+GetDatabaseFile(const nsACString& aASCIIOrigin,
+                const nsAString& aName,
+                nsIFile** aDatabaseFile)
+{
+  NS_ASSERTION(!aASCIIOrigin.IsEmpty() && !aName.IsEmpty(), "Bad arguments!");
+
+  nsCOMPtr<nsIFile> dbFile;
+  nsresult rv = IDBFactory::GetDirectory(getter_AddRefs(dbFile));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  NS_ConvertASCIItoUTF16 originSanitized(aASCIIOrigin);
+  originSanitized.ReplaceChar(":/", '+');
+
+  rv = dbFile->Append(originSanitized);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsAutoString filename;
+  filename.AppendInt(HashString(aName));
+
+  nsCString escapedName;
+  if (!NS_Escape(NS_ConvertUTF16toUTF8(aName), escapedName, url_XPAlphas)) {
+    NS_WARNING("Can't escape database name!");
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  const char* forwardIter = escapedName.BeginReading();
+  const char* backwardIter = escapedName.EndReading() - 1;
+
+  nsCString substring;
+  while (forwardIter <= backwardIter && substring.Length() < 21) {
+    if (substring.Length() % 2) {
+      substring.Append(*backwardIter--);
+    }
+    else {
+      substring.Append(*forwardIter++);
+    }
+  }
+
+  filename.Append(NS_ConvertASCIItoUTF16(substring));
+  filename.AppendLiteral(".sqlite");
+
+  rv = dbFile->Append(filename);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  dbFile.forget(aDatabaseFile);
+  return NS_OK;
+}
+
+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, "
+      "version INTEGER NOT NULL DEFAULT 0, "
+      "dataVersion INTEGER NOT NULL"
+    ");"
+  ));
+  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 NOT NULL, "
+      "auto_increment 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 BLOB NOT NULL, "
+      "key_value DEFAULT NULL, " // NONE affinity
+      "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 UNIQUE INDEX key_index "
+    "ON object_data (key_value, 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 PRIMARY KEY AUTOINCREMENT, "
+      "object_store_id INTEGER NOT NULL, "
+      "data BLOB NOT NULL, "
+      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
+        "CASCADE"
+    ");"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE UNIQUE INDEX ai_key_index "
+    "ON ai_object_data (id, object_store_id);"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Table `index`
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TABLE object_store_index ("
+      "id INTEGER, "
+      "object_store_id INTEGER NOT NULL, "
+      "name TEXT NOT NULL, "
+      "key_path TEXT NOT NULL, "
+      "unique_index INTEGER NOT NULL, "
+      "object_store_autoincrement INTERGER NOT NULL, "
+      "PRIMARY KEY (id), "
+      "UNIQUE (object_store_id, name), "
+      "FOREIGN KEY (object_store_id) REFERENCES object_store(id) ON DELETE "
+        "CASCADE"
+    ");"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Table `index_data`
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TABLE index_data ("
+      "id INTEGER, "
+      "index_id INTEGER NOT NULL, "
+      "object_data_id INTEGER NOT NULL, "
+      "object_data_key NOT NULL, " // NONE affinity
+      "value NOT NULL, "
+      "PRIMARY KEY (id), "
+      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
+        "CASCADE, "
+      "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
+        "CASCADE"
+    ");"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE INDEX value_index "
+    "ON index_data (index_id, value);"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Table `unique_index_data`
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TABLE unique_index_data ("
+      "id INTEGER, "
+      "index_id INTEGER NOT NULL, "
+      "object_data_id INTEGER NOT NULL, "
+      "object_data_key NOT NULL, " // NONE affinity
+      "value NOT NULL, "
+      "PRIMARY KEY (id), "
+      "UNIQUE (index_id, value), "
+      "FOREIGN KEY (index_id) REFERENCES object_store_index(id) ON DELETE "
+        "CASCADE "
+      "FOREIGN KEY (object_data_id) REFERENCES object_data(id) ON DELETE "
+        "CASCADE"
+    ");"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Table `ai_index_data`
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TABLE ai_index_data ("
+      "id INTEGER, "
+      "index_id INTEGER NOT NULL, "
+      "ai_object_data_id INTEGER NOT NULL, "
+      "value NOT NULL, "
+      "PRIMARY KEY (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);
+
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE INDEX ai_value_index "
+    "ON ai_index_data (index_id, value);"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Table `ai_unique_index_data`
+  rv = aDBConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TABLE ai_unique_index_data ("
+      "id INTEGER, "
+      "index_id INTEGER NOT NULL, "
+      "ai_object_data_id INTEGER NOT NULL, "
+      "value NOT NULL, "
+      "PRIMARY KEY (id), "
+      "UNIQUE (index_id, value), "
+      "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);
+
+  rv = aDBConn->SetSchemaVersion(DB_SCHEMA_VERSION);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+CreateMetaData(mozIStorageConnection* aConnection,
+               const nsAString& aName)
+{
+  NS_PRECONDITION(!NS_IsMainThread(), "Wrong thread!");
+  NS_PRECONDITION(aConnection, "Null database!");
+
+  nsCOMPtr<mozIStorageStatement> stmt;
+  nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
+    "INSERT OR REPLACE INTO database (name, dataVersion) "
+    "VALUES (:name, :dataVersion)"
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), aName);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("dataVersion"),
+                             JS_STRUCTURED_CLONE_VERSION);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return stmt->Execute();
+}
+
+nsresult
+UpgradeSchemaFrom4To5(mozIStorageConnection* aConnection)
+{
+  nsresult rv;
+
+  mozStorageTransaction transaction(aConnection, false,
+                                 mozIStorageConnection::TRANSACTION_IMMEDIATE);
+
+  // All we changed is the type of the version column, so lets try to
+  // convert that to an integer, and if we fail, set it to 0.
+  nsCOMPtr<mozIStorageStatement> stmt;
+  rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT name, version, dataVersion "
+    "FROM database"
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsString name;
+  PRInt32 intVersion;
+  PRInt64 dataVersion;
+
+  {
+    mozStorageStatementScoper scoper(stmt);
+
+    bool hasResults;
+    rv = stmt->ExecuteStep(&hasResults);
+    NS_ENSURE_SUCCESS(rv, rv);
+    NS_ENSURE_TRUE(hasResults, NS_ERROR_FAILURE);
+
+    nsString version;
+    rv = stmt->GetString(1, version);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    intVersion = version.ToInteger(&rv, 10);
+    if (NS_FAILED(rv)) {
+      intVersion = 0;
+    }
+
+    rv = stmt->GetString(0, name);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = stmt->GetInt64(2, &dataVersion);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "DROP TABLE database"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aConnection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "CREATE TABLE database ("
+      "name TEXT NOT NULL, "
+      "version INTEGER NOT NULL DEFAULT 0, "
+      "dataVersion INTEGER NOT NULL"
+    ");"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
+    "INSERT INTO database (name, version, dataVersion) "
+    "VALUES (:name, :version, :dataVersion)"
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  {
+    mozStorageStatementScoper scoper(stmt);
+
+    rv = stmt->BindStringParameter(0, name);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = stmt->BindInt32Parameter(1, intVersion);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = stmt->BindInt64Parameter(2, dataVersion);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = stmt->Execute();
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  rv = aConnection->SetSchemaVersion(DB_SCHEMA_VERSION);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  rv = transaction.Commit();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
+nsresult
+CreateDatabaseConnection(const nsAString& aName,
+                         nsIFile* aDBFile,
+                         mozIStorageConnection** aConnection)
+{
+  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
+
+  nsCOMPtr<nsIFile> dbDirectory;
+  nsresult rv = aDBFile->GetParent(getter_AddRefs(dbDirectory));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  bool exists;
+  rv = aDBFile->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  NS_NAMED_LITERAL_CSTRING(quotaVFSName, "quota");
+
+  nsCOMPtr<mozIStorageServiceQuotaManagement> ss =
+    do_GetService(MOZ_STORAGE_SERVICE_CONTRACTID);
+  NS_ENSURE_TRUE(ss, NS_ERROR_FAILURE);
+
+  nsCOMPtr<mozIStorageConnection> connection;
+  rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
+                               getter_AddRefs(connection));
+  if (rv == NS_ERROR_FILE_CORRUPTED) {
+    // Nuke the database file.  The web services can recreate their data.
+    rv = aDBFile->Remove(false);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    exists = false;
+
+    rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
+                                 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) {
+    // This logic needs to change next time we change the schema!
+    PR_STATIC_ASSERT(DB_SCHEMA_VERSION == 5);
+    if (schemaVersion == 4) {
+      rv = UpgradeSchemaFrom4To5(connection);
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+    else {
+      // Nuke it from orbit, it's the only way to be sure.
+      if (exists) {
+        // If the connection is not at the right schema version, nuke it.
+        rv = aDBFile->Remove(false);
+        NS_ENSURE_SUCCESS(rv, rv);
+
+        rv = ss->OpenDatabaseWithVFS(aDBFile, quotaVFSName,
+                                     getter_AddRefs(connection));
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+
+      mozStorageTransaction transaction(connection, false,
+                                        mozIStorageConnection::TRANSACTION_IMMEDIATE);
+      rv = CreateTables(connection);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv = CreateMetaData(connection, aName);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      rv = transaction.Commit();
+      NS_ENSURE_SUCCESS(rv, rv);
+    }
+  }
+
+  // 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.
+  rv = connection->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "PRAGMA foreign_keys = ON;"
+  ));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  connection.forget(aConnection);
+  return NS_OK;
+}
+
+class SetVersionHelper : public AsyncConnectionHelper,
+                         public IDBTransactionListener
+{
+public:
+  SetVersionHelper(IDBTransaction* aTransaction,
+                   IDBOpenDBRequest* aRequest,
+                   OpenDatabaseHelper* aHelper,
+                   PRUint64 aRequestedVersion,
+                   PRUint64 aCurrentVersion)
+  : AsyncConnectionHelper(aTransaction, aRequest),
+    mOpenRequest(aRequest), mOpenHelper(aHelper),
+    mRequestedVersion(aRequestedVersion),
+    mCurrentVersion(aCurrentVersion)
+  {
+    mTransaction->SetTransactionListener(this);
+  }
+
+  NS_DECL_ISUPPORTS_INHERITED
+
+  nsresult DoDatabaseWork(mozIStorageConnection* aConnection);
+  nsresult GetSuccessResult(JSContext* aCx,
+                            jsval* aVal);
+
+  // SetVersionHelper never fires an error event at the request.  It hands that
+  // responsibility back to the OpenDatabaseHelper
+  void OnError() { }
+
+  // Need an upgradeneeded event here.
+  already_AddRefed<nsDOMEvent> CreateSuccessEvent();
+
+  nsresult NotifyTransactionComplete(IDBTransaction* aTransaction);
+
+private:
+  // In-params
+  nsRefPtr<OpenDatabaseHelper> mOpenHelper;
+  nsRefPtr<IDBOpenDBRequest> mOpenRequest;
+  PRUint64 mRequestedVersion;
+  PRUint64 mCurrentVersion;
+};
+
+} // anonymous namespace
+
+NS_IMPL_THREADSAFE_ISUPPORTS1(OpenDatabaseHelper, nsIRunnable);
+
+nsresult
+OpenDatabaseHelper::Dispatch(nsIEventTarget* aTarget)
+{
+  NS_ASSERTION(mState == eCreated, "We've already been dispatched?");
+  mState = eDBWork;
+
+  return aTarget->Dispatch(this, NS_DISPATCH_NORMAL);
+}
+
+nsresult
+OpenDatabaseHelper::RunImmediately()
+{
+  NS_ASSERTION(mState == eCreated, "We've already been dispatched?");
+  NS_ASSERTION(NS_FAILED(mResultCode),
+               "Should only be short-circuiting if we failed!");
+  NS_ASSERTION(NS_IsMainThread(), "All hell is about to break lose!");
+
+  mState = eFiringEvents;
+  return this->Run();
+}
+
+nsresult
+OpenDatabaseHelper::DoDatabaseWork()
+{
+#ifdef DEBUG
+  {
+    bool correctThread;
+    NS_ASSERTION(NS_SUCCEEDED(IndexedDatabaseManager::Get()->IOThread()->
+                              IsOnCurrentThread(&correctThread)) &&
+                 correctThread,
+                 "Running on the wrong thread!");
+  }
+#endif
+
+  if (IndexedDatabaseManager::IsShuttingDown()) {
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  nsCOMPtr<nsIFile> dbFile;
+  nsresult rv = GetDatabaseFile(mASCIIOrigin, mName, getter_AddRefs(dbFile));
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  rv = dbFile->GetPath(mDatabaseFilePath);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  nsCOMPtr<nsIFile> dbDirectory;
+  rv = dbFile->GetParent(getter_AddRefs(dbDirectory));
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  bool exists;
+  rv = dbDirectory->Exists(&exists);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  if (exists) {
+    bool isDirectory;
+    rv = dbDirectory->IsDirectory(&isDirectory);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+    NS_ENSURE_TRUE(isDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+  else {
+    rv = dbDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755);
+    NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+  }
+
+  IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
+  NS_ASSERTION(mgr, "This should never be null!");
+
+  rv = mgr->EnsureQuotaManagementForDirectory(dbDirectory);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  nsCOMPtr<mozIStorageConnection> connection;
+  rv = CreateDatabaseConnection(mName, dbFile, getter_AddRefs(connection));
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  // Get the data version.
+  nsCOMPtr<mozIStorageStatement> stmt;
+  rv = connection->CreateStatement(NS_LITERAL_CSTRING(
+    "SELECT dataVersion "
+    "FROM database"
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  bool hasResult;
+  rv = stmt->ExecuteStep(&hasResult);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  if (!hasResult) {
+    NS_ERROR("Database has no dataVersion!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  PRInt64 dataVersion;
+  rv = stmt->GetInt64(0, &dataVersion);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  if (dataVersion > JS_STRUCTURED_CLONE_VERSION) {
+    NS_ERROR("Bad data version!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  if (dataVersion < JS_STRUCTURED_CLONE_VERSION) {
+    // Need to upgrade the database, here, before returning to the main thread.
+    NS_NOTYETIMPLEMENTED("Implement me!");
+  }
+
+  mDatabaseId = HashString(mDatabaseFilePath);
+  NS_ASSERTION(mDatabaseId, "HashString gave us 0?!");
+
+  rv = IDBFactory::LoadDatabaseInformation(connection, mDatabaseId, &mCurrentVersion,
+                                           mObjectStores);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  for (PRUint32 i = 0; i < mObjectStores.Length(); i++) {
+    nsAutoPtr<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
+  if (mCurrentVersion > mRequestedVersion) {
+    return NS_ERROR_DOM_INDEXEDDB_VERSION_ERR;
+  }
+
+  mState = mCurrentVersion != mRequestedVersion ?
+           eSetVersionPending :
+           eFiringEvents;
+  return NS_OK;
+}
+
+nsresult
+OpenDatabaseHelper::StartSetVersion()
+{
+  NS_ASSERTION(mState == eSetVersionPending, "Why are we here?");
+
+  // In case we fail, fire error events
+  mState = eFiringEvents;
+
+  nsresult rv = EnsureSuccessResult();
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  nsTArray<nsString> storesToOpen;
+  nsRefPtr<IDBTransaction> transaction =
+    IDBTransaction::Create(mDatabase, storesToOpen,
+                           IDBTransaction::VERSION_CHANGE,
+                           kDefaultDatabaseTimeoutSeconds, true);
+  NS_ENSURE_TRUE(transaction, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  nsRefPtr<SetVersionHelper> helper =
+    new SetVersionHelper(transaction, mOpenDBRequest, this, mRequestedVersion,
+                         mCurrentVersion);
+
+  IndexedDatabaseManager* mgr = IndexedDatabaseManager::Get();
+  NS_ASSERTION(mgr, "This should never be null!");
+
+  rv = mgr->SetDatabaseVersion(mDatabase, mOpenDBRequest, mCurrentVersion,
+                               mRequestedVersion, helper);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  // The SetVersionHelper is responsible for dispatching us back to the
+  // main thread again and changing the state to eSetVersionCompleted.
+  mState = eSetVersionPending;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+OpenDatabaseHelper::Run()
+{
+  NS_ASSERTION(mState != eCreated, "Dispatch was not called?!?");
+
+  if (NS_IsMainThread()) {
+    // If we need to queue up a SetVersionHelper, do that here.
+    if (mState == eSetVersionPending) {
+      nsresult rv = StartSetVersion();
+
+      if (NS_SUCCEEDED(rv)) {
+        return rv;
+      }
+
+      SetError(rv);
+      // fall through and run the default error processing
+    }
+
+    // We've done whatever work we need to do on the DB thread, and any
+    // SetVersion stuff is done by now.
+    NS_ASSERTION(mState == eFiringEvents ||
+                 mState == eSetVersionCompleted, "Why are we here?");
+
+    if (mState == eSetVersionCompleted) {
+      mState = eFiringEvents;
+    } else {
+      // Notify the request that we're done, but only if we didn't just finish
+      // a SetVersionHelper.  In the SetVersionHelper case, that helper tells
+      // the request that it is done, and we avoid calling NotifyHandlerCompleted
+      // twice.
+
+      nsresult rv = mOpenDBRequest->NotifyHelperCompleted(this);
+      if (NS_SUCCEEDED(mResultCode) && NS_FAILED(rv)) {
+        mResultCode = rv;
+      }
+    }
+
+    NS_ASSERTION(mState == eFiringEvents, "Why are we here?");
+
+    if (NS_FAILED(mResultCode)) {
+      DispatchErrorEvent();
+    } else {
+      DispatchSuccessEvent();
+    }
+
+    return NS_OK;
+  }
+
+  // If we're on the DB thread, do that
+  NS_ASSERTION(mState == eDBWork, "Why are we here?");
+  mResultCode = DoDatabaseWork();
+  NS_ASSERTION(mState != eDBWork, "We should be doing something else now.");
+
+  return NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
+}
+
+nsresult
+OpenDatabaseHelper::EnsureSuccessResult()
+{
+  DatabaseInfo* dbInfo;
+  if (DatabaseInfo::Get(mDatabaseId, &dbInfo)) {
+    NS_ASSERTION(dbInfo->referenceCount, "Bad reference count!");
+    ++dbInfo->referenceCount;
+
+#ifdef DEBUG
+    {
+      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?!");
+
+        ObjectStoreInfo* otherInfo;
+        NS_ASSERTION(ObjectStoreInfo::Get(mDatabaseId, info->name, &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,
+                     "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++) {
+          const IndexInfo& indexInfo = info->indexes[indexIndex];
+          const IndexInfo& otherIndexInfo = otherInfo->indexes[indexIndex];
+          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 {
+    nsAutoPtr<DatabaseInfo> newInfo(new DatabaseInfo());
+
+    newInfo->name = mName;
+    newInfo->id = mDatabaseId;
+    newInfo->filePath = mDatabaseFilePath;
+    newInfo->referenceCount = 1;
+
+    if (!DatabaseInfo::Put(newInfo)) {
+      NS_ERROR("Failed to add to hash!");
+      return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+    }
+
+    dbInfo = newInfo.forget();
+
+    nsresult rv = IDBFactory::UpdateDatabaseMetadata(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;
+
+  nsRefPtr<IDBDatabase> database =
+    IDBDatabase::Create(mOpenDBRequest->ScriptContext(),
+                        mOpenDBRequest->Owner(), dbInfo, mASCIIOrigin);
+  if (!database) {
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+
+  NS_ASSERTION(!mDatabase, "Shouldn't have a database yet!");
+  mDatabase.swap(database);
+
+  return NS_OK;
+}
+
+nsresult
+OpenDatabaseHelper::GetSuccessResult(JSContext* aCx,
+                                     jsval* aVal)
+{
+  // Be careful not to load the database twice.
+  if (!mDatabase) {
+    nsresult rv = EnsureSuccessResult();
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, mDatabase),
+                    aVal);
+}
+
+nsresult
+OpenDatabaseHelper::NotifySetVersionFinished()
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
+  NS_ASSERTION(mState = eSetVersionPending, "How did we get here?");
+
+  mState = eSetVersionCompleted;
+  
+  // Dispatch ourself back to the main thread
+  return NS_DispatchToCurrentThread(this);
+}
+
+void
+OpenDatabaseHelper::DispatchSuccessEvent()
+{
+  NS_ASSERTION(mDatabase, "Doesn't seem very successful to me.");
+
+  nsRefPtr<nsDOMEvent> event =
+    CreateGenericEvent(NS_LITERAL_STRING(SUCCESS_EVT_STR));
+  if (!event) {
+    NS_ERROR("Failed to create event!");
+    return;
+  }
+
+  bool dummy;
+  mOpenDBRequest->DispatchEvent(event, &dummy);
+}
+
+void
+OpenDatabaseHelper::DispatchErrorEvent()
+{
+  nsRefPtr<nsDOMEvent> event =
+    CreateGenericEvent(NS_LITERAL_STRING(ERROR_EVT_STR));
+  if (!event) {
+    NS_ERROR("Failed to create event!");
+    return;
+  }
+
+  PRUint16 errorCode = 0;
+  DebugOnly<nsresult> rv =
+    mOpenDBRequest->GetErrorCode(&errorCode);
+  NS_ASSERTION(NS_SUCCEEDED(rv), "This shouldn't be failing at this point!");
+  if (!errorCode) {
+    mOpenDBRequest->SetError(mResultCode);
+  }
+
+  bool dummy;
+  mOpenDBRequest->DispatchEvent(event, &dummy);
+}
+
+NS_IMPL_ISUPPORTS_INHERITED0(SetVersionHelper, AsyncConnectionHelper);
+
+nsresult
+SetVersionHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
+{
+  NS_ASSERTION(aConnection, "Passing a null connection!");
+
+  nsCOMPtr<mozIStorageStatement> stmt;
+  nsresult rv = aConnection->CreateStatement(NS_LITERAL_CSTRING(
+    "UPDATE database "
+    "SET version = :version"
+  ), getter_AddRefs(stmt));
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("version"),
+                             mRequestedVersion);
+  NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
+
+  if (NS_FAILED(stmt->Execute())) {
+    return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
+  }
+
+  return NS_OK;
+}
+
+nsresult
+SetVersionHelper::GetSuccessResult(JSContext* aCx,
+                                   jsval* aVal)
+{
+  DatabaseInfo* info;
+  if (!DatabaseInfo::Get(mDatabase->Id(), &info)) {
+    NS_ERROR("This should never fail!");
+    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
+  }
+  info->version = mRequestedVersion;
+
+  NS_ASSERTION(mTransaction, "Better have a transaction!");
+
+  mOpenRequest->SetTransaction(mTransaction);
+
+  return WrapNative(aCx, NS_ISUPPORTS_CAST(nsIDOMEventTarget*, mDatabase),
+                    aVal);
+}
+
+already_AddRefed<nsDOMEvent>
+SetVersionHelper::CreateSuccessEvent()
+{
+  NS_ASSERTION(mCurrentVersion < mRequestedVersion, "Huh?");
+
+  return IDBVersionChangeEvent::CreateUpgradeNeeded(mCurrentVersion,
+                                                    mRequestedVersion);
+}
+
+nsresult
+SetVersionHelper::NotifyTransactionComplete(IDBTransaction* aTransaction)
+{
+  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
+  NS_ASSERTION(aTransaction, "This is unexpected.");
+  NS_ASSERTION(mOpenRequest, "Why don't we have a request?");
+
+  // If we hit an error, the OpenDatabaseHelper needs to get that error too.
+  nsresult rv = GetResultCode();
+  if (NS_FAILED(rv)) {
+    mOpenHelper->SetError(rv);
+  }
+
+  // If the transaction was aborted, we should throw an error message.
+  if (aTransaction->IsAborted()) {
+    mOpenHelper->SetError(NS_ERROR_DOM_INDEXEDDB_ABORT_ERR);
+  }
+
+  mOpenRequest->SetTransaction(nsnull);
+
+  rv = mOpenHelper->NotifySetVersionFinished();
+  mOpenHelper = nsnull;
+
+  return rv;
+}
new file mode 100644
--- /dev/null
+++ b/dom/indexedDB/OpenDatabaseHelper.h
@@ -0,0 +1,129 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Indexed Database.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Ben Turner <bent.mozilla@gmail.com>
+ *   Kyle Huey <me@kylehuey.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * 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 ***** */
+
+#ifndef mozilla_dom_indexeddb_opendatabasehelper_h__
+#define mozilla_dom_indexeddb_opendatabasehelper_h__
+
+#include "AsyncConnectionHelper.h"
+#include "DatabaseInfo.h"
+#include "IDBDatabase.h"
+#include "IDBRequest.h"
+
+#include "nsIRunnable.h"
+
+class mozIStorageConnection;
+
+BEGIN_INDEXEDDB_NAMESPACE
+
+class OpenDatabaseHelper : public HelperBase
+{
+public:
+  OpenDatabaseHelper(IDBOpenDBRequest* aRequest,
+                     const nsAString& aName,
+                     const nsACString& aASCIIOrigin,
+                     PRUint64 aRequestedVersion)
+    : HelperBase(aRequest), mOpenDBRequest(aRequest), mName(aName),
+      mASCIIOrigin(aASCIIOrigin), mRequestedVersion(aRequestedVersion),
+      mCurrentVersion(0), mDataVersion(DB_SCHEMA_VERSION), mDatabaseId(0),
+      mLastObjectStoreId(0), mLastIndexId(0), mState(eCreated),
+      mResultCode(NS_OK)
+  { }
+
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIRUNNABLE
+
+  nsresult Dispatch(nsIEventTarget* aDatabaseThread);
+  nsresult RunImmediately();
+
+  void SetError(nsresult rv)
+  {
+    NS_ASSERTION(NS_FAILED(rv), "Why are you telling me?");
+    mResultCode = rv;
+  }
+
+  nsresult GetResultCode()
+  {
+    return mResultCode;
+  }
+
+  nsresult NotifySetVersionFinished();
+
+protected:
+  // Methods only called on the main thread
+  nsresult EnsureSuccessResult();
+  nsresult StartSetVersion();
+  nsresult GetSuccessResult(JSContext* aCx,
+                          jsval* aVal);
+  void DispatchSuccessEvent();
+  void DispatchErrorEvent();
+
+  // Methods only called on the DB thread
+  nsresult DoDatabaseWork();
+
+private:
+  // In-params.
+  nsRefPtr<IDBOpenDBRequest> mOpenDBRequest;
+  nsString mName;
+  nsCString mASCIIOrigin;
+  PRUint64 mRequestedVersion;
+
+  // Out-params.
+  nsTArray<nsAutoPtr<ObjectStoreInfo> > mObjectStores;
+  PRUint64 mCurrentVersion;
+  PRUint32 mDataVersion;
+  nsString mDatabaseFilePath;
+  PRUint32 mDatabaseId;
+  PRInt64 mLastObjectStoreId;
+  PRInt64 mLastIndexId;
+  nsRefPtr<IDBDatabase> mDatabase;
+
+  // State variables
+  enum OpenDatabaseState {
+    eCreated = 0, // Not yet dispatched to the DB thread
+    eDBWork, // Waiting to do/doing work on the DB thread
+    eFiringEvents, // Waiting to fire/firing events on the main thread
+    eSetVersionPending, // Waiting on a SetVersionHelper
+    eSetVersionCompleted, // SetVersionHelper is done
+  };
+  OpenDatabaseState mState;
+  nsresult mResultCode;
+};
+
+END_INDEXEDDB_NAMESPACE
+
+#endif // mozilla_dom_indexeddb_opendatabasehelper_h__
--- a/dom/indexedDB/nsIIDBDatabase.idl
+++ b/dom/indexedDB/nsIIDBDatabase.idl
@@ -46,22 +46,22 @@ interface nsIIDBTransaction;
 interface nsIDOMDOMStringList;
 interface nsIDOMEventListener;
 
 /**
  * IDBDatabase interface.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBDatabase
  * for more information.
  */
-[scriptable, uuid(42b38d02-1a29-45f0-99ef-04fd5b441270)]
+[scriptable, uuid(ac14faa5-261c-4a84-9616-a700fd606f83)]
 interface nsIIDBDatabase : nsISupports
 {
   readonly attribute DOMString name;
 
-  readonly attribute DOMString version;
+  readonly attribute unsigned long long version;
 
   readonly attribute nsIDOMDOMStringList objectStoreNames;
 
   /**
    * Optional arguments:
    *   - keyPath (string):
    *       Specifies key path on objects in the objectStore. Defaults to no key
    *       path.
@@ -71,20 +71,16 @@ interface nsIIDBDatabase : nsISupports
   [implicit_jscontext]
   nsIIDBObjectStore
   createObjectStore(in AString name,
                     [optional /* none */] in jsval options);
 
   void
   deleteObjectStore(in AString name);
 
-  [implicit_jscontext]
-  nsIIDBRequest
-  setVersion(in AString version);
-
   [optional_argc, implicit_jscontext]
   nsIIDBTransaction
   transaction(in nsIVariant storeNames, // js array of strings
               [optional /* READ_ONLY */] in unsigned short mode,
               [optional /* 5000ms */] in unsigned long timeout);
 
   void
   close();
--- a/dom/indexedDB/nsIIDBFactory.idl
+++ b/dom/indexedDB/nsIIDBFactory.idl
@@ -36,23 +36,23 @@
  * 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 nsIIDBKeyRange;
-interface nsIIDBRequest;
+interface nsIIDBOpenDBRequest;
 interface nsIVariant;
 
 /**
  * Interface that defines the indexedDB property on a window.  See
  * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBFactory
  * for more information.
  */
-[scriptable, uuid(137d17a5-fac5-4788-87b5-bc3806d7cfaf)]
+[scriptable, uuid(4b23254a-ce6d-4442-8c90-9d8744d3c633)]
 interface nsIIDBFactory : nsISupports
 {
   [implicit_jscontext]
-  nsIIDBRequest
-  open(in AString name);
+  nsIIDBOpenDBRequest
+  open(in AString name, in long long version);
 };
rename from dom/indexedDB/nsIIDBVersionChangeRequest.idl
rename to dom/indexedDB/nsIIDBOpenDBRequest.idl
--- a/dom/indexedDB/nsIIDBVersionChangeRequest.idl
+++ b/dom/indexedDB/nsIIDBOpenDBRequest.idl
@@ -38,17 +38,18 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsISupports.idl"
 
 interface nsIDOMEventListener;
 
 /**
- * IDBReqeust interface.  See
- * http://dev.w3.org/2006/webapi/WebSimpleDB/#idl-def-IDBRequest for more
- * information.
+ * IDBOpenDBRequest interface.  See
+ * http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#idl-def-IDBOpenDBRequest
+ * for more information.
  */
-[scriptable, uuid(aeaabb0d-594a-4c58-ac5e-68ef3bff927d)]
-interface nsIIDBVersionChangeRequest : nsISupports
+[scriptable, uuid(91010fbe-1dfb-435d-852e-288d2804c0a7)]
+interface nsIIDBOpenDBRequest : nsISupports
 {
   attribute nsIDOMEventListener onblocked;
+  attribute nsIDOMEventListener onupgradeneeded;
 };
--- a/dom/indexedDB/nsIIDBVersionChangeEvent.idl
+++ b/dom/indexedDB/nsIIDBVersionChangeEvent.idl
@@ -34,13 +34,14 @@
  * 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 "nsIDOMEvent.idl"
 
-[scriptable, uuid(6a232c30-1bc4-4d5b-9ce0-6e7c08934755)]
+[scriptable, uuid(2c5159dc-7d71-4fc6-a3b3-884ed7586456)]
 interface nsIIDBVersionChangeEvent : nsIDOMEvent
 {
-  readonly attribute AString version;
+  readonly attribute unsigned long long oldVersion;
+  readonly attribute unsigned long long newVersion;
 };
--- a/dom/indexedDB/test/bfcache_iframe1.html
+++ b/dom/indexedDB/test/bfcache_iframe1.html
@@ -1,28 +1,27 @@
 <!DOCTYPE html>
 <html>
 <head>
   <script>
-mozIndexedDB.open(parent.location).onsuccess = function(e) {
-  var db = e.target.result;
-  // This should never be called
-  db.onversionchange = function(e) {
-    db.transaction(["mystore"]).objectStore("mystore").put({ hello: "fail" }, 42);
-  }
-  db.setVersion("1.0").onsuccess = function(e) {
-    trans = e.target.transaction;
+  var request = mozIndexedDB.open(parent.location, 1);
+  request.onupgradeneeded = function(e) {
+    var db = e.target.result;
+    // This should never be called
+    db.onversionchange = function(e) {
+      db.transaction(["mystore"]).objectStore("mystore").put({ hello: "fail" }, 42);
+    }
+    var trans = e.target.transaction;
     if (db.objectStoreNames.contains("mystore")) {
       db.deleteObjectStore("mystore");
     }
     var store = db.createObjectStore("mystore");
     store.add({ hello: "world" }, 42);
     trans.oncomplete = function() {
       parent.postMessage("go", "http://mochi.test:8888");
     }
   };
-};
   </script>
 </head>
 <body>
   This is page one.
 </body>
 </html>
--- a/dom/indexedDB/test/bfcache_iframe2.html
+++ b/dom/indexedDB/test/bfcache_iframe2.html
@@ -1,31 +1,29 @@
 <!DOCTYPE html>
 <html>
 <head>
   <script>
-var res = {};
-mozIndexedDB.open(parent.location).onsuccess = function(e) {
-  var db = e.target.result;
-  res.version = db.version;
-  res.storeCount = db.objectStoreNames.length;
-
-  req = db.setVersion("2.0");
-  req.onblocked = function() {
+  var res = {};
+  var request = mozIndexedDB.open(parent.location, 2);
+  request.onblocked = function() {
     res.blockedFired = true;
   }
-  req.onsuccess = function(e) {
-    var trans = req.transaction;
+  request.onupgradeneeded  = function(e) {
+    var db = e.target.result;
+    res.version = db.version;
+    res.storeCount = db.objectStoreNames.length;
+
+    var trans = request.transaction;
     trans.objectStore("mystore").get(42).onsuccess = function(e) {
       res.value = JSON.stringify(e.target.result);
     }
     trans.oncomplete = function() {
       parent.postMessage(JSON.stringify(res), "http://mochi.test:8888");
     }
-  }
-};
+  };
 
   </script>
 </head>
 <body>
   This is page two.
 </body>
 </html>
--- a/dom/indexedDB/test/browser_forgetThisSite.js
+++ b/dom/indexedDB/test/browser_forgetThisSite.js
@@ -28,17 +28,17 @@ function test()
 function test1()
 {
   // Set database version for domain 1
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function () {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
     setFinishedCallback(function(result, exception) {
-      ok(result == "11", "Set version on database in " + testPageURL1);
+      ok(result == 11, "Set version on database in " + testPageURL1);
       ok(!exception, "No exception");
       gBrowser.removeCurrentTab();
 
       executeSoon(test2);
     });
   }, true);
   content.location = testPageURL1;
 }
@@ -46,17 +46,17 @@ function test1()
 function test2()
 {
   // Set database version for domain 2
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function () {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
     setFinishedCallback(function(result, exception) {
-      ok(result == "11", "Set version on database in " + testPageURL2);
+      ok(result == 11, "Set version on database in " + testPageURL2);
       ok(!exception, "No exception");
       gBrowser.removeCurrentTab();
 
       executeSoon(test3);
     });
   }, true);
   content.location = testPageURL2;
 }
@@ -74,17 +74,17 @@ function test3()
 function test4()
 {
   // Get database version for domain 1
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function () {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
     setFinishedCallback(function(result, exception) {
-      ok(result == "11", "Got correct version on database in " + testPageURL3);
+      ok(result == 11, "Got correct version on database in " + testPageURL3);
       ok(!exception, "No exception");
       gBrowser.removeCurrentTab();
 
       executeSoon(test5);
     });
   }, true);
   content.location = testPageURL3;
 }
@@ -92,17 +92,19 @@ function test4()
 function test5()
 {
   // Get database version for domain 2
   gBrowser.selectedTab = gBrowser.addTab();
   gBrowser.selectedBrowser.addEventListener("load", function () {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
 
     setFinishedCallback(function(result, exception) {
-      ok(result == "", "Got correct version on database in " + testPageURL4);
+      // XXXkhuey this isn't really testing anything until we get the default
+      // version behavior implemented ...
+      ok(result == 11, "Got correct version on database in " + testPageURL4);
       ok(!exception, "No exception");
       gBrowser.removeCurrentTab();
 
       executeSoon(finish);
     });
   }, true);
   content.location = testPageURL4;
 }
--- a/dom/indexedDB/test/browser_forgetThisSiteAdd.html
+++ b/dom/indexedDB/test/browser_forgetThisSiteAdd.html
@@ -4,38 +4,28 @@
 -->
 <html>
   <head>
     <title>Indexed Database Test</title>
 
     <script type="text/javascript;version=1.7">
       function testSteps()
       {
-        let request = mozIndexedDB.open("browser_forgetThisSite.js");
+        let request = mozIndexedDB.open("browser_forgetThisSite.js", 11);
         request.onerror = grabEventAndContinueHandler;
-        request.onsuccess = grabEventAndContinueHandler;
+        request.onupgradeneeded = grabEventAndContinueHandler;
         let event = yield;
 
         if (event.type == "error") {
           testException = event.target.errorCode;
         }
         else {
           let db = event.target.result;
 
-          request = db.setVersion("11");
-          request.onerror = grabEventAndContinueHandler;
-          request.onsuccess = grabEventAndContinueHandler;
-          event = yield;
-
-          if (event.type == "error") {
-            testException = event.target.errorCode;
-          }
-          else {
-            testResult = db.version;
-          }
+          testResult = db.version;
 
           event.target.transaction.oncomplete = finishTest;
           yield;
         }
 
         yield;
       }
     </script>
--- a/dom/indexedDB/test/browser_forgetThisSiteGet.html
+++ b/dom/indexedDB/test/browser_forgetThisSiteGet.html
@@ -4,17 +4,17 @@
 -->
 <html>
   <head>
     <title>Indexed Database Test</title>
 
     <script type="text/javascript;version=1.7">
       function testSteps()
       {
-        let request = mozIndexedDB.open("browser_forgetThisSite.js");
+        let request = mozIndexedDB.open("browser_forgetThisSite.js", 11);
         request.onerror = grabEventAndContinueHandler;
         request.onsuccess = grabEventAndContinueHandler;
         let event = yield;
 
         if (event.type == "error") {
           testException = event.target.errorCode;
         }
         else {
--- a/dom/indexedDB/test/browser_permissionsPrompt.html
+++ b/dom/indexedDB/test/browser_permissionsPrompt.html
@@ -7,17 +7,17 @@
     <title>Indexed Database Test</title>
 
     <script type="text/javascript;version=1.7">
       function testSteps()
       {
         const name = window.location.pathname;
         const description = "My Test Database";
 
-        let request = mozIndexedDB.open(name, description);
+        let request = mozIndexedDB.open(name, 1, description);
         request.onerror = grabEventAndContinueHandler;
         request.onsuccess = grabEventAndContinueHandler;
         let event = yield;
 
         if (event.type == "success") {
           testResult = event.target.result;
         }
         else {
--- a/dom/indexedDB/test/browser_quotaPrompt.html
+++ b/dom/indexedDB/test/browser_quotaPrompt.html
@@ -5,16 +5,17 @@
 <html>
   <head>
     <title>Indexed Database Test</title>
 
     <script type="text/javascript;version=1.7">
       const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
 
       let db;
+      let version = window.location.href.charAt(window.location.href.length - 1);
 
       function onAddMore() {
         let transaction = db.transaction("foo", READ_WRITE);
 
         transaction.oncomplete = function(event) {
           setTimeout(testFinishedCallback, 0, "complete");
         }
         transaction.onabort = function(event) {
@@ -31,47 +32,45 @@
           objectStore.add(obj).onerror = errorHandler;
         }
       }
 
       function onDone() {
         window.removeEventListener("indexedDB-addMore", onAddMore, true);
         window.removeEventListener("indexedDB-done", onDone, true);
 
-        let request = db.setVersion("2");
+        let request = mozIndexedDB.open(window.location.pathname, version++);
         request.onerror = errorHandler;
-        request.onsuccess = function(event) {
+        request.onupgradeneeded = function(event) {
           db.deleteObjectStore("foo");
+          db.onversionchange = function () { db.close(); };
           request.transaction.oncomplete = function(event) {
             testResult = "finished";
             testException = undefined;
             finishTest();
           }
         }
       }
 
       function testSteps()
       {
         const name = window.location.pathname;
         const description = "My Test Database";
 
         window.addEventListener("indexedDB-addMore", onAddMore, true);
         window.addEventListener("indexedDB-done", onDone, true);
 
-        let request = mozIndexedDB.open(name, description);
+        let request = mozIndexedDB.open(name, version++, description);
         request.onerror = errorHandler;
-        request.onsuccess = grabEventAndContinueHandler;
+        request.onupgradeneeded = grabEventAndContinueHandler;
         let event = yield;
 
         db = event.target.result;
 
-        request = db.setVersion("1");
-        request.onerror = errorHandler;
-        request.onsuccess = grabEventAndContinueHandler;
-        event = yield;
+        db.onversionchange = function () { db.close(); };
 
         db.createObjectStore("foo", { autoIncrement: true });
 
         setTimeout(testFinishedCallback, 0, "ready");
         yield;
       }
     </script>
 
--- a/dom/indexedDB/test/browser_quotaPromptAllow.js
+++ b/dom/indexedDB/test/browser_quotaPromptAllow.js
@@ -66,17 +66,17 @@ function test1()
     });
     registerPopupEventHandler("popuphidden", function () {
       ok(true, "prompt hidden");
     });
 
   }, true);
 
   info("loading test page: " + testPageURL);
-  content.location = testPageURL;
+  content.location = testPageURL + "?v=1";
 }
 
 function test2()
 {
   gBrowser.selectedTab = gBrowser.addTab();
 
   gBrowser.selectedBrowser.addEventListener("load", function () {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
@@ -131,10 +131,10 @@ function test2()
     });
     registerPopupEventHandler("popuphidden", function () {
       ok(false, "Shouldn't show a popup this time");
     });
 
   }, true);
 
   info("loading test page: " + testPageURL);
-  content.location = testPageURL;
+  content.location = testPageURL + "?v=3";
 }
--- a/dom/indexedDB/test/browser_quotaPromptDeny.js
+++ b/dom/indexedDB/test/browser_quotaPromptDeny.js
@@ -72,17 +72,17 @@ function test1()
     });
     registerPopupEventHandler("popuphidden", function () {
       ok(true, "prompt hidden");
     });
 
   }, true);
 
   info("loading test page: " + testPageURL);
-  content.location = testPageURL;
+  content.location = testPageURL + "?v=5";
 }
 
 function test2()
 {
   gBrowser.selectedTab = gBrowser.addTab();
 
   gBrowser.selectedBrowser.addEventListener("load", function () {
     gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
@@ -140,10 +140,10 @@ function test2()
     });
     registerPopupEventHandler("popuphidden", function () {
       ok(false, "Shouldn't show a popup this time");
     });
 
   }, true);
 
   info("loading test page: " + testPageURL);
-  content.location = testPageURL;
+  content.location = testPageURL + "?v=7";
 }
--- a/dom/indexedDB/test/error_events_abort_transactions_iframe.html
+++ b/dom/indexedDB/test/error_events_abort_transactions_iframe.html
@@ -51,37 +51,30 @@
       netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
       let uri = window.parent.SpecialPowers.getDocumentURIObject(window.document);
       Components.classes["@mozilla.org/permissionmanager;1"]
                 .getService(Components.interfaces.nsIPermissionManager)
                 .add(uri, "indexedDB",
                      Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
 
-      let request = mozIndexedDB.open(window.location.pathname);
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      let request = mozIndexedDB.open(window.location.pathname, 1);
+      request.onsuccess = unexpectedSuccessHandler;
+      request.onerror = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      is(db.version, "", "Correct version");
+      is(db.version, 1, "Correct version");
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
 
-      let request = db.setVersion("1");
-      request.onsuccess = grabEventAndContinueHandler;
-      request.onerror = errorHandler;
-      event = yield;
-
       event.target.transaction.oncomplete = unexpectedSuccessHandler;
       event.target.transaction.onabort = grabEventAndContinueHandler;
 
-      is(db.version, "1", "Correct version");
-      is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
-
       let objectStore = db.createObjectStore("foo");
 
       is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
       ok(db.objectStoreNames.contains("foo"), "Has correct objectStore");
 
       request = objectStore.add({}, 1);
       request.onsuccess = grabEventAndContinueHandler;
       request.onerror = errorHandler;
@@ -90,23 +83,31 @@
       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");
-      is(db.version, "", "Correct version");
+      //todo(db.version, 1, "Correct version");
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
 
-      request = db.setVersion("1");
-      request.onsuccess = grabEventAndContinueHandler;
+      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;
-      event = yield;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      let event = yield;
+
+      let db = event.target.result;
 
       event.target.transaction.oncomplete = grabEventAndContinueHandler;
       event.target.transaction.onabort = unexpectedSuccessHandler;
 
       is(db.version, "1", "Correct version");
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
 
       let objectStore = db.createObjectStore("foo");
--- a/dom/indexedDB/test/event_propagation_iframe.html
+++ b/dom/indexedDB/test/event_propagation_iframe.html
@@ -90,30 +90,25 @@
       netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
       let uri = window.parent.SpecialPowers.getDocumentURIObject(window.document);
       Components.classes["@mozilla.org/permissionmanager;1"]
                 .getService(Components.interfaces.nsIPermissionManager)
                 .add(uri, "indexedDB",
                      Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
 
-      let request = mozIndexedDB.open(window.location.pathname);
+      let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = errorEventCounter;
       db.addEventListener("error", errorEventCounter, true);
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       event.target.transaction.oncomplete = grabEventAndContinueHandler;
 
       db.createObjectStore("foo", { autoIncrement: true });
       yield;
 
       let transaction = db.transaction("foo", IDBTransaction.READ_WRITE);
       transaction.addEventListener("error", errorEventCounter, false);
       transaction.addEventListener("error", errorEventCounter, true);
--- a/dom/indexedDB/test/exceptions_in_success_events_iframe.html
+++ b/dom/indexedDB/test/exceptions_in_success_events_iframe.html
@@ -54,52 +54,67 @@
       netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
 
       let uri = SpecialPowers.getDocumentURIObject(window.document);
       Components.classes["@mozilla.org/permissionmanager;1"]
                 .getService(Components.interfaces.nsIPermissionManager)
                 .add(uri, "indexedDB",
                      Components.interfaces.nsIPermissionManager.ALLOW_ACTION);
 
-      let request = mozIndexedDB.open(window.location.pathname);
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      let request = mozIndexedDB.open(window.location.pathname, 1);
+      request.onerror = grabEventAndContinueHandler;
+      request.onsuccess = errorHandler;
+      request.onupgradeneeded = function () {
+        throw "STOP";
+      };
+
+      let event = yield;
+
+      is(event.type, "error",
+         "Throwing during an upgradeneeded event should fire an error.");
+      ok(event.target.result instanceof IDBDatabase, "Should have a DB");
+      event.target.result.close();
+
+      let request = mozIndexedDB.open(window.location.pathname, 1);
+      request.onerror = grabEventAndContinueHandler;
+      request.onblocked = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      let openrequest = request;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = function(event) {
         event.preventDefault();
       };
 
-      is(db.version, "", "Correct version");
-      is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
-
-      db.setVersion("1").onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       event.target.transaction.oncomplete = unexpectedSuccessHandler;
       event.target.transaction.onabort = grabEventAndContinueHandler;
 
-      is(db.version, "1", "Correct version");
+      is(db.version, 1, "Correct version");
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
 
       let objectStore = db.createObjectStore("foo");
 
       is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
       ok(db.objectStoreNames.contains("foo"), "Has correct objectStore");
 
       request = objectStore.add({}, 1);
       request.onsuccess = function(event) {
         throw "foo";
       };
 
       event = yield;
 
       is(event.type, "abort", "Got transaction abort event");
 
+      event = yield;
+
+      is(event.type, "error", "Got IDBOpenDBRequest error event");
+      is(event.target, openrequest, "Right event target");
+
       finishTest();
       yield;
     }
   </script>
 
 </head>
 
 <body onload="testGenerator.next();"></body>
--- a/dom/indexedDB/test/leaving_page_iframe.html
+++ b/dom/indexedDB/test/leaving_page_iframe.html
@@ -1,25 +1,23 @@
 <!DOCTYPE html>
 <html>
 <head>
   <script>
 var db;
 function startDBWork() {
-  mozIndexedDB.open(parent.location).onsuccess = function(e) {
+  mozIndexedDB.open(parent.location, 1).onupgradeneeded = function(e) {
     db = e.target.result;
-    db.setVersion("1.0").onsuccess = function(e) {
-      var trans = e.target.transaction;
-      if (db.objectStoreNames.contains("mystore")) {
-        db.deleteObjectStore("mystore");
-      }
-      var store = db.createObjectStore("mystore");
-      store.add({ hello: "world" }, 42);
-      trans.oncomplete = madeMod;
-    };
+    var trans = e.target.transaction;
+    if (db.objectStoreNames.contains("mystore")) {
+      db.deleteObjectStore("mystore");
+    }
+    var store = db.createObjectStore("mystore");
+    store.add({ hello: "world" }, 42);
+    trans.oncomplete = madeMod;
   };
 }
 
 function madeMod() {
   var trans = db.transaction(["mystore"], IDBTransaction.READ_WRITE);
   var store = trans.
               objectStore("mystore");
   trans.oncomplete = function() {
--- a/dom/indexedDB/test/test_add_twice_failure.html
+++ b/dom/indexedDB/test/test_add_twice_failure.html
@@ -10,28 +10,23 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const name = window.location.pathname;
       const description = "My Test Database";
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = request.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield;
-
       ok(event.target === request, "Good event target");
 
       let objectStore = db.createObjectStore("foo", { keyPath: "" });
       let key = 10;
 
       request = objectStore.add({}, key);
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
--- a/dom/indexedDB/test/test_autoIncrement_indexes.html
+++ b/dom/indexedDB/test/test_autoIncrement_indexes.html
@@ -7,27 +7,24 @@
   <title>Indexed Database Property Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
-      let request = mozIndexedDB.open(window.location.pathname);
+      let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = request.result;
       db.onerror = errorHandler;
 
-      db.setVersion("1").onsuccess = grabEventAndContinueHandler;
-      let event = yield;
-
       let objectStore = db.createObjectStore("foo", { keyPath: "id",
                                                       autoIncrement: true });
       objectStore.createIndex("first","first");
       objectStore.createIndex("second","second");
       objectStore.createIndex("third","third");
 
       let data = { first: "foo", second: "foo", third: "foo" };
 
--- a/dom/indexedDB/test/test_bad_keypath.html
+++ b/dom/indexedDB/test/test_bad_keypath.html
@@ -10,37 +10,33 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const name = window.location.pathname;
       const description = "My Test Database";
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = request.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore("foo", { keyPath: "keyPath" });
 
       request = objectStore.add({keyPath:"foo"});
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       try {
         request = objectStore.add({});
+        ok(false, "Shouldn't get here!");
       }
       catch (e) {
         is(e.code, IDBDatabaseException.DATA_ERR, "Good error");
       }
 
       finishTest();
       yield;
     }
--- a/dom/indexedDB/test/test_bfcache.html
+++ b/dom/indexedDB/test/test_bfcache.html
@@ -50,17 +50,17 @@
       window.onmessage = grabEventAndContinueHandler;
 
       iframe.src = "bfcache_iframe1.html";
       var event = yield;
       is(event.data, "go", "set up database successfully");
 
       iframe.src = "bfcache_iframe2.html";
       res = JSON.parse((yield).data);
-      is(res.version, "1.0", "version was set correctly");
+      is(res.version, 2, "version was set correctly");
       is(res.storeCount, 1, "correct set of stores");
       ok(!("blockedFired" in res), "blocked shouldn't fire");
       is(res.value, JSON.stringify({ hello: "world" }),
          "correct value found in store");
 
       setCachePref(false);
       finishTest();
       yield;
--- a/dom/indexedDB/test/test_clear.html
+++ b/dom/indexedDB/test/test_clear.html
@@ -13,28 +13,23 @@
     function testSteps()
     {
       const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
 
       const name = window.location.pathname;
       const description = "My Test Database";
       const entryCount = 1000;
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = request.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield;
-
       event.target.transaction.oncomplete = continueToNextStep;
 
       let objectStore = db.createObjectStore("foo", { autoIncrement: true });
 
       let firstKey;
       for (let i = 0; i < entryCount; i++) {
         request = objectStore.add({});
         request.onerror = errorHandler;
--- a/dom/indexedDB/test/test_create_index.html
+++ b/dom/indexedDB/test/test_create_index.html
@@ -22,27 +22,22 @@
         { name: "b", options: { keyPath: "id", autoIncrement: false } },
       ];
       const indexInfo = [
         { name: "1", keyPath: "unique_value", options: { unique: true } },
         { name: "2", keyPath: "value", options: { unique: false } },
         { name: "3", keyPath: "value", options: { unique: false } },
       ];
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       for (let i = 0; i < objectStoreInfo.length; i++) {
         let info = objectStoreInfo[i];
         let objectStore = info.hasOwnProperty("options") ?
                           db.createObjectStore(info.name, info.options) :
                           db.createObjectStore(info.name);
 
         // Test basic failure conditions.
         try {
--- a/dom/indexedDB/test/test_create_index_with_integer_keys.html
+++ b/dom/indexedDB/test/test_create_index_with_integer_keys.html
@@ -10,49 +10,52 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const data = { id: new Date().getTime(),
                      num: parseInt(Math.random() * 1000) };
 
-      let request = mozIndexedDB.open(window.location.pathname);
+      let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = errorHandler;
 
-      db.setVersion("1").onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       event.target.transaction.oncomplete = continueToNextStep;
 
       // Make object store, add data.
       let objectStore = db.createObjectStore("foo", { keyPath: "id" });
       objectStore.add(data);
       yield;
+      db.close();
 
-      db.setVersion("2").onsuccess = grabEventAndContinueHandler;
-      event = yield;
+      let request = mozIndexedDB.open(window.location.pathname, 2);
+      request.onerror = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      let event = yield;
+
+      let db2 = event.target.result;
+      db2.onerror = errorHandler;
 
       event.target.transaction.oncomplete = continueToNextStep;
 
       // Create index.
       event.target.transaction.objectStore("foo").createIndex("foo", "num");
       yield;
 
       // Make sure our object made it into the index.
       let seenCount = 0;
 
 
-      db.transaction("foo").objectStore("foo").index("foo")
-        .openKeyCursor().onsuccess = function(event) {
+      db2.transaction("foo").objectStore("foo").index("foo")
+         .openKeyCursor().onsuccess = function(event) {
         let cursor = event.target.result;
         if (cursor) {
           is(cursor.key, data.num, "Good key");
           is(cursor.primaryKey, data.id, "Good value");
           seenCount++;
           cursor.continue();
         }
         else {
--- a/dom/indexedDB/test/test_create_objectStore.html
+++ b/dom/indexedDB/test/test_create_objectStore.html
@@ -26,35 +26,26 @@
         { name: "6" },
         { name: "7", options: null },
         { name: "8", options: { autoIncrement: true } },
         { name: "9", options: { autoIncrement: false } },
         { name: "10", options: { keyPath: "foo", autoIncrement: false } },
         { name: "11", options: { keyPath: "foo", autoIncrement: true } }
       ];
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
-      ok(event.target.source === mozIndexedDB,
-         "event.target.source is correct");
       let db = event.target.result;
 
       let count = db.objectStoreNames.length;
       is(count, 0, "correct objectStoreNames length");
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      ok(event.target.source === db, "event.target.source is correct");
-
       try {
         db.createObjectStore(null);
         ok(false, "createObjectStore with null name should throw");
       }
       catch(e) {
         ok(true, "createObjectStore with null name should throw");
       }
 
--- a/dom/indexedDB/test/test_cursor_mutation.html
+++ b/dom/indexedDB/test/test_cursor_mutation.html
@@ -24,26 +24,22 @@
 
         // This one will be added.
         { ss: "237-23-7737", name: "Pat" }
       ];
 
       // Post-add and post-remove data ordered by name.
       const objectStoreDataNameSort = [ 1, 4, 5, 2, 3 ];
 
-      let request = mozIndexedDB.open(window.location.pathname);
+      let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
-
-      db.setVersion("1").onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       event.target.transaction.oncomplete = continueToNextStep;
 
       let objectStore = db.createObjectStore("foo", { keyPath: "ss" });
       objectStore.createIndex("name", "name", { unique: true });
 
       for (let i = 0; i < objectStoreData.length - 1; i++) {
         objectStore.add(objectStoreData[i]);
       }
--- a/dom/indexedDB/test/test_cursor_update_updates_indexes.html
+++ b/dom/indexedDB/test/test_cursor_update_updates_indexes.html
@@ -25,33 +25,28 @@
         { name: "2", options: { keyPath: "foo" },
           entry: { foo: 1, data: START_DATA } },
         { name: "3", options: { keyPath: "", autoIncrement: true },
           entry: { data: START_DATA } },
         { name: "4", options: { keyPath: "foo", autoIncrement: true },
           entry: { data: START_DATA } },
       ];
 
-      let request = mozIndexedDB.open(name, description);
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield;
-
-      let db = event.target.result;
-
       for (let i = 0; i < objectStoreInfo.length; i++) {
         // Create our object stores.
         let info = objectStoreInfo[i];
 
         ok(true, "1");
-        request = db.setVersion("1");
+        request = mozIndexedDB.open(name, i + 1, description);
         request.onerror = errorHandler;
-        request.onsuccess = grabEventAndContinueHandler;
+        request.onupgradeneeded = grabEventAndContinueHandler;
         event = yield;
 
+        let db = event.target.result;
+
         ok(true, "2");
         let objectStore = info.hasOwnProperty("options") ?
                           db.createObjectStore(info.name, info.options) :
                           db.createObjectStore(info.name);
 
         // Create the indexes on 'data' on the object store.
         let index = objectStore.createIndex("data_index", "data",
                                             { unique: false });
@@ -94,16 +89,17 @@
         request = uniqueIndex.get(END_DATA);
         request.onerror = errorHandler;
         request.onsuccess = grabEventAndContinueHandler;
         event = yield;
 
         ok(true, "7");
         SimpleTest.ok(obj.data, event.target.result.data,
                       "Unique index was properly updated.");
+        db.close();
       }
 
       finishTest();
       yield;
     }
   </script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 </head>
--- a/dom/indexedDB/test/test_cursors.html
+++ b/dom/indexedDB/test/test_cursors.html
@@ -14,28 +14,23 @@
     {
       const name = window.location.pathname;
       const description = "My Test Database";
       const keys = [1, -1, 0, 10, 2000, "q", "z", "two", "b", "a"];
       const sortedKeys = [-1, 0, 1, 10, 2000, "a", "b", "q", "two", "z"];
 
       is(keys.length, sortedKeys.length, "Good key setup");
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield;
-
       let objectStore = db.createObjectStore("autoIncrement",
                                              { autoIncrement: true });
 
       request = objectStore.openCursor();
       request.onerror = errorHandler;
       request.onsuccess = function (event) {
         ok(!event.target.result, "No results");
         testGenerator.next();
--- a/dom/indexedDB/test/test_event_source.html
+++ b/dom/indexedDB/test/test_event_source.html
@@ -11,32 +11,24 @@
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const name = window.location.pathname;
       const description = "My Test Database";
       const objectStoreName = "Objects";
 
-      var request = mozIndexedDB.open(name, description);
+      var request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       var event = yield;
 
-      ok(event.target.source === mozIndexedDB, "correct event.target.source");
+      is(event.target.source, null, "correct event.target.source");
 
       var db = event.target.result;
-
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      ok(event.target.source === db, "correct event.target.source");
-
       var objectStore = db.createObjectStore(objectStoreName,
                                              { autoIncrement: true });
       request = objectStore.add({});
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       ok(event.target.source === objectStore, "correct event.source");
--- a/dom/indexedDB/test/test_getAll.html
+++ b/dom/indexedDB/test/test_getAll.html
@@ -12,28 +12,23 @@
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const name = window.location.pathname;
       const description = "My Test Database";
 
       const values = [ "a", "1", 1, "foo", 300, true, false, 4.5, null ];
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore("foo", { autoIncrement: true });
 
       request = objectStore.getAll();
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       is(event.target.result instanceof Array, true, "Got an array object");
--- a/dom/indexedDB/test/test_global_data.html
+++ b/dom/indexedDB/test/test_global_data.html
@@ -12,36 +12,31 @@
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const name = window.location.pathname;
       const description = "My Test Database";
       const objectStore =  { name: "Objects",
                              options: { keyPath: "id", autoIncrement: true } };
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db1 = event.target.result;
 
-      request = db1.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       is(db1.objectStoreNames.length, 0, "No objectStores in db1");
 
       db1.createObjectStore(objectStore.name, objectStore.options);
 
       continueToNextStep();
       yield;
 
-      request = mozIndexedDB.open(name, description);
+      request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       let db2 = event.target.result;
 
       ok(db1 !== db2, "Databases are not the same object");
 
--- a/dom/indexedDB/test/test_index_getAll.html
+++ b/dom/indexedDB/test/test_index_getAll.html
@@ -52,28 +52,23 @@
         { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
         { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
         { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
         { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
         { key: "237-23-7737", value: { name: "Pat", height: 65 } },
         { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
       ];
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore(objectStoreName);
 
       // First, add all our data to the object store.
       let addedData = 0;
       for (let i in objectStoreData) {
         request = objectStore.add(objectStoreData[i].value,
                                   objectStoreData[i].key);
         request.onerror = errorHandler;
--- a/dom/indexedDB/test/test_index_getAllObjects.html
+++ b/dom/indexedDB/test/test_index_getAllObjects.html
@@ -52,28 +52,23 @@
         { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
         { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
         { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
         { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
         { key: "237-23-7737", value: { name: "Pat", height: 65 } },
         { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
       ];
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore(objectStoreName, {});
 
       // First, add all our data to the object store.
       let addedData = 0;
       for (let i in objectStoreData) {
         request = objectStore.add(objectStoreData[i].value,
                                   objectStoreData[i].key);
         request.onerror = errorHandler;
--- a/dom/indexedDB/test/test_index_object_cursors.html
+++ b/dom/indexedDB/test/test_index_object_cursors.html
@@ -24,28 +24,25 @@
         { name: "height", keyPath: "height", options: { } }
       ];
 
       const data = [
         { ss: "237-23-7732", name: "Ann", height: 60 },
         { ss: "237-23-7733", name: "Bob", height: 65 }
       ];
 
-      let request = mozIndexedDB.open(window.location.pathname);
+      let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = errorHandler;
 
-      db.setVersion("1").onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      event.target.result.oncomplete = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
 
       for (let objectStoreIndex in objectStoreData) {
         const objectStoreInfo = objectStoreData[objectStoreIndex];
         let objectStore = db.createObjectStore(objectStoreInfo.name,
                                                objectStoreInfo.options);
         for (let indexIndex in indexData) {
           const indexInfo = indexData[indexIndex];
           let index = objectStore.createIndex(indexInfo.name,
--- a/dom/indexedDB/test/test_indexes.html
+++ b/dom/indexedDB/test/test_indexes.html
@@ -63,28 +63,23 @@
         { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
         { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
         { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
         { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
         { key: "237-23-7737", value: { name: "Pat", height: 65 } },
         { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
       ];
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore(objectStoreName, { keyPath: "" });
 
       // First, add all our data to the object store.
       let addedData = 0;
       for (let i in objectStoreData) {
         request = objectStore.add(objectStoreData[i].value,
                                   objectStoreData[i].key);
         request.onerror = errorHandler;
--- a/dom/indexedDB/test/test_indexes_bad_values.html
+++ b/dom/indexedDB/test/test_indexes_bad_values.html
@@ -43,28 +43,23 @@
       const objectStoreDataWeightSort = [
         { key: "237-23-7733", value: { name: "Ann", height: 52, weight: 110 } },
         { key: "237-23-7732", value: { name: "Bob", height: 60, weight: 120 } },
         { key: "237-23-7735", value: { name: "Sue", height: 58, weight: 130 } },
         { key: "237-23-7736", value: { name: "Joe", height: 65, weight: 150 } },
         { key: "237-23-7734", value: { name: "Ron", height: 73, weight: 180 } }
       ];
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore(objectStoreName, { } );
 
       let addedData = 0;
       for (let i in objectStoreData) {
         request = objectStore.add(objectStoreData[i].value,
                                   objectStoreData[i].key);
         request.onerror = errorHandler;
         request.onsuccess = function(event) {
--- a/dom/indexedDB/test/test_key_requirements.html
+++ b/dom/indexedDB/test/test_key_requirements.html
@@ -10,31 +10,26 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const name = window.location.pathname;
       const description = "My Test Database";
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.addEventListener("error", function(event) {
         event.preventDefault();
       }, false);
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield;
-
       let objectStore = db.createObjectStore("foo", { autoIncrement: true });
 
       request = objectStore.add({});
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
       let key1 = event.target.result;
--- a/dom/indexedDB/test/test_leaving_page.html
+++ b/dom/indexedDB/test/test_leaving_page.html
@@ -25,17 +25,17 @@
       iframe.onload = continueToNextStep;
       yield;
       is(iframe.contentWindow.location.href, $("a").href,
          "should navigate to iframe page");
       yield;
       is(iframe.contentWindow.location.href, "about:blank",
          "should nagivate to about:blank");
          
-      let request = mozIndexedDB.open(location);
+      let request = mozIndexedDB.open(location, 1);
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.transaction(["mystore"]).objectStore("mystore").get(42).onsuccess =
         grabEventAndContinueHandler;
       event = yield;
       is(event.target.result.hello, "world", "second modification rolled back");
--- a/dom/indexedDB/test/test_objectCursors.html
+++ b/dom/indexedDB/test/test_objectCursors.html
@@ -20,28 +20,24 @@
         { name: "b", autoIncrement: true }
       ];
 
       const indexes = [
         { name: "a", options: { } },
         { name: "b", options: { unique: true } }
       ];
 
-      let request = mozIndexedDB.open(name, description);
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield;
+      var j = 0;
+      for (let i in objectStores) {
+        let request = mozIndexedDB.open(name, ++j, description);
+        request.onerror = errorHandler;
+        request.onupgradeneeded = grabEventAndContinueHandler;
+        let event = yield;
 
-      let db = event.target.result;
-
-      for (let i in objectStores) {
-        request = db.setVersion("1");
-        request.onerror = errorHandler;
-        request.onsuccess = grabEventAndContinueHandler;
-        let event = yield;
+        let db = event.target.result;
 
         let objectStore =
           db.createObjectStore(objectStores[i].name,
                                { keyPath: "id",
                                  autoIncrement: objectStores[i].autoIncrement });
 
         for (let j in indexes) {
           objectStore.createIndex(indexes[j].name, "name", indexes[j].options);
@@ -53,22 +49,28 @@
         }
 
         request = objectStore.add(data);
         request.onerror = errorHandler;
         request.onsuccess = grabEventAndContinueHandler;
         event = yield;
 
         ok(event.target.result == 1 || event.target.result == 2, "Good id");
+        db.close();
       }
 
       SimpleTest.executeSoon(function() { testGenerator.next(); });
       yield;
 
-      let objectStore = event.target.result;
+      let request = mozIndexedDB.open(name, j, description);
+      request.onerror = errorHandler;
+      request.onsuccess = grabEventAndContinueHandler;
+      let event = yield;
+
+      let db = event.target.result;
 
       for (let i in objectStores) {
         for (let j in indexes) {
           let objectStore = db.transaction(objectStores[i].name)
                               .objectStore(objectStores[i].name);
           let index = objectStore.index(indexes[j].name);
 
           request = index.openCursor();
--- a/dom/indexedDB/test/test_objectStore_inline_autoincrement_key_added_on_put.html
+++ b/dom/indexedDB/test/test_objectStore_inline_autoincrement_key_added_on_put.html
@@ -13,35 +13,30 @@
 
 function testSteps()
 {
   const IDBObjectStore = Components.interfaces.nsIIDBObjectStore;
   const IDBDatabaseException = Components.interfaces.nsIIDBDatabaseException;
   const name = window.location.pathname;
   const description = "My Test Database";
 
-  var request = mozIndexedDB.open(name, description);
+  var request = mozIndexedDB.open(name, 1, description);
   request.onerror = errorHandler;
-  request.onsuccess = grabEventAndContinueHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
   var event = yield;
 
   var db = event.target.result;
 
   var test = {
     name: "inline key; key generator",
     autoIncrement: true,
     storedObject: {name: "Lincoln"},
     keyName: "id",
   };
 
-  let request = db.setVersion("1");
-  request.onerror = errorHandler;
-  request.onsuccess = grabEventAndContinueHandler;
-  event = yield;
-
   let objectStore = db.createObjectStore(test.name,
                                          { keyPath: test.keyName,
                                            autoIncrement: test.autoIncrement });
 
   request = objectStore.add(test.storedObject);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   event = yield;
--- a/dom/indexedDB/test/test_objectStore_remove_values.html
+++ b/dom/indexedDB/test/test_objectStore_remove_values.html
@@ -13,23 +13,16 @@
 
 function testSteps()
 {
   const IDBObjectStore = Components.interfaces.nsIIDBObjectStore;
   const IDBDatabaseException = Components.interfaces.nsIIDBDatabaseException;
   const name = window.location.pathname;
   const description = "My Test Database";
 
-  var request = mozIndexedDB.open(name, description);
-  request.onerror = errorHandler;
-  request.onsuccess = grabEventAndContinueHandler;
-  var event = yield;
-
-  var db = event.target.result;
-
   var data = [
     { name: "inline key; key generator",
       autoIncrement: true,
       storedObject: {name: "Lincoln"},
       keyName: "id",
       keyValue: undefined,
     },
     { name: "inline key; no key generator",
@@ -50,21 +43,22 @@ function testSteps()
       keyName: "",
       keyValue: 1,
     }
   ];
 
   for (let i = 0; i < data.length; i++) {
     let test = data[i];
 
-
-    let request = db.setVersion("1");
+    let request = mozIndexedDB.open(name, i+1, description);
     request.onerror = errorHandler;
-    request.onsuccess = grabEventAndContinueHandler;
-    event = yield;
+    request.onupgradeneeded = grabEventAndContinueHandler;
+    let event = yield;
+
+    let db = event.target.result;
 
     let objectStore = db.createObjectStore(test.name,
                                            { keyPath: test.keyName,
                                              autoIncrement: test.autoIncrement });
 
     request = objectStore.add(test.storedObject, test.keyValue);
     request.onerror = errorHandler;
     request.onsuccess = grabEventAndContinueHandler;
@@ -87,16 +81,17 @@ function testSteps()
 
     // Make sure it was removed.
     request = objectStore.get(id);
     request.onerror = errorHandler;
     request.onsuccess = grabEventAndContinueHandler;
     event = yield;
 
     ok(event.target.result === undefined, "Object was deleted");
+    db.close();
   }
 
   finishTest();
   yield;
 }
 
   </script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
--- a/dom/indexedDB/test/test_object_identity.html
+++ b/dom/indexedDB/test/test_object_identity.html
@@ -7,28 +7,22 @@
   <title>Indexed Database Property Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
-      let request = mozIndexedDB.open(window.location.pathname, "");
+      let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
-
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let transaction = event.target.transaction;
 
       let objectStore1 = db.createObjectStore("foo");
       let objectStore2 = transaction.objectStore("foo");
       ok(objectStore1 === objectStore2, "Got same objectStores");
 
       let index1 = objectStore1.createIndex("bar", "key");
       let index2 = objectStore2.index("bar");
--- a/dom/indexedDB/test/test_odd_result_order.html
+++ b/dom/indexedDB/test/test_odd_result_order.html
@@ -9,35 +9,27 @@
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const data = { key: 5, index: 10 };
 
-      let request = mozIndexedDB.open(window.location.pathname);
+      let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
-      let db;
-      setTimeout(function() {
-        db = request.result;
-        continueToNextStep();
-      }, 0);
-      yield;
+      let db = event.target.result;
 
       ok(db instanceof IDBDatabase, "Got a real database");
 
       db.onerror = errorHandler;
 
-      db.setVersion("1").onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore("foo", { keyPath: "key",
                                                       autoIncrement: true });
       let index = objectStore.createIndex("foo", "index");
 
       event.target.transaction.oncomplete = continueToNextStep;
       yield;
 
       objectStore = db.transaction("foo", IDBTransaction.READ_WRITE)
--- a/dom/indexedDB/test/test_open_empty_db.html
+++ b/dom/indexedDB/test/test_open_empty_db.html
@@ -13,43 +13,43 @@
     function testSteps()
     {
       const name = window.location.pathname;
       const description = "My Test Database";
 
       let request;
 
       try {
-        request = mozIndexedDB.open("", "");
+        request = mozIndexedDB.open("", 1);
         ok(false, "Open with empty name should have thrown!");
       }
       catch(e) {
         is(e instanceof IDBDatabaseException, true, "Got IDBDatabaseException");
         is(e.code, IDBDatabaseException.NON_TRANSIENT_ERR, "Good error code");
         is(request, undefined, "Shouldn't be set to anything");
       }
 
       try {
-        request = mozIndexedDB.open(null, "");
+        request = mozIndexedDB.open(null, 1);
         ok(false, "Open with null name should have thrown!");
       }
       catch(e) {
         is(e instanceof IDBDatabaseException, true, "Got IDBDatabaseException");
         is(e.code, IDBDatabaseException.NON_TRANSIENT_ERR, "Good error code");
         is(request, undefined, "Shouldn't be set to anything");
       }
 
-      request = mozIndexedDB.open(name, description);
+      request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       is(db.name, name, "Bad name");
-      is(db.version, "", "Bad version");
+      is(db.version, 1, "Bad version");
       is(db.objectStoreNames.length, 0, "Bad objectStores list");
 
       is(db.name, request.result.name, "Bad name");
       is(db.version, request.result.version, "Bad version");
       is(db.objectStoreNames.length, request.result.objectStoreNames.length,
          "Bad objectStores list");
 
       finishTest();
--- a/dom/indexedDB/test/test_open_objectStore.html
+++ b/dom/indexedDB/test/test_open_objectStore.html
@@ -12,31 +12,24 @@
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
       const name = window.location.pathname;
       const description = "My Test Database";
       const objectStoreName = "Objects";
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       is(db.objectStoreNames.length, 0, "Bad objectStores list");
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
-      is(db.objectStoreNames.length, 0, "Bad objectStores list");
-
       let objectStore = db.createObjectStore(objectStoreName,
                                              { keyPath: "foo" });
 
       is(db.objectStoreNames.length, 1, "Bad objectStores list");
       is(db.objectStoreNames.item(0), objectStoreName, "Bad name");
 
       continueToNextStep();
       yield;
--- a/dom/indexedDB/test/test_overlapping_transactions.html
+++ b/dom/indexedDB/test/test_overlapping_transactions.html
@@ -13,33 +13,29 @@
     function testSteps()
     {
       const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
 
       const name = window.location.pathname;
       const description = "My Test Database";
       const objectStores = [ "foo", "bar" ];
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = function(event) {
-        event.target.transaction.oncomplete = grabEventAndContinueHandler;
-        for (let i in objectStores) {
-          db.createObjectStore(objectStores[i], { autoIncrement: true });
-        }
-      };
-      yield;
+      event.target.transaction.oncomplete = grabEventAndContinueHandler;
+      for (let i in objectStores) {
+        db.createObjectStore(objectStores[i], { autoIncrement: true });
+      }
+      let event = yield;
 
       is(db.objectStoreNames.length, objectStores.length,
          "Correct objectStoreNames list");
 
       for (let i = 0; i < 50; i++) {
         let stepNumber = 0;
 
         request = db.transaction(["foo"], READ_WRITE)
--- a/dom/indexedDB/test/test_put_get_values.html
+++ b/dom/indexedDB/test/test_put_get_values.html
@@ -14,28 +14,23 @@
     {
       const name = window.location.pathname;
       const description = "My Test Database";
       const objectStoreName = "Objects";
 
       let testString = { key: 0, value: "testString" };
       let testInt = { key: 1, value: 1002 };
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore(objectStoreName,
                                              { autoIncrement: 0 });
 
       request = objectStore.add(testString.value, testString.key);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
         is(event.target.result, testString.key, "Got the right key");
         request = objectStore.get(testString.key);
--- a/dom/indexedDB/test/test_put_get_values_autoIncrement.html
+++ b/dom/indexedDB/test/test_put_get_values_autoIncrement.html
@@ -14,28 +14,23 @@
     {
       const name = window.location.pathname;
       const description = "My Test Database";
       const objectStoreName = "Objects";
 
       let testString = { value: "testString" };
       let testInt = { value: 1002 };
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore(objectStoreName,
                                              { autoIncrement: 1 });
 
       request = objectStore.add(testString.value);
       request.onerror = errorHandler;
       request.onsuccess = function(event) {
         testString.key = event.target.result;
         request = objectStore.get(testString.key);
--- a/dom/indexedDB/test/test_readonly_transactions.html
+++ b/dom/indexedDB/test/test_readonly_transactions.html
@@ -14,29 +14,24 @@
     {
       const READ_ONLY = Components.interfaces.nsIIDBTransaction.READ_ONLY;
       const READ_WRITE = Components.interfaces.nsIIDBTransaction.READ_WRITE;
 
       const name = window.location.pathname;
       const description = "My Test Database";
       const osName = "foo";
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       db.createObjectStore(osName, { autoIncrement: "true" });
 
       let key1, key2;
 
       request = db.transaction([osName], READ_WRITE)
                   .objectStore(osName)
                   .add({});
       request.onerror = errorHandler;
--- a/dom/indexedDB/test/test_remove_index.html
+++ b/dom/indexedDB/test/test_remove_index.html
@@ -13,29 +13,24 @@
     function testSteps()
     {
       const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
 
       const name = window.location.pathname;
       const description = "My Test Database";
       const indexName = "My Test Index";
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore("test store", { keyPath: "foo" });
       is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
       is(db.objectStoreNames.item(0), objectStore.name, "Correct name");
 
       is(objectStore.indexNames.length, 0, "Correct indexNames list");
 
       objectStore.createIndex(indexName, "foo");
 
--- a/dom/indexedDB/test/test_remove_objectStore.html
+++ b/dom/indexedDB/test/test_remove_objectStore.html
@@ -15,29 +15,24 @@
       const nsIIDBObjectStore = Components.interfaces.nsIIDBObjectStore;
       const UNKNOWN_ERR =
         Components.interfaces.nsIIDBDatabaseException.UNKNOWN_ERR;
 
       const name = window.location.pathname;
       const description = "My Test Database";
       const objectStoreName = "Objects";
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       is(db.objectStoreNames.length, 0, "Correct objectStoreNames list");
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       let objectStore = db.createObjectStore(objectStoreName,
                                              { keyPath: "foo" });
 
       let addedCount = 0;
 
       for (let i = 0; i < 100; i++) {
         request = objectStore.add({foo: i});
         request.onerror = errorHandler;
@@ -47,20 +42,24 @@
           }
         }
       }
       yield;
 
       is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
       is(db.objectStoreNames.item(0), objectStoreName, "Correct name");
 
-      request = db.setVersion("2");
+      db.close();
+
+      let request = mozIndexedDB.open(name, 2, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      let event = yield;
+
+      let db = event.target.result;
 
       db.deleteObjectStore(objectStore.name);
       is(db.objectStoreNames.length, 0, "Correct objectStores list");
 
       objectStore = db.createObjectStore(objectStoreName, { keyPath: "foo" });
       is(db.objectStoreNames.length, 1, "Correct objectStoreNames list");
       is(db.objectStoreNames.item(0), objectStoreName, "Correct name");
 
@@ -73,20 +72,24 @@
       event = yield;
 
       db.deleteObjectStore(objectStore.name);
       is(db.objectStoreNames.length, 0, "Correct objectStores list");
 
       continueToNextStep();
       yield;
 
-      request = db.setVersion("3");
+      db.close();
+
+      let request = mozIndexedDB.open(name, 3, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      let event = yield;
+
+      let db = event.target.result;
 
       objectStore = db.createObjectStore(objectStoreName, { keyPath: "foo" });
 
       request = objectStore.add({foo:"bar"});
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
 
       db.deleteObjectStore(objectStoreName);
--- a/dom/indexedDB/test/test_request_readyState.html
+++ b/dom/indexedDB/test/test_request_readyState.html
@@ -13,36 +13,27 @@
     function testSteps()
     {
       const name = window.location.pathname;
       const description = "My Test Database";
 
       const LOADING = Components.interfaces.nsIIDBRequest.LOADING;
       const DONE = Components.interfaces.nsIIDBRequest.DONE;
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       is(request.readyState, LOADING, "Correct readyState");
 
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       is(request.readyState, DONE, "Correct readyState");
 
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      is(request.readyState, LOADING, "Correct readyState");
-
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield;
-
-      is(request.readyState, DONE, "Correct readyState");
-
       let objectStore = db.createObjectStore("foo");
       let key = 10;
 
       request = objectStore.add({}, key);
       is(request.readyState, LOADING, "Correct readyState");
 
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
--- a/dom/indexedDB/test/test_setVersion.html
+++ b/dom/indexedDB/test/test_setVersion.html
@@ -14,44 +14,49 @@
 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, description);
+  let request = mozIndexedDB.open(name, 1, description);
   request.onerror = errorHandler;
   request.onsuccess = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
   // Check default state.
-  is(db.version, "", "Correct default version for a new database.");
+  is(db.version, 1, "Correct default version for a new database.");
 
   const versions = [
-    "1.0",
-    "",
+    7,
+    42,
   ];
 
+  db.close();
+
   for (let i = 0; i < versions.length; i++) {
     let version = versions[i];
 
-    request = db.setVersion(version);
+    let request = mozIndexedDB.open(name, version, description);
     request.onerror = errorHandler;
-    request.onsuccess = grabEventAndContinueHandler;
-    event = yield;
+    request.onupgradeneeded = grabEventAndContinueHandler;
+    let event = yield;
+
+    let db = event.target.result;
 
     is(db.version, version, "Database version number updated correctly");
     is(event.target.transaction.mode, VERSION_CHANGE, "Correct mode");
 
     SimpleTest.executeSoon(function() { testGenerator.next(); });
     yield;
+    db.close();
   }
 
   finishTest();
   yield;
 }
   </script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
--- a/dom/indexedDB/test/test_setVersion_abort.html
+++ b/dom/indexedDB/test/test_setVersion_abort.html
@@ -14,44 +14,47 @@
 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, description);
-  request.onerror = errorHandler;
-  request.onsuccess = grabEventAndContinueHandler;
+  let request = mozIndexedDB.open(name, 1, description);
+  request.onerror = grabEventAndContinueHandler;
+  request.onsuccess = errorHandler;
+  request.onupgradeneeded = grabEventAndContinueHandler;
   let event = yield;
 
   let db = event.target.result;
 
-  request = db.setVersion("1");
-  request.onerror = errorHandler;
-  request.onsuccess = grabEventAndContinueHandler;
-  event = yield;
-
   let objectStore = db.createObjectStore("foo");
   let index = objectStore.createIndex("bar", "baz");
 
-  is(db.version, "1", "Correct version");
+  is(db.version, 1, "Correct version");
   is(db.objectStoreNames.length, 1, "Correct objectStoreNames length");
   is(objectStore.indexNames.length, 1, "Correct indexNames length");
 
-  event.target.transaction.oncomplete = unexpectedSuccessHandler;
-  event.target.transaction.onabort = grabEventAndContinueHandler;
-  event.target.transaction.abort();
+  let transaction = event.target.transaction;
+  transaction.oncomplete = unexpectedSuccessHandler;
+  transaction.onabort = grabEventAndContinueHandler;
+  transaction.abort();
 
   event = yield;
+  is(event.type, "abort", "Got transaction abort event");
+  is(event.target, transaction, "Right target");
 
-  is(db.version, "", "Correct version");
+  todo(db.version, 1, "Correct version");
   is(db.objectStoreNames.length, 0, "Correct objectStoreNames length");
 
+  event = yield;
+  is(event.type, "error", "Got request error event");
+  is(event.target, request, "Right target");
+
   finishTest();
   yield;
 }
   </script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
 
 </head>
 
--- a/dom/indexedDB/test/test_setVersion_events.html
+++ b/dom/indexedDB/test/test_setVersion_events.html
@@ -10,86 +10,146 @@
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
       const name = window.location.pathname;
       const description = "My Test Database";
 
-      let request = mozIndexedDB.open(name, description);
+      // Open a datbase for the first time.
+      let request = mozIndexedDB.open(name, 1, description);
+
+      // Sanity checks
+      ok(request instanceof IDBRequest, "Request should be an IDBRequest");
+      ok(request instanceof IDBOpenDBRequest, "Request should be an IDBOpenDBRequest");
+      ok(request instanceof EventTarget, "Request should be an EventTarget");
+      is(request.source, null, "Request should have no source");
+      try {
+        request.result;
+        ok(false, "Getter should have thrown!");
+      } catch (e if e.result == 0x80660006 /* NS_ERROR_DOM_INDEXEDDB_NOTALLOWED_ERR */) {
+        ok(true, "Getter threw the right exception");
+      }
+
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       let event = yield;
 
       let versionChangeEventCount = 0;
       let db1, db2, db3;
 
       db1 = event.target.result;
       db1.addEventListener("versionchange", function(event) {
         ok(true, "Got version change event");
+        ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
         is(event.target.source, null, "Correct source");
         is(event.target, db1, "Correct target");
-        is(event.target.version, "", "Correct db version");
-        is(event.version, "1", "Correct event version");
+        is(event.target.version, 1, "Correct db version");
+        is(event.oldVersion, 1, "Correct event oldVersion");
+        is(event.newVersion, 2, "Correct event newVersion");
         is(versionChangeEventCount++, 0, "Correct count");
         db1.close();
       }, false);
 
-      request = mozIndexedDB.open(name, description);
+      // Open the database again and trigger an upgrade that should succeed
+      request = mozIndexedDB.open(name, 2, description);
       request.onerror = errorHandler;
+      request.onsuccess = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      request.onblocked = errorHandler;
+      event = yield;
+
+      // Test the upgradeneeded event.
+      ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
+      ok(event.target.result instanceof IDBDatabase, "Good result");
+      db2 = event.target.result;
+      is(event.target.transaction.mode, IDBTransaction.VERSION_CHANGE,
+         "Correct mode");
+      is(db2.version, 2, "Correct db version");
+      is(event.oldVersion, 1, "Correct event oldVersion");
+      is(event.newVersion, 2, "Correct event newVersion");
+
+      request.onupgradeneeded = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
 
-      db2 = event.target.result;
       db2.addEventListener("versionchange", function(event) {
         ok(true, "Got version change event");
+        ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
         is(event.target.source, null, "Correct source");
         is(event.target, db2, "Correct target");
-        is(event.target.version, "1", "Correct db version");
-        is(event.version, "2", "Correct event version");
+        is(event.target.version, 2, "Correct db version");
+        is(event.oldVersion, 2, "Correct event oldVersion");
+        is(event.newVersion, 3, "Correct event newVersion");
         is(versionChangeEventCount++, 1, "Correct count");
       }, false);
 
-      request = db2.setVersion("1");
+      // Test opening the existing version again
+      request = mozIndexedDB.open(name, 2, description);
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       request.onblocked = errorHandler;
       event = yield;
 
-      ok(event.target.result === event.target.transaction, "Good result");
-      is(event.target.transaction.mode, IDBTransaction.VERSION_CHANGE,
-         "Correct mode");
-      is(db2.version, "1", "Correct db version");
+      db3 = event.target.result;
+
+      // Test an upgrade that should fail
+      request = mozIndexedDB.open(name, 3, description);
+      request.onerror = errorHandler;
+      request.onsuccess = errorHandler;
+      request.onupgradeneeded = errorHandler;
+      request.onblocked = grabEventAndContinueHandler;
 
-      request = mozIndexedDB.open(name, description);
-      request.onerror = errorHandler;
+      event = yield;
+      ok(true, "Got version change blocked event");
+      ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
+      is(event.target.source, null, "Correct source");
+      is(event.target.transaction, null, "Correct transaction");
+      is(event.target, request, "Correct target");
+      is(db3.version, 2, "Correct db version");
+      is(event.oldVersion, 2, "Correct event oldVersion");
+      is(event.newVersion, 3, "Correct event newVersion");
+      versionChangeEventCount++;
+      db2.close();
+      db3.close();
+
+      request.onupgradeneeded = grabEventAndContinueHandler;
       request.onsuccess = grabEventAndContinueHandler;
+
+      event = yield;
       event = yield;
 
       db3 = event.target.result;
+      db3.close();
 
-      request = db3.setVersion("2");
+      // Test another upgrade that should succeed.
+      request = mozIndexedDB.open(name, 4);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      request.onblocked = function(event) {
-        ok(true, "Got version change blocked event");
-        is(event.target.source, db3, "Correct source");
-        is(event.target, request, "Correct target");
-        is(event.target.source.version, "1", "Correct db version");
-        is(event.version, "2", "Correct event version");
-        versionChangeEventCount++;
-        db2.close();
-      };
+      request.onsuccess = errorHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
+      request.onblocked = errorHandler;
+
       event = yield;
 
-      ok(event.target.result === event.target.transaction, "Good result");
+      ok(event instanceof IDBVersionChangeEvent, "Event is of the right type");
+      ok(event.target.result instanceof IDBDatabase, "Good result");
       is(event.target.transaction.mode, IDBTransaction.VERSION_CHANGE,
          "Correct mode");
-      is(db3.version, "2", "Correct db version");
+      is(event.oldVersion, 3, "Correct event oldVersion");
+      is(event.newVersion, 4, "Correct event newVersion");
+
+      request.onsuccess = grabEventAndContinueHandler;
+
+      event = yield;
+      ok(event.target.result instanceof IDBDatabase, "Expect a database here");
+      is(event.target.result.version, 4, "Right version");
+      todo_is(db3.version, 3, "After closing the version should not change!");
+      todo_is(db2.version, 2, "After closing the version should not change!");
+      todo_is(db1.version, 1, "After closing the version should not change!");
 
       is(versionChangeEventCount, 3, "Saw all expected events");
 
       finishTest();
       yield;
     }
   </script>
   <script type="text/javascript;version=1.7" src="helpers.js"></script>
--- a/dom/indexedDB/test/test_success_events_after_abort.html
+++ b/dom/indexedDB/test/test_success_events_after_abort.html
@@ -7,29 +7,24 @@
   <title>Indexed Database Property Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
-      let request = mozIndexedDB.open(window.location.pathname);
+      let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      let request = db.setVersion("1");
-      request.onsuccess = grabEventAndContinueHandler;
-      request.onerror = errorHandler;
-      event = yield;
-
-      event.target.result.oncomplete = continueToNextStep;
+      event.target.transaction.oncomplete = continueToNextStep;
 
       let objectStore = db.createObjectStore("foo");
       objectStore.add({}, 1).onerror = errorHandler;
 
       yield;
 
       objectStore = db.transaction("foo").objectStore("foo");
 
--- a/dom/indexedDB/test/test_transaction_abort.html
+++ b/dom/indexedDB/test/test_transaction_abort.html
@@ -21,31 +21,26 @@
       const READ_ONLY = Ci.nsIIDBTransaction.READ_ONLY;
       const READ_WRITE = Ci.nsIIDBTransaction.READ_WRITE;
       const VERSION_CHANGE = Ci.nsIIDBTransaction.VERSION_CHANGE;
 
       const name = window.location.pathname;
       const description = "My Test Database";
 
 
-      let request = mozIndexedDB.open(name, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
       let transaction;
       let objectStore;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       transaction = event.target.transaction;
       objectStore = db.createObjectStore("foo", { autoIncrement: true });
 
       is(transaction.db, db, "Correct database");
       is(transaction.readyState, LOADING, "Correct readyState");
       is(transaction.mode, VERSION_CHANGE, "Correct mode");
       is(transaction.objectStoreNames.length, 1, "Correct names length");
       is(transaction.objectStoreNames.item(0), "foo", "Correct name");
--- a/dom/indexedDB/test/test_transaction_lifetimes.html
+++ b/dom/indexedDB/test/test_transaction_lifetimes.html
@@ -7,27 +7,24 @@
   <title>Indexed Database Property Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
-      let request = mozIndexedDB.open(window.location.pathname);
+      let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = errorHandler;
 
-      db.setVersion("1").onsuccess = grabEventAndContinueHandler;
-      let event = yield;
-
       event.target.transaction.oncomplete = continueToNextStep;
 
       db.createObjectStore("foo", { autoIncrement: true });
       yield;
 
       let transaction = db.transaction("foo");
       continueToNextStep();
       yield;
--- a/dom/indexedDB/test/test_transaction_lifetimes_nested.html
+++ b/dom/indexedDB/test/test_transaction_lifetimes_nested.html
@@ -7,27 +7,24 @@
   <title>Indexed Database Property Test</title>
 
   <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 
   <script type="text/javascript;version=1.7">
     function testSteps()
     {
-      let request = mozIndexedDB.open(window.location.pathname);
+      let request = mozIndexedDB.open(window.location.pathname, 1);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
       db.onerror = errorHandler;
 
-      db.setVersion("1").onsuccess = grabEventAndContinueHandler;
-      event = yield;
-
       event.target.transaction.oncomplete = continueToNextStep;
       db.createObjectStore("foo");
       yield;
 
       let transaction1 = db.transaction("foo");
       is(transaction1.readyState, IDBTransaction.INITIAL, "Correct readyState");
 
       let transaction2;
--- a/dom/indexedDB/test/test_writer_starvation.html
+++ b/dom/indexedDB/test/test_writer_starvation.html
@@ -15,28 +15,23 @@
       const READ_ONLY = Components.interfaces.nsIIDBTransaction.READ_ONLY;
       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, description);
+      let request = mozIndexedDB.open(name, 1, description);
       request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
+      request.onupgradeneeded = grabEventAndContinueHandler;
       let event = yield;
 
       let db = event.target.result;
 
-      request = db.setVersion("1");
-      request.onerror = errorHandler;
-      request.onsuccess = grabEventAndContinueHandler;
-      let event = yield;
-
       is(event.target.transaction.mode, VERSION_CHANGE, "Correct mode");
 
       let objectStore = db.createObjectStore("foo", { autoIncrement: true });
 
       request = objectStore.add({});
       request.onerror = errorHandler;
       request.onsuccess = grabEventAndContinueHandler;
       event = yield;
--- a/dom/indexedDB/test/third_party_iframe2.html
+++ b/dom/indexedDB/test/third_party_iframe2.html
@@ -10,17 +10,17 @@
     function report(result) {
       let message = { source: "iframe" };
       message.result = result;
       window.parent.postMessage(message.toSource(), "*");
     }
 
     function runIndexedDBTest() {
       try {
-        let request = mozIndexedDB.open(window.location.pathname);
+        let request = mozIndexedDB.open(window.location.pathname, 1);
         request.onsuccess = function(event) {
           report(!!(event.target.result instanceof IDBDatabase));
         }
       }
       catch (e) {
         report(false);
       }
     }
--- a/gfx/thebes/GLContext.cpp
+++ b/gfx/thebes/GLContext.cpp
@@ -1025,24 +1025,24 @@ GLContext::ResizeOffscreenFBO(const gfxI
 
     MakeCurrent();
 
     const bool alpha = mCreationFormat.alpha > 0;
     const int depth = mCreationFormat.depth;
     const int stencil = mCreationFormat.stencil;
     int samples = mCreationFormat.samples;
 
-    const bool useDrawMSFBO = (samples > 0) && SupportsFramebufferMultisample();
+    if (!SupportsFramebufferMultisample() || aDisableAA)
+        samples = 0;
+
+    const bool useDrawMSFBO = (samples > 0);
 
     if (!useDrawMSFBO && !aUseReadFBO)
         return true;
 
-    if (!useDrawMSFBO || aDisableAA)
-        samples = 0;
-
     const bool firstTime = (mOffscreenDrawFBO == 0 && mOffscreenReadFBO == 0);
 
     GLuint curBoundFramebufferDraw = 0;
     GLuint curBoundFramebufferRead = 0;
     GLuint curBoundRenderbuffer = 0;
     GLuint curBoundTexture = 0;
 
     GLint viewport[4];
--- a/gfx/thebes/GLContext.h
+++ b/gfx/thebes/GLContext.h
@@ -1323,17 +1323,21 @@ protected:
     // for offscreen implementations that use FBOs.
     bool ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO, const bool aDisableAA);
     bool ResizeOffscreenFBO(const gfxIntSize& aSize, const bool aUseReadFBO) {
         if (ResizeOffscreenFBO(aSize, aUseReadFBO, false))
             return true;
 
         if (!mCreationFormat.samples)
             return false;
-        printf("ResizeOffscreenFBO failed with AA, retrying without...\n");
+
+        if (mDebugMode) {
+            printf_stderr("Requested level of multisampling is unavailable, continuing without multisampling\n");
+        }
+
         return ResizeOffscreenFBO(aSize, aUseReadFBO, true);
     }
     void DeleteOffscreenFBO();
     GLuint mOffscreenDrawFBO;
     GLuint mOffscreenReadFBO;
     GLuint mOffscreenColorRB;
     GLuint mOffscreenDepthRB;
     GLuint mOffscreenStencilRB;
--- a/js/xpconnect/src/dom_quickstubs.qsconf
+++ b/js/xpconnect/src/dom_quickstubs.qsconf
@@ -447,18 +447,18 @@ members = [
     'nsIIDBDatabase.*',
     'nsIIDBDatabaseException.*',
     'nsIIDBIndex.*',
     'nsIIDBKeyRange.*',
     'nsIIDBObjectStore.*',
     'nsIIDBRequest.*',
     'nsIIDBTransaction.*',
     'nsIIDBFactory.*',
+    'nsIIDBOpenDBRequest.*',
     'nsIIDBVersionChangeEvent.*',
-    'nsIIDBVersionChangeRequest.*',
     'nsIIndexedDatabaseUsageCallback.*',
     'nsIIndexedDatabaseManager.*',
     ]
 
 # Most interfaces can be found by searching the includePath; to find
 # nsIDOMEvent, for example, just look for nsIDOMEvent.idl.  But IDL filenames
 # for very long interface names are slightly abbreviated, and many interfaces
 # don't have their own files, just for extra wackiness.  So qsgen.py needs
--- a/js/xpconnect/src/qsgen.py
+++ b/js/xpconnect/src/qsgen.py
@@ -658,17 +658,17 @@ resultConvTemplates = {
     'short':
         "    ${jsvalRef} = INT_TO_JSVAL((int32) result);\n"
         "    return JS_TRUE;\n",
 
     'long':
         "    return xpc_qsInt32ToJsval(cx, result, ${jsvalPtr});\n",
 
     'long long':
-        "    return xpc_qsInt64ToJsval(cx, result, ${jsvalPtr};\n",
+        "    return xpc_qsInt64ToJsval(cx, result, ${jsvalPtr});\n",
 
     'unsigned short':
         "    ${jsvalRef} = INT_TO_JSVAL((int32) result);\n"
         "    return JS_TRUE;\n",
 
     'unsigned long':
         "    return xpc_qsUint32ToJsval(cx, result, ${jsvalPtr});\n",