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/. */
9 #include "IDBDatabase.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"
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),
42 mContinueCalled(false),
44 MOZ_ASSERT(aBackgroundActor
);
45 aBackgroundActor
->AssertIsOnOwningThread();
48 mTransaction
->RegisterCursor(*this);
51 template <IDBCursor::Type CursorType
>
52 IDBTypedCursor
<CursorType
>::~IDBTypedCursor() {
53 AssertIsOnOwningThread();
55 mTransaction
->UnregisterCursor(*this);
59 if (mBackgroundActor
) {
60 (*mBackgroundActor
)->SendDeleteMeInternal();
61 MOZ_ASSERT(!mBackgroundActor
, "SendDeleteMeInternal should have cleared!");
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
));
78 RefPtr
<IDBObjectStoreKeyCursor
> IDBCursor::Create(
79 BackgroundCursorChild
<Type::ObjectStoreKey
>* const aBackgroundActor
,
81 MOZ_ASSERT(aBackgroundActor
);
82 aBackgroundActor
->AssertIsOnOwningThread();
83 MOZ_ASSERT(!aKey
.IsUnset());
85 return MakeRefPtr
<IDBObjectStoreKeyCursor
>(aBackgroundActor
, std::move(aKey
));
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
));
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
),
113 std::move(aPrimaryKey
));
118 void IDBCursor::AssertIsOnOwningThread() const {
119 MOZ_ASSERT(mTransaction
);
120 mTransaction
->AssertIsOnOwningThread();
125 template <IDBCursor::Type CursorType
>
126 void IDBTypedCursor
<CursorType
>::DropJSObjects() {
127 AssertIsOnOwningThread();
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
) {
150 if (GetSourceRef().IsDeleted()) {
154 const auto* const res
= GetSourceRef().ObjectStore();
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;
174 mContinueCalled
= false;
177 template <IDBCursor::Type CursorType
>
178 void IDBTypedCursor
<CursorType
>::Reset() {
179 AssertIsOnOwningThread();
181 if constexpr (!IsKeyOnlyCursor
) {
182 IDBObjectStore::ClearCloneReadInfo(mData
.mCloneInfo
);
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
;
212 MOZ_CRASH("Bad direction!");
216 RefPtr
<IDBRequest
> IDBCursor::Request() const {
217 AssertIsOnOwningThread();
221 template <IDBCursor::Type CursorType
>
222 void IDBTypedCursor
<CursorType
>::GetSource(
223 OwningIDBObjectStoreOrIDBIndex
& aSource
) const {
224 AssertIsOnOwningThread();
226 if constexpr (IsObjectStoreCursor
) {
227 aSource
.SetAsIDBObjectStore() = mSource
;
229 aSource
.SetAsIDBIndex() = mSource
;
233 template <IDBCursor::Type CursorType
>
234 void IDBTypedCursor
<CursorType
>::GetKey(JSContext
* const aCx
,
235 JS::MutableHandle
<JS::Value
> aResult
,
237 AssertIsOnOwningThread();
238 MOZ_ASSERT(!mData
.mKey
.IsUnset() || !mHaveValue
);
241 aResult
.setUndefined();
245 if (!mHaveCachedKey
) {
247 mozilla::HoldJSObjects(this);
251 aRv
= mData
.mKey
.ToJSVal(aCx
, mCachedKey
);
252 if (NS_WARN_IF(aRv
.Failed())) {
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
,
266 AssertIsOnOwningThread();
269 aResult
.setUndefined();
273 if (!mHaveCachedPrimaryKey
) {
275 mozilla::HoldJSObjects(this);
279 const Key
& key
= mData
.GetObjectStoreKey();
281 MOZ_ASSERT(!key
.IsUnset());
283 aRv
= key
.ToJSVal(aCx
, mCachedPrimaryKey
);
284 if (NS_WARN_IF(aRv
.Failed())) {
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
,
298 AssertIsOnOwningThread();
300 if constexpr (!IsKeyOnlyCursor
) {
302 aResult
.setUndefined();
306 if (!mHaveCachedValue
) {
308 mozilla::HoldJSObjects(this);
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
);
319 // XXX This seems redundant, sine mData.mCloneInfo is moved above.
320 IDBObjectStore::ClearCloneReadInfo(mData
.mCloneInfo
);
323 mHaveCachedValue
= true;
326 aResult
.set(mCachedValue
);
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
,
336 AssertIsOnOwningThread();
338 if (!mTransaction
->IsActive()) {
339 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
343 if (IsSourceDeleted() || !mHaveValue
|| mContinueCalled
) {
344 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
349 auto result
= key
.SetFromJSVal(aCx
, aKey
);
350 if (result
.isErr()) {
351 aRv
= result
.unwrapErr().ExtractErrorResult(
352 InvalidMapsTo
<NS_ERROR_DOM_INDEXEDDB_DATA_ERR
>);
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());
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
);
379 case Direction::Prev
:
380 case Direction::Prevunique
:
381 if (key
>= sortKey
) {
382 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
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
));
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
);
433 if (IsSourceDeleted()) {
434 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
438 if (IsObjectStoreCursor
||
439 (mDirection
!= Direction::Next
&& mDirection
!= Direction::Prev
)) {
440 aRv
.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
444 if constexpr (!IsObjectStoreCursor
) {
445 if (!mHaveValue
|| mContinueCalled
) {
446 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
451 auto result
= key
.SetFromJSVal(aCx
, aKey
);
452 if (result
.isErr()) {
453 aRv
= result
.unwrapErr().ExtractErrorResult(
454 InvalidMapsTo
<NS_ERROR_DOM_INDEXEDDB_DATA_ERR
>);
458 if (IsLocaleAware() && !key
.IsUnset()) {
459 auto result
= key
.ToLocaleAwareKey(GetSourceRef().Locale());
460 if (result
.isErr()) {
461 aRv
.Throw(result
.inspectErr());
464 key
= result
.unwrap();
468 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
473 result
= primaryKey
.SetFromJSVal(aCx
, aPrimaryKey
);
474 if (result
.isErr()) {
475 aRv
= result
.unwrapErr().ExtractErrorResult(
476 InvalidMapsTo
<NS_ERROR_DOM_INDEXEDDB_DATA_ERR
>);
480 if (primaryKey
.IsUnset()) {
481 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
485 const Key
& sortKey
= mData
.GetSortKey(IsLocaleAware());
487 switch (mDirection
) {
488 case Direction::Next
:
490 (key
== sortKey
&& primaryKey
<= mData
.mObjectStoreKey
)) {
491 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
496 case Direction::Prev
:
498 (key
== sortKey
&& primaryKey
>= mData
.mObjectStoreKey
)) {
499 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
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
,
532 AssertIsOnOwningThread();
535 aRv
.ThrowTypeError("0 (Zero) is not a valid advance count.");
539 if (!mTransaction
->IsActive()) {
540 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
544 if (IsSourceDeleted() || !mHaveValue
|| mContinueCalled
) {
545 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
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
);
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
),
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
);
589 if (!mTransaction
->IsWriteAllowed()) {
590 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR
);
594 if (mTransaction
->GetMode() == IDBTransaction::Mode::Cleanup
||
595 IsSourceDeleted() || !mHaveValue
|| IsKeyOnlyCursor
|| mContinueCalled
) {
596 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
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
);
621 // Make sure the object given has the correct keyPath value set on it.
622 const KeyPath
& keyPath
= objectStore
.GetKeyPath();
625 aRv
= keyPath
.ExtractKey(aCx
, valueWrapper
.Value(), key
);
630 if (key
!= primaryKey
) {
631 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
635 request
= objectStore
.AddOrPut(aCx
, valueWrapper
,
636 /* aKey */ JS::UndefinedHandleValue
,
637 /* aOverwrite */ true,
638 /* aFromCursor */ true, aRv
);
643 JS::Rooted
<JS::Value
> keyVal(aCx
);
644 aRv
= primaryKey
.ToJSVal(aCx
, &keyVal
);
649 request
= objectStore
.AddOrPut(aCx
, valueWrapper
, keyVal
,
650 /* aOverwrite */ true,
651 /* aFromCursor */ true, aRv
);
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
));
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
));
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.
689 template <IDBCursor::Type CursorType
>
690 RefPtr
<IDBRequest
> IDBTypedCursor
<CursorType
>::Delete(JSContext
* const aCx
,
692 AssertIsOnOwningThread();
694 if (!mTransaction
->IsActive()) {
695 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
699 if (!mTransaction
->IsWriteAllowed()) {
700 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR
);
704 if (IsSourceDeleted() || !mHaveValue
|| IsKeyOnlyCursor
|| mContinueCalled
) {
705 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
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())) {
722 auto& objectStore
= GetSourceObjectStoreRef();
723 RefPtr
<IDBRequest
> request
=
724 objectStore
.DeleteInternal(aCx
, key
, /* aFromCursor */ true, aRv
);
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
));
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
));
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.
761 template <IDBCursor::Type CursorType
>
762 void IDBTypedCursor
<CursorType
>::Reset(CursorData
<CursorType
>&& aCursorData
) {
763 this->AssertIsOnOwningThread();
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
)
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
) {
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