示例#1
0
void setJSIDBDatabaseOnversionchange(ExecState* exec, JSObject* thisObject, JSValue value)
{
    UNUSED_PARAM(exec);
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(thisObject);
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());
    imp->setOnversionchange(createJSAttributeEventListener(exec, value, thisObject));
}
示例#2
0
EncodedJSValue JSC_HOST_CALL jsIDBDatabasePrototypeFunctionCreateObjectStore(ExecState* exec)
{
    JSValue thisValue = exec->hostThisValue();
    if (!thisValue.inherits(&JSIDBDatabase::s_info))
        return throwVMTypeError(exec);
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(asObject(thisValue));
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());
    ExceptionCode ec = 0;
    const String& name(ustringToString(exec->argument(0).toString(exec)));
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    int argsCount = exec->argumentCount();
    if (argsCount <= 1) {

        JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->createObjectStore(name, ec)));
        setDOMException(exec, ec);
        return JSValue::encode(result);
    }

    OptionsObject* options(toOptionsObject(exec->argument(1)));
    if (exec->hadException())
        return JSValue::encode(jsUndefined());


    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->createObjectStore(name, options, ec)));
    setDOMException(exec, ec);
    return JSValue::encode(result);
}
void IDBOpenDBRequest::onUpgradeNeeded(int64_t oldVersion, PassOwnPtr<WebIDBDatabase> backend, const IDBDatabaseMetadata& metadata, WebIDBDataLoss dataLoss, String dataLossMessage)
{
    IDB_TRACE("IDBOpenDBRequest::onUpgradeNeeded()");
    if (m_contextStopped || !executionContext()) {
        OwnPtr<WebIDBDatabase> db = backend;
        db->abort(m_transactionId);
        db->close();
        return;
    }
    if (!shouldEnqueueEvent())
        return;

    ASSERT(m_databaseCallbacks);

    IDBDatabase* idbDatabase = IDBDatabase::create(executionContext(), backend, m_databaseCallbacks.release());
    idbDatabase->setMetadata(metadata);

    if (oldVersion == IDBDatabaseMetadata::NoIntVersion) {
        // This database hasn't had an integer version before.
        oldVersion = IDBDatabaseMetadata::DefaultIntVersion;
    }
    IDBDatabaseMetadata oldMetadata(metadata);
    oldMetadata.intVersion = oldVersion;

    m_transaction = IDBTransaction::create(scriptState(), m_transactionId, idbDatabase, this, oldMetadata);
    setResult(IDBAny::create(idbDatabase));

    if (m_version == IDBDatabaseMetadata::NoIntVersion)
        m_version = 1;
    enqueueEvent(IDBVersionChangeEvent::create(EventTypeNames::upgradeneeded, oldVersion, m_version, dataLoss, dataLossMessage));
}
示例#4
0
void IDBConnectionProxy::registerDatabaseConnection(IDBDatabase& database)
{
    Locker<Lock> locker(m_databaseConnectionMapLock);

    ASSERT(!m_databaseConnectionMap.contains(database.databaseConnectionIdentifier()));
    m_databaseConnectionMap.set(database.databaseConnectionIdentifier(), &database);
}
void IDBOpenDBRequest::onSuccess(PassOwnPtr<WebIDBDatabase> backend, const IDBDatabaseMetadata& metadata)
{
    IDB_TRACE("IDBOpenDBRequest::onSuccess()");
    if (m_contextStopped || !executionContext()) {
        OwnPtr<WebIDBDatabase> db = backend;
        if (db)
            db->close();
        return;
    }
    if (!shouldEnqueueEvent())
        return;

    IDBDatabase* idbDatabase = nullptr;
    if (resultAsAny()) {
        // Previous onUpgradeNeeded call delivered the backend.
        ASSERT(!backend.get());
        idbDatabase = resultAsAny()->idbDatabase();
        ASSERT(idbDatabase);
        ASSERT(!m_databaseCallbacks);
    } else {
        ASSERT(backend.get());
        ASSERT(m_databaseCallbacks);
        idbDatabase = IDBDatabase::create(executionContext(), backend, m_databaseCallbacks.release());
        setResult(IDBAny::create(idbDatabase));
    }
    idbDatabase->setMetadata(metadata);
    enqueueEvent(Event::create(EventTypeNames::success));
}
示例#6
0
void IDBConnectionProxy::unregisterDatabaseConnection(IDBDatabase& database)
{
    Locker<Lock> locker(m_databaseConnectionMapLock);

    ASSERT(!m_databaseConnectionMap.contains(database.databaseConnectionIdentifier()) || m_databaseConnectionMap.get(database.databaseConnectionIdentifier()) == &database);
    m_databaseConnectionMap.remove(database.databaseConnectionIdentifier());
}
示例#7
0
JSValue jsIDBDatabaseObjectStoreNames(ExecState* exec, JSValue slotBase, const Identifier&)
{
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(asObject(slotBase));
    UNUSED_PARAM(exec);
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());
    JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->objectStoreNames()));
    return result;
}
示例#8
0
JSValue jsIDBDatabaseVersion(ExecState* exec, JSValue slotBase, const Identifier&)
{
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(asObject(slotBase));
    UNUSED_PARAM(exec);
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());
    JSValue result = jsString(exec, imp->version());
    return result;
}
示例#9
0
IDBDatabase* IDBDatabase::create(ExecutionContext* context,
                                 std::unique_ptr<WebIDBDatabase> database,
                                 IDBDatabaseCallbacks* callbacks) {
  IDBDatabase* idbDatabase =
      new IDBDatabase(context, std::move(database), callbacks);
  idbDatabase->suspendIfNeeded();
  return idbDatabase;
}
示例#10
0
EncodedJSValue JSC_HOST_CALL jsIDBDatabasePrototypeFunctionClose(ExecState* exec)
{
    JSValue thisValue = exec->hostThisValue();
    if (!thisValue.inherits(&JSIDBDatabase::s_info))
        return throwVMTypeError(exec);
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(asObject(thisValue));
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());

    imp->close();
    return JSValue::encode(jsUndefined());
}
示例#11
0
EncodedJSValue JSC_HOST_CALL jsIDBDatabasePrototypeFunctionRemoveEventListener(ExecState* exec)
{
    JSValue thisValue = exec->hostThisValue();
    if (!thisValue.inherits(&JSIDBDatabase::s_info))
        return throwVMTypeError(exec);
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(asObject(thisValue));
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());
    JSValue listener = exec->argument(1);
    if (!listener.isObject())
        return JSValue::encode(jsUndefined());
    imp->removeEventListener(ustringToAtomicString(exec->argument(0).toString(exec)), JSEventListener::create(asObject(listener), castedThis, false, currentWorld(exec)).get(), exec->argument(2).toBoolean(exec));
    return JSValue::encode(jsUndefined());
}
示例#12
0
JSValue jsIDBDatabaseOnversionchange(ExecState* exec, JSValue slotBase, const Identifier&)
{
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(asObject(slotBase));
    UNUSED_PARAM(exec);
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());
    if (EventListener* listener = imp->onversionchange()) {
        if (const JSEventListener* jsListener = JSEventListener::cast(listener)) {
            if (JSObject* jsFunction = jsListener->jsFunction(imp->scriptExecutionContext()))
                return jsFunction;
        }
    }
    return jsNull();
}
示例#13
0
EncodedJSValue JSC_HOST_CALL jsIDBDatabasePrototypeFunctionDeleteObjectStore(ExecState* exec)
{
    JSValue thisValue = exec->hostThisValue();
    if (!thisValue.inherits(&JSIDBDatabase::s_info))
        return throwVMTypeError(exec);
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(asObject(thisValue));
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());
    ExceptionCode ec = 0;
    const String& name(ustringToString(exec->argument(0).toString(exec)));
    if (exec->hadException())
        return JSValue::encode(jsUndefined());

    imp->deleteObjectStore(name, ec);
    setDOMException(exec, ec);
    return JSValue::encode(jsUndefined());
}
IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo& info)
    : WebCore::IDBTransaction(database.scriptExecutionContext())
    , m_database(database)
    , m_info(info)
    , m_operationTimer(*this, &IDBTransaction::operationTimerFired)

