void IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv) { AssertIsOnOwningThread(); if (!aCount) { aRv.ThrowTypeError<MSG_INVALID_ADVANCE_COUNT>(); return; } if (!mTransaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return; } if (IsSourceDeleted() || !mHaveValue || mContinueCalled) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return; } const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); mRequest->SetLoggingSerialNumber(requestSerialNumber); if (mType == Type_ObjectStore || mType == Type_ObjectStoreKey) { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s)." "cursor(%s).advance(%ld)", "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.advance()", IDB_LOG_ID_STRING(), mTransaction->LoggingSerialNumber(), requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSourceObjectStore), IDB_LOG_STRINGIFY(mDirection), aCount); } else { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s)." "index(%s).cursor(%s).advance(%ld)", "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.advance()", IDB_LOG_ID_STRING(), mTransaction->LoggingSerialNumber(), requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()), IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection), aCount); } mBackgroundActor->SendContinueInternal(AdvanceParams(aCount)); mContinueCalled = true; }
void IDBTransaction::FireCompleteOrAbortEvents(nsresult aResult) { AssertIsOnOwningThread(); MOZ_ASSERT(!mFiredCompleteOrAbort); mReadyState = DONE; #ifdef DEBUG mFiredCompleteOrAbort = true; #endif // Make sure we drop the WorkerFeature when this function completes. nsAutoPtr<WorkerFeature> workerFeature = Move(mWorkerFeature); nsCOMPtr<nsIDOMEvent> event; if (NS_SUCCEEDED(aResult)) { event = CreateGenericEvent(this, nsDependentString(kCompleteEventType), eDoesNotBubble, eNotCancelable); MOZ_ASSERT(event); } else { if (!mError && !mAbortedByScript) { mError = new DOMError(GetOwner(), aResult); } event = CreateGenericEvent(this, nsDependentString(kAbortEventType), eDoesBubble, eNotCancelable); MOZ_ASSERT(event); } if (NS_SUCCEEDED(mAbortCode)) { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: " "Firing 'complete' event", "IndexedDB %s: C T[%lld]: IDBTransaction 'complete' event", IDB_LOG_ID_STRING(), mLoggingSerialNumber); } else { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: " "Firing 'abort' event with error 0x%x", "IndexedDB %s: C T[%lld]: IDBTransaction 'abort' event (0x%x)", IDB_LOG_ID_STRING(), mLoggingSerialNumber, mAbortCode); } bool dummy; if (NS_FAILED(DispatchEvent(event, &dummy))) { NS_WARNING("DispatchEvent failed!"); } mDatabase->DelayedMaybeExpireFileActors(); }
void IDBTransaction::SendAbort(nsresult aResultCode) { AssertIsOnOwningThread(); MOZ_ASSERT(NS_FAILED(aResultCode)); MOZ_ASSERT(IsCommittingOrDone()); MOZ_ASSERT(!mSentCommitOrAbort); // Don't do this in the macro because we always need to increment the serial // number to keep in sync with the parent. const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "Aborting transaction with result 0x%x", "IndexedDB %s: C T[%lld] R[%llu]: IDBTransaction abort (0x%x)", IDB_LOG_ID_STRING(), LoggingSerialNumber(), requestSerialNumber, aResultCode); if (mMode == VERSION_CHANGE) { MOZ_ASSERT(mBackgroundActor.mVersionChangeBackgroundActor); mBackgroundActor.mVersionChangeBackgroundActor->SendAbort(aResultCode); } else { MOZ_ASSERT(mBackgroundActor.mNormalBackgroundActor); mBackgroundActor.mNormalBackgroundActor->SendAbort(aResultCode); } #ifdef DEBUG mSentCommitOrAbort = true; #endif }
void IDBTransaction::OnRequestFinished(bool aActorDestroyedNormally) { AssertIsOnOwningThread(); MOZ_ASSERT(mPendingRequestCount); --mPendingRequestCount; if (!mPendingRequestCount && !mDatabase->IsInvalidated()) { mReadyState = COMMITTING; if (aActorDestroyedNormally) { if (NS_SUCCEEDED(mAbortCode)) { SendCommit(); } else { SendAbort(mAbortCode); } } else { // Don't try to send any more messages to the parent if the request actor // was killed. #ifdef DEBUG MOZ_ASSERT(!mSentCommitOrAbort); mSentCommitOrAbort = true; #endif IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: " "Request actor was killed, transaction will be aborted", "IndexedDB %s: C T[%lld]: IDBTransaction abort", IDB_LOG_ID_STRING(), LoggingSerialNumber()); } } }
already_AddRefed<IDBRequest> IDBIndex::Count(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv) { AssertIsOnOwningThread(); if (mDeletedMetadata) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return nullptr; } IDBTransaction* transaction = mObjectStore->Transaction(); if (!transaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return nullptr; } RefPtr<IDBKeyRange> keyRange; aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); if (aRv.Failed()) { return nullptr; } IndexCountParams params; params.objectStoreId() = mObjectStore->Id(); params.indexId() = Id(); if (keyRange) { SerializedKeyRange serializedKeyRange; keyRange->ToSerialized(serializedKeyRange); params.optionalKeyRange() = serializedKeyRange; } else { params.optionalKeyRange() = void_t(); } RefPtr<IDBRequest> request = GenerateRequest(this); MOZ_ASSERT(request); IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s).index(%s)." "count(%s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.count()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(transaction->Database()), IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange)); transaction->StartRequest(request, params); return request.forget(); }
void IDBIndex::SetName(const nsAString& aName, ErrorResult& aRv) { AssertIsOnOwningThread(); IDBTransaction* transaction = mObjectStore->Transaction(); if (transaction->GetMode() != IDBTransaction::VERSION_CHANGE || mDeletedMetadata) { aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); return; } if (!transaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return; } if (aName == mMetadata->name()) { return; } // Cache logging string of this index before renaming. const LoggingString loggingOldIndex(this); const int64_t indexId = Id(); nsresult rv = transaction->Database()->RenameIndex(mObjectStore->Id(), indexId, aName); if (NS_FAILED(rv)) { aRv.Throw(rv); return; } // Don't do this in the macro because we always need to increment the serial // number to keep in sync with the parent. const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s).index(%s)." "rename(%s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.rename()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), requestSerialNumber, IDB_LOG_STRINGIFY(transaction->Database()), IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), loggingOldIndex.get(), IDB_LOG_STRINGIFY(this)); transaction->RenameIndex(mObjectStore, indexId, aName); }
already_AddRefed<IDBRequest> IDBDatabase::CreateMutableFile(JSContext* aCx, const nsAString& aName, const Optional<nsAString>& aType, ErrorResult& aRv) { AssertIsOnOwningThread(); if (QuotaManager::IsShuttingDown()) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } if (mClosed || mFileHandleDisabled) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return nullptr; } nsString type; if (aType.WasPassed()) { type = aType.Value(); } CreateFileParams params(nsString(aName), type); RefPtr<IDBRequest> request = IDBRequest::Create(aCx, this, nullptr); MOZ_ASSERT(request); BackgroundDatabaseRequestChild* actor = new BackgroundDatabaseRequestChild(this, request); IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: " "database(%s).createMutableFile(%s)", "IndexedDB %s: C R[%llu]: IDBDatabase.createMutableFile()", IDB_LOG_ID_STRING(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(this), NS_ConvertUTF16toUTF8(aName).get()); mBackgroundActor->SendPBackgroundIDBDatabaseRequestConstructor(actor, params); return request.forget(); }
already_AddRefed<IDBOpenDBRequest> IDBFactory::OpenInternal(JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName, const Optional<uint64_t>& aVersion, const Optional<StorageType>& aStorageType, bool aDeleting, CallerType aCallerType, ErrorResult& aRv) { MOZ_ASSERT(mWindow || mOwningObject); MOZ_ASSERT_IF(!mWindow, !mPrivateBrowsingMode); CommonFactoryRequestParams commonParams; PrincipalInfo& principalInfo = commonParams.principalInfo(); if (aPrincipal) { if (!NS_IsMainThread()) { MOZ_CRASH("Figure out security checks for workers! What's this " "aPrincipal we have on a worker thread?"); } MOZ_ASSERT(aCallerType == CallerType::System); MOZ_DIAGNOSTIC_ASSERT(mPrivateBrowsingMode == (aPrincipal->GetPrivateBrowsingId() > 0)); if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal, &principalInfo)))) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo && principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } } else { principalInfo = *mPrincipalInfo; } uint64_t version = 0; if (!aDeleting && aVersion.WasPassed()) { if (aVersion.Value() < 1) { aRv.ThrowTypeError<MSG_INVALID_VERSION>(); return nullptr; } version = aVersion.Value(); } // Nothing can be done here if we have previously failed to create a // background actor. if (mBackgroundActorFailed) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } PersistenceType persistenceType; bool isInternal = principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo; if (!isInternal && principalInfo.type() == PrincipalInfo::TContentPrincipalInfo) { nsCString origin = principalInfo.get_ContentPrincipalInfo().originNoSuffix(); isInternal = QuotaManager::IsOriginInternal(origin); } // Allow storage attributes for add-ons independent of the pref. // This works in the main thread only, workers don't have the principal. bool isAddon = false; if (NS_IsMainThread()) { // aPrincipal is passed inconsistently, so even when we are already on // the main thread, we may have been passed a null aPrincipal. nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(principalInfo); if (principal) { nsAutoString addonId; Unused << NS_WARN_IF(NS_FAILED(principal->GetAddonId(addonId))); isAddon = !addonId.IsEmpty(); } } if (isInternal) { // Chrome privilege and internal origins always get persistent storage. persistenceType = PERSISTENCE_TYPE_PERSISTENT; } else if (isAddon || DOMPrefs::IndexedDBStorageOptionsEnabled()) { persistenceType = PersistenceTypeFromStorage(aStorageType); } else { persistenceType = PERSISTENCE_TYPE_DEFAULT; } DatabaseMetadata& metadata = commonParams.metadata(); metadata.name() = aName; metadata.persistenceType() = persistenceType; FactoryRequestParams params; if (aDeleting) { metadata.version() = 0; params = DeleteDatabaseRequestParams(commonParams); } else { metadata.version() = version; params = OpenDatabaseRequestParams(commonParams); } if (!mBackgroundActor) { BackgroundChildImpl::ThreadLocal* threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread(); nsAutoPtr<ThreadLocal> newIDBThreadLocal; ThreadLocal* idbThreadLocal; if (threadLocal && threadLocal->mIndexedDBThreadLocal) { idbThreadLocal = threadLocal->mIndexedDBThreadLocal; } else { nsCOMPtr<nsIUUIDGenerator> uuidGen = do_GetService("@mozilla.org/uuid-generator;1"); MOZ_ASSERT(uuidGen); nsID id; MOZ_ALWAYS_SUCCEEDS(uuidGen->GenerateUUIDInPlace(&id)); newIDBThreadLocal = idbThreadLocal = new ThreadLocal(id); } PBackgroundChild* backgroundActor = BackgroundChild::GetOrCreateForCurrentThread(); if (NS_WARN_IF(!backgroundActor)) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } { BackgroundFactoryChild* actor = new BackgroundFactoryChild(this); // Set EventTarget for the top-level actor. // All child actors created later inherit the same event target. backgroundActor->SetEventTargetForActor(actor, EventTarget()); MOZ_ASSERT(actor->GetActorEventTarget()); mBackgroundActor = static_cast<BackgroundFactoryChild*>( backgroundActor->SendPBackgroundIDBFactoryConstructor(actor, idbThreadLocal->GetLoggingInfo())); if (NS_WARN_IF(!mBackgroundActor)) { mBackgroundActorFailed = true; IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } } if (newIDBThreadLocal) { if (!threadLocal) { threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread(); } MOZ_ASSERT(threadLocal); MOZ_ASSERT(!threadLocal->mIndexedDBThreadLocal); threadLocal->mIndexedDBThreadLocal = newIDBThreadLocal.forget(); } } RefPtr<IDBOpenDBRequest> request; if (mWindow) { JS::Rooted<JSObject*> scriptOwner(aCx, nsGlobalWindowInner::Cast(mWindow.get())->FastGetGlobalJSObject()); MOZ_ASSERT(scriptOwner); request = IDBOpenDBRequest::CreateForWindow(aCx, this, mWindow, scriptOwner); } else { JS::Rooted<JSObject*> scriptOwner(aCx, mOwningObject); request = IDBOpenDBRequest::CreateForJS(aCx, this, scriptOwner); if (!request) { MOZ_ASSERT(!NS_IsMainThread()); aRv.ThrowUncatchableException(); return nullptr; } } MOZ_ASSERT(request); if (aDeleting) { IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: " "indexedDB.deleteDatabase(\"%s\")", "IndexedDB %s: C R[%llu]: IDBFactory.deleteDatabase()", IDB_LOG_ID_STRING(), request->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName).get()); } else { IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: " "indexedDB.open(\"%s\", %s)", "IndexedDB %s: C R[%llu]: IDBFactory.open()", IDB_LOG_ID_STRING(), request->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName).get(), IDB_LOG_STRINGIFY(aVersion)); } nsresult rv = InitiateRequest(request, params); if (NS_WARN_IF(NS_FAILED(rv))) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } return request.forget(); }
already_AddRefed<IDBRequest> IDBIndex::OpenCursorInternal(bool aKeysOnly, JSContext* aCx, JS::Handle<JS::Value> aRange, IDBCursorDirection aDirection, ErrorResult& aRv) { AssertIsOnOwningThread(); if (mDeletedMetadata) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return nullptr; } IDBTransaction* transaction = mObjectStore->Transaction(); if (!transaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return nullptr; } RefPtr<IDBKeyRange> keyRange; aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange)); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } int64_t objectStoreId = mObjectStore->Id(); int64_t indexId = Id(); OptionalKeyRange optionalKeyRange; if (keyRange) { SerializedKeyRange serializedKeyRange; keyRange->ToSerialized(serializedKeyRange); optionalKeyRange = Move(serializedKeyRange); } else { optionalKeyRange = void_t(); } IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection); OpenCursorParams params; if (aKeysOnly) { IndexOpenKeyCursorParams openParams; openParams.objectStoreId() = objectStoreId; openParams.indexId() = indexId; openParams.optionalKeyRange() = Move(optionalKeyRange); openParams.direction() = direction; params = Move(openParams); } else { IndexOpenCursorParams openParams; openParams.objectStoreId() = objectStoreId; openParams.indexId() = indexId; openParams.optionalKeyRange() = Move(optionalKeyRange); openParams.direction() = direction; params = Move(openParams); } RefPtr<IDBRequest> request = GenerateRequest(this); MOZ_ASSERT(request); if (aKeysOnly) { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s).index(%s)." "openKeyCursor(%s, %s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.openKeyCursor()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(transaction->Database()), IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange), IDB_LOG_STRINGIFY(direction)); } else { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s).index(%s)." "openCursor(%s, %s)", "IndexedDB %s: C T[%lld] R[%llu]: " "IDBObjectStore.openKeyCursor()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(transaction->Database()), IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange), IDB_LOG_STRINGIFY(direction)); } BackgroundCursorChild* actor = new BackgroundCursorChild(request, this, direction); mObjectStore->Transaction()->OpenCursor(actor, params); return request.forget(); }
already_AddRefed<IDBRequest> IDBIndex::GetAllInternal(bool aKeysOnly, JSContext* aCx, JS::Handle<JS::Value> aKey, const Optional<uint32_t>& aLimit, ErrorResult& aRv) { AssertIsOnOwningThread(); if (mDeletedMetadata) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return nullptr; } IDBTransaction* transaction = mObjectStore->Transaction(); if (!transaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return nullptr; } RefPtr<IDBKeyRange> keyRange; aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } const int64_t objectStoreId = mObjectStore->Id(); const int64_t indexId = Id(); OptionalKeyRange optionalKeyRange; if (keyRange) { SerializedKeyRange serializedKeyRange; keyRange->ToSerialized(serializedKeyRange); optionalKeyRange = serializedKeyRange; } else { optionalKeyRange = void_t(); } const uint32_t limit = aLimit.WasPassed() ? aLimit.Value() : 0; RequestParams params; if (aKeysOnly) { params = IndexGetAllKeysParams(objectStoreId, indexId, optionalKeyRange, limit); } else { params = IndexGetAllParams(objectStoreId, indexId, optionalKeyRange, limit); } RefPtr<IDBRequest> request = GenerateRequest(this); MOZ_ASSERT(request); if (aKeysOnly) { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s).index(%s)." "getAllKeys(%s, %s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAllKeys()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(transaction->Database()), IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange), IDB_LOG_STRINGIFY(aLimit)); } else { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s).index(%s)." "getAll(%s, %s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAll()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(transaction->Database()), IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange), IDB_LOG_STRINGIFY(aLimit)); } transaction->StartRequest(request, params); return request.forget(); }
already_AddRefed<IDBRequest> IDBIndex::GetInternal(bool aKeyOnly, JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv) { AssertIsOnOwningThread(); if (mDeletedMetadata) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return nullptr; } IDBTransaction* transaction = mObjectStore->Transaction(); if (!transaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return nullptr; } RefPtr<IDBKeyRange> keyRange; aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } if (!keyRange) { // Must specify a key or keyRange for get() and getKey(). aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); return nullptr; } const int64_t objectStoreId = mObjectStore->Id(); const int64_t indexId = Id(); SerializedKeyRange serializedKeyRange; keyRange->ToSerialized(serializedKeyRange); RequestParams params; if (aKeyOnly) { params = IndexGetKeyParams(objectStoreId, indexId, serializedKeyRange); } else { params = IndexGetParams(objectStoreId, indexId, serializedKeyRange); } RefPtr<IDBRequest> request = GenerateRequest(this); MOZ_ASSERT(request); if (aKeyOnly) { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s).index(%s)." "getKey(%s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getKey()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(transaction->Database()), IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange)); } else { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s).index(%s)." "get(%s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.get()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(transaction->Database()), IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(mObjectStore), IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(keyRange)); } transaction->StartRequest(request, params); return request.forget(); }
void IDBDatabase::DeleteObjectStore(const nsAString& aName, ErrorResult& aRv) { AssertIsOnOwningThread(); IDBTransaction* transaction = IDBTransaction::GetCurrent(); if (!transaction || transaction->Database() != this || transaction->GetMode() != IDBTransaction::VERSION_CHANGE) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return; } if (!transaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return; } nsTArray<ObjectStoreSpec>& specArray = mSpec->objectStores(); int64_t objectStoreId = 0; for (uint32_t specCount = specArray.Length(), specIndex = 0; specIndex < specCount; specIndex++) { const ObjectStoreMetadata& metadata = specArray[specIndex].metadata(); MOZ_ASSERT(metadata.id()); if (aName == metadata.name()) { objectStoreId = metadata.id(); // Must do this before altering the metadata array! transaction->DeleteObjectStore(objectStoreId); specArray.RemoveElementAt(specIndex); RefreshSpec(/* aMayDelete */ false); break; } } if (!objectStoreId) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR); return; } // Don't do this in the macro because we always need to increment the serial // number to keep in sync with the parent. const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).deleteObjectStore(\"%s\")", "IndexedDB %s: C T[%lld] R[%llu]: " "IDBDatabase.deleteObjectStore()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), requestSerialNumber, IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(transaction), NS_ConvertUTF16toUTF8(aName).get()); }
void IDBCursor::Continue(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult &aRv) { AssertIsOnOwningThread(); if (!mTransaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return; } if (!mHaveValue || mContinueCalled) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return; } Key key; aRv = key.SetFromJSVal(aCx, aKey); if (aRv.Failed()) { return; } if (!key.IsUnset()) { switch (mDirection) { case NEXT: case NEXT_UNIQUE: if (key <= mKey) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); return; } break; case PREV: case PREV_UNIQUE: if (key >= mKey) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); return; } break; default: MOZ_CRASH("Unknown direction type!"); } } const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); mRequest->SetLoggingSerialNumber(requestSerialNumber); if (mType == Type_ObjectStore || mType == Type_ObjectStoreKey) { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s)." "cursor(%s).continue(%s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.continue()", IDB_LOG_ID_STRING(), mTransaction->LoggingSerialNumber(), requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSourceObjectStore), IDB_LOG_STRINGIFY(mDirection), IDB_LOG_STRINGIFY(key)); } else { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s)." "index(%s).cursor(%s).continue(%s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.continue()", IDB_LOG_ID_STRING(), mTransaction->LoggingSerialNumber(), requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()), IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection), IDB_LOG_STRINGIFY(key)); } mBackgroundActor->SendContinueInternal(ContinueParams(key)); mContinueCalled = true; }
void IDBCursor::ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey, JS::Handle<JS::Value> aPrimaryKey, ErrorResult &aRv) { AssertIsOnOwningThread(); if (!mTransaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return; } if (IsSourceDeleted()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return; } if ((mType != Type_Index && mType != Type_IndexKey) || (mDirection != NEXT && mDirection != PREV)) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return; } if (!mHaveValue || mContinueCalled) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return; } Key key; aRv = key.SetFromJSVal(aCx, aKey); if (aRv.Failed()) { return; } if (IsLocaleAware() && !key.IsUnset()) { Key tmp; aRv = key.ToLocaleBasedKey(tmp, mSourceIndex->Locale()); if (aRv.Failed()) { return; } key = tmp; } const Key& sortKey = IsLocaleAware() ? mSortKey : mKey; if (key.IsUnset()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); return; } Key primaryKey; aRv = primaryKey.SetFromJSVal(aCx, aPrimaryKey); if (aRv.Failed()) { return; } if (primaryKey.IsUnset()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); return; } switch (mDirection) { case NEXT: if (key < sortKey || (key == sortKey && primaryKey <= mPrimaryKey)) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); return; } break; case PREV: if (key > sortKey || (key == sortKey && primaryKey >= mPrimaryKey)) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); return; } break; default: MOZ_CRASH("Unknown direction type!"); } const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); mRequest->SetLoggingSerialNumber(requestSerialNumber); IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s)." "index(%s).cursor(%s).continuePrimaryKey(%s, %s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.continuePrimaryKey()", IDB_LOG_ID_STRING(), mTransaction->LoggingSerialNumber(), requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()), IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection), IDB_LOG_STRINGIFY(key), IDB_LOG_STRINGIFY(primaryKey)); mBackgroundActor->SendContinueInternal(ContinuePrimaryKeyParams(key, primaryKey)); mContinueCalled = true; }
already_AddRefed<IDBOpenDBRequest> IDBFactory::OpenInternal(JSContext* aCx, nsIPrincipal* aPrincipal, const nsAString& aName, const Optional<uint64_t>& aVersion, const Optional<StorageType>& aStorageType, bool aDeleting, ErrorResult& aRv) { MOZ_ASSERT(mWindow || mOwningObject); MOZ_ASSERT_IF(!mWindow, !mPrivateBrowsingMode); CommonFactoryRequestParams commonParams; commonParams.privateBrowsingMode() = mPrivateBrowsingMode; PrincipalInfo& principalInfo = commonParams.principalInfo(); if (aPrincipal) { if (!NS_IsMainThread()) { MOZ_CRASH("Figure out security checks for workers!"); } MOZ_ASSERT(nsContentUtils::IsCallerChrome()); if (NS_WARN_IF(NS_FAILED(PrincipalToPrincipalInfo(aPrincipal, &principalInfo)))) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } if (principalInfo.type() != PrincipalInfo::TContentPrincipalInfo && principalInfo.type() != PrincipalInfo::TSystemPrincipalInfo) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } } else { principalInfo = *mPrincipalInfo; } uint64_t version = 0; if (!aDeleting && aVersion.WasPassed()) { if (aVersion.Value() < 1) { aRv.ThrowTypeError<MSG_INVALID_VERSION>(); return nullptr; } version = aVersion.Value(); } // Nothing can be done here if we have previously failed to create a // background actor. if (mBackgroundActorFailed) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } PersistenceType persistenceType; if (principalInfo.type() == PrincipalInfo::TSystemPrincipalInfo) { // Chrome privilege always gets persistent storage. persistenceType = PERSISTENCE_TYPE_PERSISTENT; } else { persistenceType = PersistenceTypeFromStorage(aStorageType); } DatabaseMetadata& metadata = commonParams.metadata(); metadata.name() = aName; metadata.persistenceType() = persistenceType; FactoryRequestParams params; if (aDeleting) { metadata.version() = 0; params = DeleteDatabaseRequestParams(commonParams); } else { metadata.version() = version; params = OpenDatabaseRequestParams(commonParams); } if (!mBackgroundActor && mPendingRequests.IsEmpty()) { BackgroundChildImpl::ThreadLocal* threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread(); nsAutoPtr<ThreadLocal> newIDBThreadLocal; ThreadLocal* idbThreadLocal; if (threadLocal && threadLocal->mIndexedDBThreadLocal) { idbThreadLocal = threadLocal->mIndexedDBThreadLocal; } else { nsCOMPtr<nsIUUIDGenerator> uuidGen = do_GetService("@mozilla.org/uuid-generator;1"); MOZ_ASSERT(uuidGen); nsID id; MOZ_ALWAYS_SUCCEEDS(uuidGen->GenerateUUIDInPlace(&id)); newIDBThreadLocal = idbThreadLocal = new ThreadLocal(id); } if (PBackgroundChild* actor = BackgroundChild::GetForCurrentThread()) { BackgroundActorCreated(actor, idbThreadLocal->GetLoggingInfo()); } else { // We need to start the sequence to create a background actor for this // thread. RefPtr<BackgroundCreateCallback> cb = new BackgroundCreateCallback(this, idbThreadLocal->GetLoggingInfo()); if (NS_WARN_IF(!BackgroundChild::GetOrCreateForCurrentThread(cb))) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } } if (newIDBThreadLocal) { if (!threadLocal) { threadLocal = BackgroundChildImpl::GetThreadLocalForCurrentThread(); } MOZ_ASSERT(threadLocal); MOZ_ASSERT(!threadLocal->mIndexedDBThreadLocal); threadLocal->mIndexedDBThreadLocal = newIDBThreadLocal.forget(); } } RefPtr<IDBOpenDBRequest> request; if (mWindow) { JS::Rooted<JSObject*> scriptOwner(aCx, nsGlobalWindow::Cast(mWindow.get())->FastGetGlobalJSObject()); MOZ_ASSERT(scriptOwner); request = IDBOpenDBRequest::CreateForWindow(aCx, this, mWindow, scriptOwner); } else { JS::Rooted<JSObject*> scriptOwner(aCx, mOwningObject); request = IDBOpenDBRequest::CreateForJS(aCx, this, scriptOwner); if (!request) { MOZ_ASSERT(!NS_IsMainThread()); aRv.ThrowUncatchableException(); return nullptr; } } MOZ_ASSERT(request); if (aDeleting) { IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: " "indexedDB.deleteDatabase(\"%s\")", "IndexedDB %s: C R[%llu]: IDBFactory.deleteDatabase()", IDB_LOG_ID_STRING(), request->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName).get()); } else { IDB_LOG_MARK("IndexedDB %s: Child Request[%llu]: " "indexedDB.open(\"%s\", %s)", "IndexedDB %s: C R[%llu]: IDBFactory.open()", IDB_LOG_ID_STRING(), request->LoggingSerialNumber(), NS_ConvertUTF16toUTF8(aName).get(), IDB_LOG_STRINGIFY(aVersion)); } // If we already have a background actor then we can start this request now. if (mBackgroundActor) { nsresult rv = InitiateRequest(request, params); if (NS_WARN_IF(NS_FAILED(rv))) { IDB_REPORT_INTERNAL_ERR(); aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); return nullptr; } } else { mPendingRequests.AppendElement(new PendingRequestInfo(request, params)); } return request.forget(); }
already_AddRefed<IDBObjectStore> IDBDatabase::CreateObjectStore( const nsAString& aName, const IDBObjectStoreParameters& aOptionalParameters, ErrorResult& aRv) { AssertIsOnOwningThread(); IDBTransaction* transaction = IDBTransaction::GetCurrent(); if (!transaction || transaction->Database() != this || transaction->GetMode() != IDBTransaction::VERSION_CHANGE) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return nullptr; } if (!transaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return nullptr; } KeyPath keyPath(0); if (NS_FAILED(KeyPath::Parse(aOptionalParameters.mKeyPath, &keyPath))) { aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); return nullptr; } nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores(); for (uint32_t count = objectStores.Length(), index = 0; index < count; index++) { if (aName == objectStores[index].metadata().name()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR); return nullptr; } } if (!keyPath.IsAllowedForObjectStore(aOptionalParameters.mAutoIncrement)) { aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); return nullptr; } const ObjectStoreSpec* oldSpecElements = objectStores.IsEmpty() ? nullptr : objectStores.Elements(); ObjectStoreSpec* newSpec = objectStores.AppendElement(); newSpec->metadata() = ObjectStoreMetadata(transaction->NextObjectStoreId(), nsString(aName), keyPath, aOptionalParameters.mAutoIncrement); if (oldSpecElements && oldSpecElements != objectStores.Elements()) { MOZ_ASSERT(objectStores.Length() > 1); // Array got moved, update the spec pointers for all live objectStores and // indexes. RefreshSpec(/* aMayDelete */ false); } RefPtr<IDBObjectStore> objectStore = transaction->CreateObjectStore(*newSpec); MOZ_ASSERT(objectStore); // Don't do this in the macro because we always need to increment the serial // number to keep in sync with the parent. const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).createObjectStore(%s)", "IndexedDB %s: C T[%lld] R[%llu]: " "IDBDatabase.createObjectStore()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), requestSerialNumber, IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(transaction), IDB_LOG_STRINGIFY(objectStore)); return objectStore.forget(); }
already_AddRefed<IDBRequest> IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv) { AssertIsOnOwningThread(); if (!mTransaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return nullptr; } if (!mHaveValue || mType == Type_ObjectStoreKey || mType == Type_IndexKey) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return nullptr; } if (!mTransaction->IsWriteAllowed()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); return nullptr; } MOZ_ASSERT(mType == Type_ObjectStore || mType == Type_Index); MOZ_ASSERT(!mKey.IsUnset()); MOZ_ASSERT_IF(mType == Type_Index, !mPrimaryKey.IsUnset()); IDBObjectStore* objectStore; if (mType == Type_ObjectStore) { objectStore = mSourceObjectStore; } else { objectStore = mSourceIndex->ObjectStore(); } MOZ_ASSERT(objectStore); const Key& primaryKey = (mType == Type_ObjectStore) ? mKey : mPrimaryKey; nsRefPtr<IDBRequest> request; if (objectStore->HasValidKeyPath()) { // Make sure the object given has the correct keyPath value set on it. const KeyPath& keyPath = objectStore->GetKeyPath(); Key key; aRv = keyPath.ExtractKey(aCx, aValue, key); if (aRv.Failed()) { return nullptr; } if (key != primaryKey) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); return nullptr; } request = objectStore->AddOrPut(aCx, aValue, /* aKey */ JS::UndefinedHandleValue, /* aOverwrite */ true, /* aFromCursor */ true, aRv); if (aRv.Failed()) { return nullptr; } } else { JS::Rooted<JS::Value> keyVal(aCx); aRv = primaryKey.ToJSVal(aCx, &keyVal); if (aRv.Failed()) { return nullptr; } request = objectStore->AddOrPut(aCx, aValue, keyVal, /* aOverwrite */ true, /* aFromCursor */ true, aRv); if (aRv.Failed()) { return nullptr; } } request->SetSource(this); if (mType == Type_ObjectStore) { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s)." "cursor(%s).update(%s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.update()", IDB_LOG_ID_STRING(), mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore), IDB_LOG_STRINGIFY(mDirection), IDB_LOG_STRINGIFY(objectStore, primaryKey)); } else { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s)." "index(%s).cursor(%s).update(%s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.update()", IDB_LOG_ID_STRING(), mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore), IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection), IDB_LOG_STRINGIFY(objectStore, primaryKey)); } return request.forget(); }
nsresult IDBDatabase::Transaction(const StringOrStringSequence& aStoreNames, IDBTransactionMode aMode, IDBTransaction** aTransaction) { AssertIsOnOwningThread(); if (NS_WARN_IF(aMode == IDBTransactionMode::Readwriteflush && !IndexedDatabaseManager::ExperimentalFeaturesEnabled())) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (QuotaManager::IsShuttingDown()) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } if (mClosed || RunningVersionChangeTransaction()) { return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR; } nsAutoTArray<nsString, 1> stackSequence; if (aStoreNames.IsString()) { stackSequence.AppendElement(aStoreNames.GetAsString()); } else { MOZ_ASSERT(aStoreNames.IsStringSequence()); if (aStoreNames.GetAsStringSequence().IsEmpty()) { return NS_ERROR_DOM_INVALID_ACCESS_ERR; } } const nsTArray<nsString>& storeNames = aStoreNames.IsString() ? stackSequence : static_cast<const nsTArray<nsString>&>(aStoreNames.GetAsStringSequence()); MOZ_ASSERT(!storeNames.IsEmpty()); const nsTArray<ObjectStoreSpec>& objectStores = mSpec->objectStores(); const uint32_t nameCount = storeNames.Length(); nsTArray<nsString> sortedStoreNames; sortedStoreNames.SetCapacity(nameCount); // Check to make sure the object store names we collected actually exist. for (uint32_t nameIndex = 0; nameIndex < nameCount; nameIndex++) { const nsString& name = storeNames[nameIndex]; bool found = false; for (uint32_t objCount = objectStores.Length(), objIndex = 0; objIndex < objCount; objIndex++) { if (objectStores[objIndex].metadata().name() == name) { found = true; break; } } if (!found) { return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR; } sortedStoreNames.InsertElementSorted(name); } // Remove any duplicates. for (uint32_t nameIndex = nameCount - 1; nameIndex > 0; nameIndex--) { if (sortedStoreNames[nameIndex] == sortedStoreNames[nameIndex - 1]) { sortedStoreNames.RemoveElementAt(nameIndex); } } IDBTransaction::Mode mode; switch (aMode) { case IDBTransactionMode::Readonly: mode = IDBTransaction::READ_ONLY; break; case IDBTransactionMode::Readwrite: mode = IDBTransaction::READ_WRITE; break; case IDBTransactionMode::Readwriteflush: mode = IDBTransaction::READ_WRITE_FLUSH; break; case IDBTransactionMode::Versionchange: return NS_ERROR_DOM_INVALID_ACCESS_ERR; default: MOZ_CRASH("Unknown mode!"); } RefPtr<IDBTransaction> transaction = IDBTransaction::Create(this, sortedStoreNames, mode); if (NS_WARN_IF(!transaction)) { IDB_REPORT_INTERNAL_ERR(); return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; } BackgroundTransactionChild* actor = new BackgroundTransactionChild(transaction); IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld]: " "database(%s).transaction(%s)", "IndexedDB %s: C T[%lld]: IDBDatabase.transaction()", IDB_LOG_ID_STRING(), transaction->LoggingSerialNumber(), IDB_LOG_STRINGIFY(this), IDB_LOG_STRINGIFY(transaction)); MOZ_ALWAYS_TRUE( mBackgroundActor->SendPBackgroundIDBTransactionConstructor(actor, sortedStoreNames, mode)); transaction->SetBackgroundActor(actor); transaction.forget(aTransaction); return NS_OK; }
already_AddRefed<IDBRequest> IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv) { AssertIsOnOwningThread(); if (!mTransaction->IsOpen()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); return nullptr; } if (!mHaveValue || mType == Type_ObjectStoreKey || mType == Type_IndexKey) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); return nullptr; } if (!mTransaction->IsWriteAllowed()) { aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); return nullptr; } MOZ_ASSERT(mType == Type_ObjectStore || mType == Type_Index); MOZ_ASSERT(!mKey.IsUnset()); IDBObjectStore* objectStore; if (mType == Type_ObjectStore) { objectStore = mSourceObjectStore; } else { objectStore = mSourceIndex->ObjectStore(); } MOZ_ASSERT(objectStore); const Key& primaryKey = (mType == Type_ObjectStore) ? mKey : mPrimaryKey; JS::Rooted<JS::Value> key(aCx); aRv = primaryKey.ToJSVal(aCx, &key); if (NS_WARN_IF(aRv.Failed())) { return nullptr; } nsRefPtr<IDBRequest> request = objectStore->DeleteInternal(aCx, key, /* aFromCursor */ true, aRv); if (aRv.Failed()) { return nullptr; } request->SetSource(this); if (mType == Type_ObjectStore) { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s)." "cursor(%s).delete(%s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.delete()", IDB_LOG_ID_STRING(), mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore), IDB_LOG_STRINGIFY(mDirection), IDB_LOG_STRINGIFY(objectStore, primaryKey)); } else { IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " "database(%s).transaction(%s).objectStore(%s)." "index(%s).cursor(%s).delete(%s)", "IndexedDB %s: C T[%lld] R[%llu]: IDBCursor.delete()", IDB_LOG_ID_STRING(), mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(), IDB_LOG_STRINGIFY(mTransaction->Database()), IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore), IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection), IDB_LOG_STRINGIFY(objectStore, primaryKey)); } return request.forget(); }