Bug 1729395 - Handle message sender going away during message processing r=robwu
[gecko.git] / dom / indexedDB / IDBCursor.cpp
blobe1c97d8449dcb0cbc3545543e2dc6eb299283bde
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "IDBCursor.h"
9 #include "IDBDatabase.h"
10 #include "IDBIndex.h"
11 #include "IDBObjectStore.h"
12 #include "IDBRequest.h"
13 #include "IDBTransaction.h"
14 #include "IndexedDatabaseInlines.h"
15 #include "mozilla/ErrorResult.h"
16 #include "mozilla/HoldDropJSObjects.h"
17 #include "mozilla/dom/UnionTypes.h"
18 #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
19 #include "nsString.h"
20 #include "ProfilerHelpers.h"
21 #include "ReportInternalError.h"
23 // Include this last to avoid path problems on Windows.
24 #include "ActorsChild.h"
26 namespace mozilla::dom {
28 using namespace indexedDB;
30 IDBCursor::IDBCursor(BackgroundCursorChildBase* const aBackgroundActor)
31 : mBackgroundActor(WrapNotNull(aBackgroundActor)),
32 mRequest(aBackgroundActor->GetRequest()),
33 mTransaction(&mRequest->MutableTransactionRef()),
34 mCachedKey(JS::UndefinedValue()),
35 mCachedPrimaryKey(JS::UndefinedValue()),
36 mCachedValue(JS::UndefinedValue()),
37 mDirection(aBackgroundActor->GetDirection()),
38 mHaveCachedKey(false),
39 mHaveCachedPrimaryKey(false),
40 mHaveCachedValue(false),
41 mRooted(false),
42 mContinueCalled(false),
43 mHaveValue(true) {
44 MOZ_ASSERT(aBackgroundActor);
45 aBackgroundActor->AssertIsOnOwningThread();
46 MOZ_ASSERT(mRequest);
48 mTransaction->RegisterCursor(*this);
51 template <IDBCursor::Type CursorType>
52 IDBTypedCursor<CursorType>::~IDBTypedCursor() {
53 AssertIsOnOwningThread();
55 mTransaction->UnregisterCursor(*this);
57 DropJSObjects();
59 if (mBackgroundActor) {
60 (*mBackgroundActor)->SendDeleteMeInternal();
61 MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
65 // static
66 RefPtr<IDBObjectStoreCursor> IDBCursor::Create(
67 BackgroundCursorChild<Type::ObjectStore>* const aBackgroundActor, Key aKey,
68 StructuredCloneReadInfoChild&& aCloneInfo) {
69 MOZ_ASSERT(aBackgroundActor);
70 aBackgroundActor->AssertIsOnOwningThread();
71 MOZ_ASSERT(!aKey.IsUnset());
73 return MakeRefPtr<IDBObjectStoreCursor>(aBackgroundActor, std::move(aKey),
74 std::move(aCloneInfo));
77 // static
78 RefPtr<IDBObjectStoreKeyCursor> IDBCursor::Create(
79 BackgroundCursorChild<Type::ObjectStoreKey>* const aBackgroundActor,
80 Key aKey) {
81 MOZ_ASSERT(aBackgroundActor);
82 aBackgroundActor->AssertIsOnOwningThread();
83 MOZ_ASSERT(!aKey.IsUnset());
85 return MakeRefPtr<IDBObjectStoreKeyCursor>(aBackgroundActor, std::move(aKey));
88 // static
89 RefPtr<IDBIndexCursor> IDBCursor::Create(
90 BackgroundCursorChild<Type::Index>* const aBackgroundActor, Key aKey,
91 Key aSortKey, Key aPrimaryKey, StructuredCloneReadInfoChild&& aCloneInfo) {
92 MOZ_ASSERT(aBackgroundActor);
93 aBackgroundActor->AssertIsOnOwningThread();
94 MOZ_ASSERT(!aKey.IsUnset());
95 MOZ_ASSERT(!aPrimaryKey.IsUnset());
97 return MakeRefPtr<IDBIndexCursor>(aBackgroundActor, std::move(aKey),
98 std::move(aSortKey), std::move(aPrimaryKey),
99 std::move(aCloneInfo));
102 // static
103 RefPtr<IDBIndexKeyCursor> IDBCursor::Create(
104 BackgroundCursorChild<Type::IndexKey>* const aBackgroundActor, Key aKey,
105 Key aSortKey, Key aPrimaryKey) {
106 MOZ_ASSERT(aBackgroundActor);
107 aBackgroundActor->AssertIsOnOwningThread();
108 MOZ_ASSERT(!aKey.IsUnset());
109 MOZ_ASSERT(!aPrimaryKey.IsUnset());
111 return MakeRefPtr<IDBIndexKeyCursor>(aBackgroundActor, std::move(aKey),
112 std::move(aSortKey),
113 std::move(aPrimaryKey));
116 #ifdef DEBUG
118 void IDBCursor::AssertIsOnOwningThread() const {
119 MOZ_ASSERT(mTransaction);
120 mTransaction->AssertIsOnOwningThread();
123 #endif // DEBUG
125 template <IDBCursor::Type CursorType>
126 void IDBTypedCursor<CursorType>::DropJSObjects() {
127 AssertIsOnOwningThread();
129 Reset();
131 if (!mRooted) {
132 return;
135 mRooted = false;
137 mozilla::DropJSObjects(this);
140 template <IDBCursor::Type CursorType>
141 bool IDBTypedCursor<CursorType>::IsSourceDeleted() const {
142 AssertIsOnOwningThread();
143 MOZ_ASSERT(mTransaction);
144 MOZ_ASSERT(mTransaction->IsActive());
146 const auto* const sourceObjectStore = [this]() -> const IDBObjectStore* {
147 if constexpr (IsObjectStoreCursor) {
148 return mSource;
149 } else {
150 if (GetSourceRef().IsDeleted()) {
151 return nullptr;
154 const auto* const res = GetSourceRef().ObjectStore();
155 MOZ_ASSERT(res);
156 return res;
158 }();
160 return !sourceObjectStore || sourceObjectStore->IsDeleted();
163 void IDBCursor::ResetBase() {
164 AssertIsOnOwningThread();
166 mCachedKey.setUndefined();
167 mCachedPrimaryKey.setUndefined();
168 mCachedValue.setUndefined();
170 mHaveCachedKey = false;
171 mHaveCachedPrimaryKey = false;
172 mHaveCachedValue = false;
173 mHaveValue = false;
174 mContinueCalled = false;
177 template <IDBCursor::Type CursorType>
178 void IDBTypedCursor<CursorType>::Reset() {
179 AssertIsOnOwningThread();
181 if constexpr (!IsKeyOnlyCursor) {
182 IDBObjectStore::ClearCloneReadInfo(mData.mCloneInfo);
185 ResetBase();
188 nsIGlobalObject* IDBCursor::GetParentObject() const {
189 AssertIsOnOwningThread();
190 MOZ_ASSERT(mTransaction);
192 return mTransaction->GetParentObject();
195 IDBCursorDirection IDBCursor::GetDirection() const {
196 AssertIsOnOwningThread();
198 switch (mDirection) {
199 case Direction::Next:
200 return IDBCursorDirection::Next;
202 case Direction::Nextunique:
203 return IDBCursorDirection::Nextunique;
205 case Direction::Prev:
206 return IDBCursorDirection::Prev;
208 case Direction::Prevunique:
209 return IDBCursorDirection::Prevunique;
211 default:
212 MOZ_CRASH("Bad direction!");
216 RefPtr<IDBRequest> IDBCursor::Request() const {
217 AssertIsOnOwningThread();
218 return mRequest;
221 template <IDBCursor::Type CursorType>
222 void IDBTypedCursor<CursorType>::GetSource(
223 OwningIDBObjectStoreOrIDBIndex& aSource) const {
224 AssertIsOnOwningThread();
226 if constexpr (IsObjectStoreCursor) {
227 aSource.SetAsIDBObjectStore() = mSource;
228 } else {
229 aSource.SetAsIDBIndex() = mSource;
233 template <IDBCursor::Type CursorType>
234 void IDBTypedCursor<CursorType>::GetKey(JSContext* const aCx,
235 JS::MutableHandle<JS::Value> aResult,
236 ErrorResult& aRv) {
237 AssertIsOnOwningThread();
238 MOZ_ASSERT(!mData.mKey.IsUnset() || !mHaveValue);
240 if (!mHaveValue) {
241 aResult.setUndefined();
242 return;
245 if (!mHaveCachedKey) {
246 if (!mRooted) {
247 mozilla::HoldJSObjects(this);
248 mRooted = true;
251 aRv = mData.mKey.ToJSVal(aCx, mCachedKey);
252 if (NS_WARN_IF(aRv.Failed())) {
253 return;
256 mHaveCachedKey = true;
259 aResult.set(mCachedKey);
262 template <IDBCursor::Type CursorType>
263 void IDBTypedCursor<CursorType>::GetPrimaryKey(
264 JSContext* const aCx, JS::MutableHandle<JS::Value> aResult,
265 ErrorResult& aRv) {
266 AssertIsOnOwningThread();
268 if (!mHaveValue) {
269 aResult.setUndefined();
270 return;
273 if (!mHaveCachedPrimaryKey) {
274 if (!mRooted) {
275 mozilla::HoldJSObjects(this);
276 mRooted = true;
279 const Key& key = mData.GetObjectStoreKey();
281 MOZ_ASSERT(!key.IsUnset());
283 aRv = key.ToJSVal(aCx, mCachedPrimaryKey);
284 if (NS_WARN_IF(aRv.Failed())) {
285 return;
288 mHaveCachedPrimaryKey = true;
291 aResult.set(mCachedPrimaryKey);
294 template <IDBCursor::Type CursorType>
295 void IDBTypedCursor<CursorType>::GetValue(JSContext* const aCx,
296 JS::MutableHandle<JS::Value> aResult,
297 ErrorResult& aRv) {
298 AssertIsOnOwningThread();
300 if constexpr (!IsKeyOnlyCursor) {
301 if (!mHaveValue) {
302 aResult.setUndefined();
303 return;
306 if (!mHaveCachedValue) {
307 if (!mRooted) {
308 mozilla::HoldJSObjects(this);
309 mRooted = true;
312 JS::Rooted<JS::Value> val(aCx);
313 if (NS_WARN_IF(!IDBObjectStore::DeserializeValue(
314 aCx, std::move(mData.mCloneInfo), &val))) {
315 aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
316 return;
319 // XXX This seems redundant, sine mData.mCloneInfo is moved above.
320 IDBObjectStore::ClearCloneReadInfo(mData.mCloneInfo);
322 mCachedValue = val;
323 mHaveCachedValue = true;
326 aResult.set(mCachedValue);
327 } else {
328 MOZ_CRASH("This shouldn't be callable on a key-only cursor.");
332 template <IDBCursor::Type CursorType>
333 void IDBTypedCursor<CursorType>::Continue(JSContext* const aCx,
334 JS::Handle<JS::Value> aKey,
335 ErrorResult& aRv) {
336 AssertIsOnOwningThread();
338 if (!mTransaction->IsActive()) {
339 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
340 return;
343 if (IsSourceDeleted() || !mHaveValue || mContinueCalled) {
344 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
345 return;
348 Key key;
349 auto result = key.SetFromJSVal(aCx, aKey);
350 if (result.isErr()) {
351 aRv = result.unwrapErr().ExtractErrorResult(
352 InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>);
353 return;
356 if constexpr (!IsObjectStoreCursor) {
357 if (IsLocaleAware() && !key.IsUnset()) {
358 auto result = key.ToLocaleAwareKey(GetSourceRef().Locale());
359 if (result.isErr()) {
360 aRv.Throw(result.inspectErr());
361 return;
363 key = result.unwrap();
367 const Key& sortKey = mData.GetSortKey(IsLocaleAware());
369 if (!key.IsUnset()) {
370 switch (mDirection) {
371 case Direction::Next:
372 case Direction::Nextunique:
373 if (key <= sortKey) {
374 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
375 return;
377 break;
379 case Direction::Prev:
380 case Direction::Prevunique:
381 if (key >= sortKey) {
382 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
383 return;
385 break;
387 default:
388 MOZ_CRASH("Unknown direction type!");
392 const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
393 mRequest->SetLoggingSerialNumber(requestSerialNumber);
395 if constexpr (IsObjectStoreCursor) {
396 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
397 "database(%s).transaction(%s).objectStore(%s)."
398 "cursor(%s).continue(%s)",
399 "IDBCursor.continue(%.0s%.0s%.0s%.0s%.0s)",
400 mTransaction->LoggingSerialNumber(), requestSerialNumber,
401 IDB_LOG_STRINGIFY(mTransaction->Database()),
402 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(mSource),
403 IDB_LOG_STRINGIFY(mDirection), IDB_LOG_STRINGIFY(key));
404 } else {
405 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
406 "database(%s).transaction(%s).objectStore(%s)."
407 "index(%s).cursor(%s).continue(%s)",
408 "IDBCursor.continue(%.0s%.0s%.0s%.0s%.0s%.0s)",
409 mTransaction->LoggingSerialNumber(), requestSerialNumber,
410 IDB_LOG_STRINGIFY(mTransaction->Database()),
411 IDB_LOG_STRINGIFY(*mTransaction),
412 IDB_LOG_STRINGIFY(GetSourceRef().ObjectStore()),
413 IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection),
414 IDB_LOG_STRINGIFY(key));
417 GetTypedBackgroundActorRef().SendContinueInternal(ContinueParams(key), mData);
419 mContinueCalled = true;
422 template <IDBCursor::Type CursorType>
423 void IDBTypedCursor<CursorType>::ContinuePrimaryKey(
424 JSContext* const aCx, JS::Handle<JS::Value> aKey,
425 JS::Handle<JS::Value> aPrimaryKey, ErrorResult& aRv) {
426 AssertIsOnOwningThread();
428 if (!mTransaction->IsActive()) {
429 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
430 return;
433 if (IsSourceDeleted()) {
434 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
435 return;
438 if (IsObjectStoreCursor ||
439 (mDirection != Direction::Next && mDirection != Direction::Prev)) {
440 aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
441 return;
444 if constexpr (!IsObjectStoreCursor) {
445 if (!mHaveValue || mContinueCalled) {
446 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
447 return;
450 Key key;
451 auto result = key.SetFromJSVal(aCx, aKey);
452 if (result.isErr()) {
453 aRv = result.unwrapErr().ExtractErrorResult(
454 InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>);
455 return;
458 if (IsLocaleAware() && !key.IsUnset()) {
459 auto result = key.ToLocaleAwareKey(GetSourceRef().Locale());
460 if (result.isErr()) {
461 aRv.Throw(result.inspectErr());
462 return;
464 key = result.unwrap();
467 if (key.IsUnset()) {
468 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
469 return;
472 Key primaryKey;
473 result = primaryKey.SetFromJSVal(aCx, aPrimaryKey);
474 if (result.isErr()) {
475 aRv = result.unwrapErr().ExtractErrorResult(
476 InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>);
477 return;
480 if (primaryKey.IsUnset()) {
481 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
482 return;
485 const Key& sortKey = mData.GetSortKey(IsLocaleAware());
487 switch (mDirection) {
488 case Direction::Next:
489 if (key < sortKey ||
490 (key == sortKey && primaryKey <= mData.mObjectStoreKey)) {
491 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
492 return;
494 break;
496 case Direction::Prev:
497 if (key > sortKey ||
498 (key == sortKey && primaryKey >= mData.mObjectStoreKey)) {
499 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
500 return;
502 break;
504 default:
505 MOZ_CRASH("Unknown direction type!");
508 const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
509 mRequest->SetLoggingSerialNumber(requestSerialNumber);
511 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
512 "database(%s).transaction(%s).objectStore(%s)."
513 "index(%s).cursor(%s).continuePrimaryKey(%s, %s)",
514 "IDBCursor.continuePrimaryKey(%.0s%.0s%.0s%.0s%.0s%.0s%.0s)",
515 mTransaction->LoggingSerialNumber(), requestSerialNumber,
516 IDB_LOG_STRINGIFY(mTransaction->Database()),
517 IDB_LOG_STRINGIFY(*mTransaction),
518 IDB_LOG_STRINGIFY(&GetSourceObjectStoreRef()),
519 IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection),
520 IDB_LOG_STRINGIFY(key), IDB_LOG_STRINGIFY(primaryKey));
522 GetTypedBackgroundActorRef().SendContinueInternal(
523 ContinuePrimaryKeyParams(key, primaryKey), mData);
525 mContinueCalled = true;
529 template <IDBCursor::Type CursorType>
530 void IDBTypedCursor<CursorType>::Advance(const uint32_t aCount,
531 ErrorResult& aRv) {
532 AssertIsOnOwningThread();
534 if (!aCount) {
535 aRv.ThrowTypeError("0 (Zero) is not a valid advance count.");
536 return;
539 if (!mTransaction->IsActive()) {
540 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
541 return;
544 if (IsSourceDeleted() || !mHaveValue || mContinueCalled) {
545 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
546 return;
549 const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
550 mRequest->SetLoggingSerialNumber(requestSerialNumber);
552 if constexpr (IsObjectStoreCursor) {
553 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
554 "database(%s).transaction(%s).objectStore(%s)."
555 "cursor(%s).advance(%" PRIi32 ")",
556 "IDBCursor.advance(%.0s%.0s%.0s%.0s%" PRIi32 ")",
557 mTransaction->LoggingSerialNumber(), requestSerialNumber,
558 IDB_LOG_STRINGIFY(mTransaction->Database()),
559 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(mSource),
560 IDB_LOG_STRINGIFY(mDirection), aCount);
561 } else {
562 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
563 "database(%s).transaction(%s).objectStore(%s)."
564 "index(%s).cursor(%s).advance(%" PRIi32 ")",
565 "IDBCursor.advance(%.0s%.0s%.0s%.0s%.0s%" PRIi32 ")",
566 mTransaction->LoggingSerialNumber(), requestSerialNumber,
567 IDB_LOG_STRINGIFY(mTransaction->Database()),
568 IDB_LOG_STRINGIFY(*mTransaction),
569 IDB_LOG_STRINGIFY(GetSourceRef().ObjectStore()),
570 IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection), aCount);
573 GetTypedBackgroundActorRef().SendContinueInternal(AdvanceParams(aCount),
574 mData);
576 mContinueCalled = true;
579 template <IDBCursor::Type CursorType>
580 RefPtr<IDBRequest> IDBTypedCursor<CursorType>::Update(
581 JSContext* const aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv) {
582 AssertIsOnOwningThread();
584 if (!mTransaction->IsActive()) {
585 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
586 return nullptr;
589 if (!mTransaction->IsWriteAllowed()) {
590 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
591 return nullptr;
594 if (mTransaction->GetMode() == IDBTransaction::Mode::Cleanup ||
595 IsSourceDeleted() || !mHaveValue || IsKeyOnlyCursor || mContinueCalled) {
596 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
597 return nullptr;
600 if constexpr (!IsKeyOnlyCursor) {
601 MOZ_ASSERT(!mData.mKey.IsUnset());
602 if constexpr (!IsObjectStoreCursor) {
603 MOZ_ASSERT(!mData.mObjectStoreKey.IsUnset());
606 mTransaction->InvalidateCursorCaches();
608 IDBObjectStore::ValueWrapper valueWrapper(aCx, aValue);
610 const Key& primaryKey = mData.GetObjectStoreKey();
612 RefPtr<IDBRequest> request;
614 IDBObjectStore& objectStore = GetSourceObjectStoreRef();
615 if (objectStore.HasValidKeyPath()) {
616 if (!valueWrapper.Clone(aCx)) {
617 aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
618 return nullptr;
621 // Make sure the object given has the correct keyPath value set on it.
622 const KeyPath& keyPath = objectStore.GetKeyPath();
623 Key key;
625 aRv = keyPath.ExtractKey(aCx, valueWrapper.Value(), key);
626 if (aRv.Failed()) {
627 return nullptr;
630 if (key != primaryKey) {
631 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
632 return nullptr;
635 request = objectStore.AddOrPut(aCx, valueWrapper,
636 /* aKey */ JS::UndefinedHandleValue,
637 /* aOverwrite */ true,
638 /* aFromCursor */ true, aRv);
639 if (aRv.Failed()) {
640 return nullptr;
642 } else {
643 JS::Rooted<JS::Value> keyVal(aCx);
644 aRv = primaryKey.ToJSVal(aCx, &keyVal);
645 if (aRv.Failed()) {
646 return nullptr;
649 request = objectStore.AddOrPut(aCx, valueWrapper, keyVal,
650 /* aOverwrite */ true,
651 /* aFromCursor */ true, aRv);
652 if (aRv.Failed()) {
653 return nullptr;
657 request->SetSource(this);
659 if (IsObjectStoreCursor) {
660 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
661 "database(%s).transaction(%s).objectStore(%s)."
662 "cursor(%s).update(%s)",
663 "IDBCursor.update(%.0s%.0s%.0s%.0s%.0s)",
664 mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(),
665 IDB_LOG_STRINGIFY(mTransaction->Database()),
666 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(&objectStore),
667 IDB_LOG_STRINGIFY(mDirection),
668 IDB_LOG_STRINGIFY(&objectStore, primaryKey));
669 } else {
670 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
671 "database(%s).transaction(%s).objectStore(%s)."
672 "index(%s).cursor(%s).update(%s)",
673 "IDBCursor.update(%.0s%.0s%.0s%.0s%.0s%.0s)",
674 mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(),
675 IDB_LOG_STRINGIFY(mTransaction->Database()),
676 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(&objectStore),
677 IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection),
678 IDB_LOG_STRINGIFY(&objectStore, primaryKey));
681 return request;
682 } else {
683 // XXX: Just to work around a bug in gcc, which otherwise claims 'control
684 // reaches end of non-void function', which is not true.
685 return nullptr;
689 template <IDBCursor::Type CursorType>
690 RefPtr<IDBRequest> IDBTypedCursor<CursorType>::Delete(JSContext* const aCx,
691 ErrorResult& aRv) {
692 AssertIsOnOwningThread();
694 if (!mTransaction->IsActive()) {
695 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
696 return nullptr;
699 if (!mTransaction->IsWriteAllowed()) {
700 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
701 return nullptr;
704 if (IsSourceDeleted() || !mHaveValue || IsKeyOnlyCursor || mContinueCalled) {
705 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
706 return nullptr;
709 if constexpr (!IsKeyOnlyCursor) {
710 MOZ_ASSERT(!mData.mKey.IsUnset());
712 mTransaction->InvalidateCursorCaches();
714 const Key& primaryKey = mData.GetObjectStoreKey();
716 JS::Rooted<JS::Value> key(aCx);
717 aRv = primaryKey.ToJSVal(aCx, &key);
718 if (NS_WARN_IF(aRv.Failed())) {
719 return nullptr;
722 auto& objectStore = GetSourceObjectStoreRef();
723 RefPtr<IDBRequest> request =
724 objectStore.DeleteInternal(aCx, key, /* aFromCursor */ true, aRv);
725 if (aRv.Failed()) {
726 return nullptr;
729 request->SetSource(this);
731 if (IsObjectStoreCursor) {
732 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
733 "database(%s).transaction(%s).objectStore(%s)."
734 "cursor(%s).delete(%s)",
735 "IDBCursor.delete(%.0s%.0s%.0s%.0s%.0s)",
736 mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(),
737 IDB_LOG_STRINGIFY(mTransaction->Database()),
738 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(&objectStore),
739 IDB_LOG_STRINGIFY(mDirection),
740 IDB_LOG_STRINGIFY(&objectStore, primaryKey));
741 } else {
742 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
743 "database(%s).transaction(%s).objectStore(%s)."
744 "index(%s).cursor(%s).delete(%s)",
745 "IDBCursor.delete(%.0s%.0s%.0s%.0s%.0s%.0s)",
746 mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(),
747 IDB_LOG_STRINGIFY(mTransaction->Database()),
748 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(&objectStore),
749 IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection),
750 IDB_LOG_STRINGIFY(&objectStore, primaryKey));
753 return request;
754 } else {
755 // XXX: Just to work around a bug in gcc, which otherwise claims 'control
756 // reaches end of non-void function', which is not true.
757 return nullptr;
761 template <IDBCursor::Type CursorType>
762 void IDBTypedCursor<CursorType>::Reset(CursorData<CursorType>&& aCursorData) {
763 this->AssertIsOnOwningThread();
765 Reset();
767 mData = std::move(aCursorData);
769 mHaveValue = !mData.mKey.IsUnset();
772 template <IDBCursor::Type CursorType>
773 void IDBTypedCursor<CursorType>::InvalidateCachedResponses() {
774 AssertIsOnOwningThread();
776 // TODO: Can mBackgroundActor actually be empty at this point?
777 if (mBackgroundActor) {
778 GetTypedBackgroundActorRef().InvalidateCachedResponses();
782 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor)
783 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor)
785 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor)
786 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
787 NS_INTERFACE_MAP_ENTRY(nsISupports)
788 NS_INTERFACE_MAP_END
790 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor)
792 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor)
793 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
794 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
796 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
797 MOZ_ASSERT_IF(!tmp->mHaveCachedKey, tmp->mCachedKey.isUndefined());
798 MOZ_ASSERT_IF(!tmp->mHaveCachedPrimaryKey,
799 tmp->mCachedPrimaryKey.isUndefined());
800 MOZ_ASSERT_IF(!tmp->mHaveCachedValue, tmp->mCachedValue.isUndefined());
802 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
803 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKey)
804 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedPrimaryKey)
805 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedValue)
806 NS_IMPL_CYCLE_COLLECTION_TRACE_END
808 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
809 // Unlinking is done in the subclasses.
810 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
812 // Don't unlink mRequest or mSource in
813 // NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED!
814 #define NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS_METHODS(_subclassName) \
815 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_subclassName, IDBCursor) \
816 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource) \
817 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \
819 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_subclassName, IDBCursor) \
820 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
821 tmp->DropJSObjects(); \
822 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
824 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(_subclassName) \
825 NS_INTERFACE_MAP_END_INHERITING(IDBCursor) \
827 NS_IMPL_ADDREF_INHERITED(_subclassName, IDBCursor) \
828 NS_IMPL_RELEASE_INHERITED(_subclassName, IDBCursor)
830 #define NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(_subclassName) \
831 NS_IMPL_CYCLE_COLLECTION_MULTI_ZONE_JSHOLDER_CLASS(_subclassName) \
832 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS_METHODS(_subclassName)
834 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBObjectStoreCursor)
835 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBObjectStoreKeyCursor)
836 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBIndexCursor)
837 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBIndexKeyCursor)
839 template <IDBCursor::Type CursorType>
840 JSObject* IDBTypedCursor<CursorType>::WrapObject(
841 JSContext* const aCx, JS::Handle<JSObject*> aGivenProto) {
842 AssertIsOnOwningThread();
844 return IsKeyOnlyCursor
845 ? IDBCursor_Binding::Wrap(aCx, this, aGivenProto)
846 : IDBCursorWithValue_Binding::Wrap(aCx, this, aGivenProto);
849 template <IDBCursor::Type CursorType>
850 template <typename... DataArgs>
851 IDBTypedCursor<CursorType>::IDBTypedCursor(
852 indexedDB::BackgroundCursorChild<CursorType>* const aBackgroundActor,
853 DataArgs&&... aDataArgs)
854 : IDBCursor{aBackgroundActor},
855 mData{std::forward<DataArgs>(aDataArgs)...},
856 mSource(aBackgroundActor->GetSource()) {}
858 template <IDBCursor::Type CursorType>
859 bool IDBTypedCursor<CursorType>::IsLocaleAware() const {
860 if constexpr (IsObjectStoreCursor) {
861 return false;
862 } else {
863 return !GetSourceRef().Locale().IsEmpty();
867 template class IDBTypedCursor<IDBCursorType::ObjectStore>;
868 template class IDBTypedCursor<IDBCursorType::ObjectStoreKey>;
869 template class IDBTypedCursor<IDBCursorType::Index>;
870 template class IDBTypedCursor<IDBCursorType::IndexKey>;
872 } // namespace mozilla::dom