{
    relaxAdoptionRequirement();

    if (m_info.mode() == IndexedDB::TransactionMode::VersionChange) {
        m_originalDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_database->info());
        m_startedOnServer = true;
    } else {
        activate();

        RefPtr<IDBTransaction> self;
        JSC::VM& vm = JSDOMWindowBase::commonVM();
        vm.whenIdle([self, this]() {
            deactivate();
        });

        establishOnServer();
    }

    suspendIfNeeded();
}
示例#15
0
IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest* request)
    : WebCore::IDBTransaction(database.scriptExecutionContext())
    , m_database(database)
    , m_info(info)
    , m_operationTimer(*this, &IDBTransaction::operationTimerFired)
    , m_openDBRequest(request)

{
    LOG(IndexedDB, "IDBTransaction::IDBTransaction - %s", m_info.loggingString().utf8().data());

    relaxAdoptionRequirement();

    if (m_info.mode() == IndexedDB::TransactionMode::VersionChange) {
        ASSERT(m_openDBRequest);
        m_openDBRequest->setVersionChangeTransaction(*this);
        m_startedOnServer = true;
    } else {
        activate();

        RefPtr<IDBTransaction> self;
        JSC::VM& vm = JSDOMWindowBase::commonVM();
        vm.whenIdle([self, this]() {
            deactivate();
        });

        establishOnServer();
    }

    suspendIfNeeded();
}
示例#16
0
EncodedJSValue JSC_HOST_CALL jsIDBDatabasePrototypeFunctionDispatchEvent(ExecState* exec)
{
    JSValue thisValue = exec->hostThisValue();
    if (!thisValue.inherits(&JSIDBDatabase::s_info))
        return throwVMTypeError(exec);
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(asObject(thisValue));
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());
    ExceptionCode ec = 0;
    Event* evt(toEvent(exec->argument(0)));
    if (exec->hadException())
        return JSValue::encode(jsUndefined());


    JSC::JSValue result = jsBoolean(imp->dispatchEvent(evt, ec));
    setDOMException(exec, ec);
    return JSValue::encode(result);
}
示例#17
0
EncodedJSValue JSC_HOST_CALL jsIDBDatabasePrototypeFunctionSetVersion(ExecState* exec)
{
    JSValue thisValue = exec->hostThisValue();
    if (!thisValue.inherits(&JSIDBDatabase::s_info))
        return throwVMTypeError(exec);
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(asObject(thisValue));
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());
    ExceptionCode ec = 0;
    ScriptExecutionContext* scriptContext = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();
    if (!scriptContext)
        return JSValue::encode(jsUndefined());
    const String& version(ustringToString(exec->argument(0).toString(exec)));
    if (exec->hadException())
        return JSValue::encode(jsUndefined());


    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->setVersion(scriptContext, version, ec)));
    setDOMException(exec, ec);
    return JSValue::encode(result);
}
示例#18
0
// static
already_AddRefed<IDBCursor>
IDBCursor::CreateCommon(IDBRequest* aRequest,
                        IDBTransaction* aTransaction,
                        IDBObjectStore* aObjectStore,
                        Direction aDirection,
                        const Key& aRangeKey,
                        const nsACString& aContinueQuery,
                        const nsACString& aContinueToQuery)
{
  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  NS_ASSERTION(aRequest, "Null pointer!");
  NS_ASSERTION(aTransaction, "Null pointer!");
  NS_ASSERTION(aObjectStore, "Null pointer!");
  NS_ASSERTION(!aContinueQuery.IsEmpty(), "Empty query!");
  NS_ASSERTION(!aContinueToQuery.IsEmpty(), "Empty query!");

  nsRefPtr<IDBCursor> cursor = new IDBCursor();

  IDBDatabase* database = aTransaction->Database();
  cursor->mScriptOwner = database->GetScriptOwner();

  if (cursor->mScriptOwner) {
    if (NS_FAILED(NS_HOLD_JS_OBJECTS(cursor, IDBCursor))) {
      return nsnull;
    }

    cursor->mRooted = true;
  }

  cursor->mRequest = aRequest;
  cursor->mTransaction = aTransaction;
  cursor->mObjectStore = aObjectStore;
  cursor->mDirection = aDirection;
  cursor->mContinueQuery = aContinueQuery;
  cursor->mContinueToQuery = aContinueToQuery;
  cursor->mRangeKey = aRangeKey;

  return cursor.forget();
}
示例#19
0
EncodedJSValue JSC_HOST_CALL jsIDBDatabasePrototypeFunctionTransaction(ExecState* exec)
{
    JSValue thisValue = exec->hostThisValue();
    if (!thisValue.inherits(&JSIDBDatabase::s_info))
        return throwVMTypeError(exec);
    JSIDBDatabase* castedThis = static_cast<JSIDBDatabase*>(asObject(thisValue));
    IDBDatabase* imp = static_cast<IDBDatabase*>(castedThis->impl());
    ExceptionCode ec = 0;
    ScriptExecutionContext* scriptContext = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject())->scriptExecutionContext();
    if (!scriptContext)
        return JSValue::encode(jsUndefined());

    int argsCount = exec->argumentCount();
    if (argsCount <= 0) {

        JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->transaction(scriptContext, ec)));
        setDOMException(exec, ec);
        return JSValue::encode(result);
    }

    DOMStringList* storeNames(toDOMStringList(exec->argument(0)));
    if (exec->hadException())
        return JSValue::encode(jsUndefined());
    if (argsCount <= 1) {

        JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->transaction(scriptContext, storeNames, ec)));
        setDOMException(exec, ec);
        return JSValue::encode(result);
    }

    unsigned short mode(exec->argument(1).toUInt32(exec));
    if (exec->hadException())
        return JSValue::encode(jsUndefined());


    JSC::JSValue result = toJS(exec, castedThis->globalObject(), WTF::getPtr(imp->transaction(scriptContext, storeNames, mode, ec)));
    setDOMException(exec, ec);
    return JSValue::encode(result);
}
示例#20
0
// static
already_AddRefed<IDBIndex>
IDBIndex::Create(IDBObjectStore* aObjectStore,
                 const IndexInfo* aIndexInfo)
{
  NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
  NS_ASSERTION(aObjectStore, "Null pointer!");
  NS_ASSERTION(aIndexInfo, "Null pointer!");

  IDBDatabase* database = aObjectStore->Transaction()->Database();

  nsRefPtr<IDBIndex> index = new IDBIndex();

  index->mScriptContext = database->ScriptContext();
  index->mOwner = database->Owner();

  index->mObjectStore = aObjectStore;
  index->mId = aIndexInfo->id;
  index->mName = aIndexInfo->name;
  index->mKeyPath = aIndexInfo->keyPath;
  index->mUnique = aIndexInfo->unique;
  index->mAutoIncrement = aIndexInfo->autoIncrement;

  return index.forget();
}
NS_IMETHODIMP
CommitHelper::Run()
{
  if (NS_IsMainThread()) {
    NS_ASSERTION(mDoomedObjects.IsEmpty(), "Didn't release doomed objects!");

    mTransaction->mReadyState = IDBTransaction::DONE;

    // Release file infos on the main thread, so they will eventually get
    // destroyed on correct thread.
    mTransaction->ClearCreatedFileInfos();
    if (mUpdateFileRefcountFunction) {
      mUpdateFileRefcountFunction->ClearFileInfoEntries();
      mUpdateFileRefcountFunction = nullptr;
    }

    nsCOMPtr<nsIDOMEvent> event;
    if (NS_FAILED(mAbortCode)) {
      if (mTransaction->GetMode() == IDBTransaction::VERSION_CHANGE) {
        // This will make the database take a snapshot of it's DatabaseInfo
        mTransaction->Database()->Close();
        // Then remove the info from the hash as it contains invalid data.
        DatabaseInfo::Remove(mTransaction->Database()->Id());
      }

      event = CreateGenericEvent(NS_LITERAL_STRING(ABORT_EVT_STR),
                                 eDoesBubble, eNotCancelable);

      // The transaction may already have an error object (e.g. if one of the
      // requests failed).  If it doesn't, and it wasn't aborted
      // programmatically, create one now.
      if (!mTransaction->mError &&
          mAbortCode != NS_ERROR_DOM_INDEXEDDB_ABORT_ERR) {
        mTransaction->mError = DOMError::CreateForNSResult(mAbortCode);
      }
    }
    else {
      event = CreateGenericEvent(NS_LITERAL_STRING(COMPLETE_EVT_STR),
                                 eDoesNotBubble, eNotCancelable);
    }
    NS_ENSURE_TRUE(event, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);

    if (mListener) {
      mListener->NotifyTransactionPreComplete(mTransaction);
    }

    bool dummy;
    if (NS_FAILED(mTransaction->DispatchEvent(event, &dummy))) {
      NS_WARNING("Dispatch failed!");
    }

#ifdef DEBUG
    mTransaction->mFiredCompleteOrAbort = true;
#endif

    if (mListener) {
      mListener->NotifyTransactionPostComplete(mTransaction);
    }

    mTransaction = nullptr;

    return NS_OK;
  }

  IDBDatabase* database = mTransaction->Database();
  if (database->IsInvalidated()) {
    mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  }

  if (mConnection) {
    QuotaManager::SetCurrentWindow(database->GetOwner());

    if (NS_SUCCEEDED(mAbortCode) && mUpdateFileRefcountFunction &&
        NS_FAILED(mUpdateFileRefcountFunction->WillCommit(mConnection))) {
      mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    }

    if (NS_SUCCEEDED(mAbortCode) && NS_FAILED(WriteAutoIncrementCounts())) {
      mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
    }

    if (NS_SUCCEEDED(mAbortCode)) {
      NS_NAMED_LITERAL_CSTRING(release, "COMMIT TRANSACTION");
      nsresult rv = mConnection->ExecuteSimpleSQL(release);
      if (NS_SUCCEEDED(rv)) {
        if (mUpdateFileRefcountFunction) {
          mUpdateFileRefcountFunction->DidCommit();
        }
        CommitAutoIncrementCounts();
      }
      else if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
        // mozstorage translates SQLITE_FULL to NS_ERROR_FILE_NO_DEVICE_SPACE,
        // which we know better as NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR.
        mAbortCode = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
      }
      else {
        mAbortCode = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
      }
    }

    if (NS_FAILED(mAbortCode)) {
      if (mUpdateFileRefcountFunction) {
        mUpdateFileRefcountFunction->DidAbort();
      }
      RevertAutoIncrementCounts();
      NS_NAMED_LITERAL_CSTRING(rollback, "ROLLBACK TRANSACTION");
      if (NS_FAILED(mConnection->ExecuteSimpleSQL(rollback))) {
        NS_WARNING("Failed to rollback transaction!");
      }
    }
  }

  mDoomedObjects.Clear();

  if (mConnection) {
    if (mUpdateFileRefcountFunction) {
      nsresult rv = mConnection->RemoveFunction(
        NS_LITERAL_CSTRING("update_refcount"));
      if (NS_FAILED(rv)) {
        NS_WARNING("Failed to remove function!");
      }
    }

    mConnection->Close();
    mConnection = nullptr;

    QuotaManager::SetCurrentWindow(nullptr);
  }

  return NS_OK;
}
IDBDatabase* IDBDatabase::create(ExecutionContext* context, PassOwnPtr<WebIDBDatabase> database, IDBDatabaseCallbacks* callbacks)
{
    IDBDatabase* idbDatabase = new IDBDatabase(context, database, callbacks);
    idbDatabase->suspendIfNeeded();
    return idbDatabase;
}
示例#23
0
void IDBConnectionToServer::databaseConnectionClosed(IDBDatabase& database)
{
    LOG(IndexedDB, "IDBConnectionToServer::databaseConnectionClosed");

    m_delegate->databaseConnectionClosed(database.databaseConnectionIdentifier());
}
示例#24
0
void IDBConnectionToServer::registerDatabaseConnection(IDBDatabase& database)
{
    ASSERT(!m_databaseConnectionMap.contains(database.databaseConnectionIdentifier()));
    m_databaseConnectionMap.set(database.databaseConnectionIdentifier(), &database);
}
示例#25
0
void IDBConnectionToServer::unregisterDatabaseConnection(IDBDatabase& database)
{
    ASSERT(m_databaseConnectionMap.contains(database.databaseConnectionIdentifier()));
    ASSERT(m_databaseConnectionMap.get(database.databaseConnectionIdentifier()) == &database);
    m_databaseConnectionMap.remove(database.databaseConnectionIdentifier());
}
示例#26
0
void IDBConnectionProxy::confirmDidCloseFromServer(IDBDatabase& database)
{
    callConnectionOnMainThread(&IDBConnectionToServer::confirmDidCloseFromServer, database.databaseConnectionIdentifier());
}
示例#27
0
void IDBConnectionProxy::databaseConnectionClosed(IDBDatabase& database)
{
    callConnectionOnMainThread(&IDBConnectionToServer::databaseConnectionClosed, database.databaseConnectionIdentifier());
}
示例#28
0
nsresult
DataStoreDB::UpgradeSchema(nsIDOMEvent* aEvent)
{
  MOZ_ASSERT(NS_IsMainThread());

  // This DB has been just created and we have to inform the callback about
  // this.
  mCreatedSchema = true;

#ifdef DEBUG
  nsCOMPtr<IDBVersionChangeEvent> event = do_QueryInterface(aEvent);
  MOZ_ASSERT(event);

  Nullable<uint64_t> version = event->GetNewVersion();
  MOZ_ASSERT(!version.IsNull());
  MOZ_ASSERT(version.Value() == DATASTOREDB_VERSION);
#endif

  ErrorResult error;
  JS::Rooted<JS::Value> result(nsContentUtils::RootingCx());
  mRequest->GetResult(&result, error);
  if (NS_WARN_IF(error.Failed())) {
    return error.StealNSResult();
  }

  MOZ_ASSERT(result.isObject());

  IDBDatabase* database = nullptr;
  nsresult rv = UNWRAP_OBJECT(IDBDatabase, &result.toObject(), database);
  if (NS_FAILED(rv)) {
    NS_WARNING("Didn't get the object we expected!");
    return rv;
  }

  {
    IDBObjectStoreParameters params;
    params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true }"));
    RefPtr<IDBObjectStore> store =
      database->CreateObjectStore(NS_LITERAL_STRING(DATASTOREDB_NAME),
                                  params, error);
    if (NS_WARN_IF(error.Failed())) {
      return error.StealNSResult();
    }
  }

  RefPtr<IDBObjectStore> store;

  {
    IDBObjectStoreParameters params;
    params.Init(NS_LITERAL_STRING("{ \"autoIncrement\": true, \"keyPath\": \"internalRevisionId\" }"));

    store =
      database->CreateObjectStore(NS_LITERAL_STRING(DATASTOREDB_REVISION),
                                  params, error);
    if (NS_WARN_IF(error.Failed())) {
      return error.StealNSResult();
    }
  }

  {
    IDBIndexParameters params;
    params.Init(NS_LITERAL_STRING("{ \"unique\": true }"));
    RefPtr<IDBIndex> index =
      store->CreateIndex(NS_LITERAL_STRING(DATASTOREDB_REVISION_INDEX),
                         NS_LITERAL_STRING("revisionId"), params, error);
    if (NS_WARN_IF(error.Failed())) {
      return error.StealNSResult();
    }
  }

  return NS_OK;
}