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!");
64 // Let's explicitly not leave any dangling CheckedUnsafePtr.
65 mTransaction
= nullptr;
69 RefPtr
<IDBObjectStoreCursor
> IDBCursor::Create(
70 BackgroundCursorChild
<Type::ObjectStore
>* const aBackgroundActor
, Key aKey
,
71 StructuredCloneReadInfoChild
&& aCloneInfo
) {
72 MOZ_ASSERT(aBackgroundActor
);
73 aBackgroundActor
->AssertIsOnOwningThread();
74 MOZ_ASSERT(!aKey
.IsUnset());
76 return MakeRefPtr
<IDBObjectStoreCursor
>(aBackgroundActor
, std::move(aKey
),
77 std::move(aCloneInfo
));
81 RefPtr
<IDBObjectStoreKeyCursor
> IDBCursor::Create(
82 BackgroundCursorChild
<Type::ObjectStoreKey
>* const aBackgroundActor
,
84 MOZ_ASSERT(aBackgroundActor
);
85 aBackgroundActor
->AssertIsOnOwningThread();
86 MOZ_ASSERT(!aKey
.IsUnset());
88 return MakeRefPtr
<IDBObjectStoreKeyCursor
>(aBackgroundActor
, std::move(aKey
));
92 RefPtr
<IDBIndexCursor
> IDBCursor::Create(
93 BackgroundCursorChild
<Type::Index
>* const aBackgroundActor
, Key aKey
,
94 Key aSortKey
, Key aPrimaryKey
, StructuredCloneReadInfoChild
&& aCloneInfo
) {
95 MOZ_ASSERT(aBackgroundActor
);
96 aBackgroundActor
->AssertIsOnOwningThread();
97 MOZ_ASSERT(!aKey
.IsUnset());
98 MOZ_ASSERT(!aPrimaryKey
.IsUnset());
100 return MakeRefPtr
<IDBIndexCursor
>(aBackgroundActor
, std::move(aKey
),
101 std::move(aSortKey
), std::move(aPrimaryKey
),
102 std::move(aCloneInfo
));
106 RefPtr
<IDBIndexKeyCursor
> IDBCursor::Create(
107 BackgroundCursorChild
<Type::IndexKey
>* const aBackgroundActor
, Key aKey
,
108 Key aSortKey
, Key aPrimaryKey
) {
109 MOZ_ASSERT(aBackgroundActor
);
110 aBackgroundActor
->AssertIsOnOwningThread();
111 MOZ_ASSERT(!aKey
.IsUnset());
112 MOZ_ASSERT(!aPrimaryKey
.IsUnset());
114 return MakeRefPtr
<IDBIndexKeyCursor
>(aBackgroundActor
, std::move(aKey
),
116 std::move(aPrimaryKey
));
121 void IDBCursor::AssertIsOnOwningThread() const {
122 MOZ_ASSERT(mTransaction
);
123 mTransaction
->AssertIsOnOwningThread();
128 template <IDBCursor::Type CursorType
>
129 void IDBTypedCursor
<CursorType
>::DropJSObjects() {
130 AssertIsOnOwningThread();
140 mozilla::DropJSObjects(this);
143 template <IDBCursor::Type CursorType
>
144 bool IDBTypedCursor
<CursorType
>::IsSourceDeleted() const {
145 AssertIsOnOwningThread();
146 MOZ_ASSERT(mTransaction
);
147 MOZ_ASSERT(mTransaction
->IsActive());
149 const auto* const sourceObjectStore
= [this]() -> const IDBObjectStore
* {
150 if constexpr (IsObjectStoreCursor
) {
153 if (GetSourceRef().IsDeleted()) {
157 const auto* const res
= GetSourceRef().ObjectStore();
163 return !sourceObjectStore
|| sourceObjectStore
->IsDeleted();
166 void IDBCursor::ResetBase() {
167 AssertIsOnOwningThread();
169 mCachedKey
.setUndefined();
170 mCachedPrimaryKey
.setUndefined();
171 mCachedValue
.setUndefined();
173 mHaveCachedKey
= false;
174 mHaveCachedPrimaryKey
= false;
175 mHaveCachedValue
= false;
177 mContinueCalled
= false;
180 template <IDBCursor::Type CursorType
>
181 void IDBTypedCursor
<CursorType
>::Reset() {
182 AssertIsOnOwningThread();
184 if constexpr (!IsKeyOnlyCursor
) {
185 IDBObjectStore::ClearCloneReadInfo(mData
.mCloneInfo
);
191 nsIGlobalObject
* IDBCursor::GetParentObject() const {
192 AssertIsOnOwningThread();
193 MOZ_ASSERT(mTransaction
);
195 return mTransaction
->GetParentObject();
198 IDBCursorDirection
IDBCursor::GetDirection() const {
199 AssertIsOnOwningThread();
201 switch (mDirection
) {
202 case Direction::Next
:
203 return IDBCursorDirection::Next
;
205 case Direction::Nextunique
:
206 return IDBCursorDirection::Nextunique
;
208 case Direction::Prev
:
209 return IDBCursorDirection::Prev
;
211 case Direction::Prevunique
:
212 return IDBCursorDirection::Prevunique
;
215 MOZ_CRASH("Bad direction!");
219 RefPtr
<IDBRequest
> IDBCursor::Request() const {
220 AssertIsOnOwningThread();
224 template <IDBCursor::Type CursorType
>
225 void IDBTypedCursor
<CursorType
>::GetSource(
226 OwningIDBObjectStoreOrIDBIndex
& aSource
) const {
227 AssertIsOnOwningThread();
229 if constexpr (IsObjectStoreCursor
) {
230 aSource
.SetAsIDBObjectStore() = mSource
;
232 aSource
.SetAsIDBIndex() = mSource
;
236 template <IDBCursor::Type CursorType
>
237 void IDBTypedCursor
<CursorType
>::GetKey(JSContext
* const aCx
,
238 JS::MutableHandle
<JS::Value
> aResult
,
240 AssertIsOnOwningThread();
241 MOZ_ASSERT(!mData
.mKey
.IsUnset() || !mHaveValue
);
244 aResult
.setUndefined();
248 if (!mHaveCachedKey
) {
250 mozilla::HoldJSObjects(this);
254 aRv
= mData
.mKey
.ToJSVal(aCx
, mCachedKey
);
255 if (NS_WARN_IF(aRv
.Failed())) {
259 mHaveCachedKey
= true;
262 aResult
.set(mCachedKey
);
265 template <IDBCursor::Type CursorType
>
266 void IDBTypedCursor
<CursorType
>::GetPrimaryKey(
267 JSContext
* const aCx
, JS::MutableHandle
<JS::Value
> aResult
,
269 AssertIsOnOwningThread();
272 aResult
.setUndefined();
276 if (!mHaveCachedPrimaryKey
) {
278 mozilla::HoldJSObjects(this);
282 const Key
& key
= mData
.GetObjectStoreKey();
284 MOZ_ASSERT(!key
.IsUnset());
286 aRv
= key
.ToJSVal(aCx
, mCachedPrimaryKey
);
287 if (NS_WARN_IF(aRv
.Failed())) {
291 mHaveCachedPrimaryKey
= true;
294 aResult
.set(mCachedPrimaryKey
);
297 template <IDBCursor::Type CursorType
>
298 void IDBTypedCursor
<CursorType
>::GetValue(JSContext
* const aCx
,
299 JS::MutableHandle
<JS::Value
> aResult
,
301 AssertIsOnOwningThread();
303 if constexpr (!IsKeyOnlyCursor
) {
305 aResult
.setUndefined();
309 if (!mHaveCachedValue
) {
311 mozilla::HoldJSObjects(this);
315 JS::Rooted
<JS::Value
> val(aCx
);
316 if (NS_WARN_IF(!IDBObjectStore::DeserializeValue(
317 aCx
, std::move(mData
.mCloneInfo
), &val
))) {
318 aRv
.Throw(NS_ERROR_DOM_DATA_CLONE_ERR
);
322 // XXX This seems redundant, sine mData.mCloneInfo is moved above.
323 IDBObjectStore::ClearCloneReadInfo(mData
.mCloneInfo
);
326 mHaveCachedValue
= true;
329 aResult
.set(mCachedValue
);
331 MOZ_CRASH("This shouldn't be callable on a key-only cursor.");
335 template <IDBCursor::Type CursorType
>
336 void IDBTypedCursor
<CursorType
>::Continue(JSContext
* const aCx
,
337 JS::Handle
<JS::Value
> aKey
,
339 AssertIsOnOwningThread();
341 if (!mTransaction
->IsActive()) {
342 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
346 if (IsSourceDeleted() || !mHaveValue
|| mContinueCalled
) {
347 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
352 auto result
= key
.SetFromJSVal(aCx
, aKey
);
353 if (result
.isErr()) {
354 aRv
= result
.unwrapErr().ExtractErrorResult(
355 InvalidMapsTo
<NS_ERROR_DOM_INDEXEDDB_DATA_ERR
>);
359 if constexpr (!IsObjectStoreCursor
) {
360 if (IsLocaleAware() && !key
.IsUnset()) {
361 auto result
= key
.ToLocaleAwareKey(GetSourceRef().Locale());
362 if (result
.isErr()) {
363 aRv
.Throw(result
.inspectErr());
366 key
= result
.unwrap();
370 const Key
& sortKey
= mData
.GetSortKey(IsLocaleAware());
372 if (!key
.IsUnset()) {
373 switch (mDirection
) {
374 case Direction::Next
:
375 case Direction::Nextunique
:
376 if (key
<= sortKey
) {
377 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
382 case Direction::Prev
:
383 case Direction::Prevunique
:
384 if (key
>= sortKey
) {
385 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
391 MOZ_CRASH("Unknown direction type!");
395 const uint64_t requestSerialNumber
= IDBRequest::NextSerialNumber();
396 mRequest
->SetLoggingSerialNumber(requestSerialNumber
);
398 if constexpr (IsObjectStoreCursor
) {
399 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
400 "database(%s).transaction(%s).objectStore(%s)."
401 "cursor(%s).continue(%s)",
402 "IDBCursor.continue(%.0s%.0s%.0s%.0s%.0s)",
403 mTransaction
->LoggingSerialNumber(), requestSerialNumber
,
404 IDB_LOG_STRINGIFY(mTransaction
->Database()),
405 IDB_LOG_STRINGIFY(*mTransaction
), IDB_LOG_STRINGIFY(mSource
),
406 IDB_LOG_STRINGIFY(mDirection
), IDB_LOG_STRINGIFY(key
));
408 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
409 "database(%s).transaction(%s).objectStore(%s)."
410 "index(%s).cursor(%s).continue(%s)",
411 "IDBCursor.continue(%.0s%.0s%.0s%.0s%.0s%.0s)",
412 mTransaction
->LoggingSerialNumber(), requestSerialNumber
,
413 IDB_LOG_STRINGIFY(mTransaction
->Database()),
414 IDB_LOG_STRINGIFY(*mTransaction
),
415 IDB_LOG_STRINGIFY(GetSourceRef().ObjectStore()),
416 IDB_LOG_STRINGIFY(mSource
), IDB_LOG_STRINGIFY(mDirection
),
417 IDB_LOG_STRINGIFY(key
));
420 GetTypedBackgroundActorRef().SendContinueInternal(ContinueParams(key
), mData
);
422 mContinueCalled
= true;
425 template <IDBCursor::Type CursorType
>
426 void IDBTypedCursor
<CursorType
>::ContinuePrimaryKey(
427 JSContext
* const aCx
, JS::Handle
<JS::Value
> aKey
,
428 JS::Handle
<JS::Value
> aPrimaryKey
, ErrorResult
& aRv
) {
429 AssertIsOnOwningThread();
431 if (!mTransaction
->IsActive()) {
432 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
436 if (IsSourceDeleted()) {
437 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
441 if (IsObjectStoreCursor
||
442 (mDirection
!= Direction::Next
&& mDirection
!= Direction::Prev
)) {
443 aRv
.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
447 if constexpr (!IsObjectStoreCursor
) {
448 if (!mHaveValue
|| mContinueCalled
) {
449 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
454 auto result
= key
.SetFromJSVal(aCx
, aKey
);
455 if (result
.isErr()) {
456 aRv
= result
.unwrapErr().ExtractErrorResult(
457 InvalidMapsTo
<NS_ERROR_DOM_INDEXEDDB_DATA_ERR
>);
461 if (IsLocaleAware() && !key
.IsUnset()) {
462 auto result
= key
.ToLocaleAwareKey(GetSourceRef().Locale());
463 if (result
.isErr()) {
464 aRv
.Throw(result
.inspectErr());
467 key
= result
.unwrap();
471 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
476 result
= primaryKey
.SetFromJSVal(aCx
, aPrimaryKey
);
477 if (result
.isErr()) {
478 aRv
= result
.unwrapErr().ExtractErrorResult(
479 InvalidMapsTo
<NS_ERROR_DOM_INDEXEDDB_DATA_ERR
>);
483 if (primaryKey
.IsUnset()) {
484 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
488 const Key
& sortKey
= mData
.GetSortKey(IsLocaleAware());
490 switch (mDirection
) {
491 case Direction::Next
:
493 (key
== sortKey
&& primaryKey
<= mData
.mObjectStoreKey
)) {
494 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
499 case Direction::Prev
:
501 (key
== sortKey
&& primaryKey
>= mData
.mObjectStoreKey
)) {
502 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
508 MOZ_CRASH("Unknown direction type!");
511 const uint64_t requestSerialNumber
= IDBRequest::NextSerialNumber();
512 mRequest
->SetLoggingSerialNumber(requestSerialNumber
);
514 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
515 "database(%s).transaction(%s).objectStore(%s)."
516 "index(%s).cursor(%s).continuePrimaryKey(%s, %s)",
517 "IDBCursor.continuePrimaryKey(%.0s%.0s%.0s%.0s%.0s%.0s%.0s)",
518 mTransaction
->LoggingSerialNumber(), requestSerialNumber
,
519 IDB_LOG_STRINGIFY(mTransaction
->Database()),
520 IDB_LOG_STRINGIFY(*mTransaction
),
521 IDB_LOG_STRINGIFY(&GetSourceObjectStoreRef()),
522 IDB_LOG_STRINGIFY(mSource
), IDB_LOG_STRINGIFY(mDirection
),
523 IDB_LOG_STRINGIFY(key
), IDB_LOG_STRINGIFY(primaryKey
));
525 GetTypedBackgroundActorRef().SendContinueInternal(
526 ContinuePrimaryKeyParams(key
, primaryKey
), mData
);
528 mContinueCalled
= true;
532 template <IDBCursor::Type CursorType
>
533 void IDBTypedCursor
<CursorType
>::Advance(const uint32_t aCount
,
535 AssertIsOnOwningThread();
538 aRv
.ThrowTypeError("0 (Zero) is not a valid advance count.");
542 if (!mTransaction
->IsActive()) {
543 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
547 if (IsSourceDeleted() || !mHaveValue
|| mContinueCalled
) {
548 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
552 const uint64_t requestSerialNumber
= IDBRequest::NextSerialNumber();
553 mRequest
->SetLoggingSerialNumber(requestSerialNumber
);
555 if constexpr (IsObjectStoreCursor
) {
556 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
557 "database(%s).transaction(%s).objectStore(%s)."
558 "cursor(%s).advance(%" PRIi32
")",
559 "IDBCursor.advance(%.0s%.0s%.0s%.0s%" PRIi32
")",
560 mTransaction
->LoggingSerialNumber(), requestSerialNumber
,
561 IDB_LOG_STRINGIFY(mTransaction
->Database()),
562 IDB_LOG_STRINGIFY(*mTransaction
), IDB_LOG_STRINGIFY(mSource
),
563 IDB_LOG_STRINGIFY(mDirection
), aCount
);
565 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
566 "database(%s).transaction(%s).objectStore(%s)."
567 "index(%s).cursor(%s).advance(%" PRIi32
")",
568 "IDBCursor.advance(%.0s%.0s%.0s%.0s%.0s%" PRIi32
")",
569 mTransaction
->LoggingSerialNumber(), requestSerialNumber
,
570 IDB_LOG_STRINGIFY(mTransaction
->Database()),
571 IDB_LOG_STRINGIFY(*mTransaction
),
572 IDB_LOG_STRINGIFY(GetSourceRef().ObjectStore()),
573 IDB_LOG_STRINGIFY(mSource
), IDB_LOG_STRINGIFY(mDirection
), aCount
);
576 GetTypedBackgroundActorRef().SendContinueInternal(AdvanceParams(aCount
),
579 mContinueCalled
= true;
582 template <IDBCursor::Type CursorType
>
583 RefPtr
<IDBRequest
> IDBTypedCursor
<CursorType
>::Update(
584 JSContext
* const aCx
, JS::Handle
<JS::Value
> aValue
, ErrorResult
& aRv
) {
585 AssertIsOnOwningThread();
587 if (!mTransaction
->IsActive()) {
588 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
592 if (!mTransaction
->IsWriteAllowed()) {
593 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR
);
597 if (mTransaction
->GetMode() == IDBTransaction::Mode::Cleanup
||
598 IsSourceDeleted() || !mHaveValue
|| IsKeyOnlyCursor
|| mContinueCalled
) {
599 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
603 if constexpr (!IsKeyOnlyCursor
) {
604 MOZ_ASSERT(!mData
.mKey
.IsUnset());
605 if constexpr (!IsObjectStoreCursor
) {
606 MOZ_ASSERT(!mData
.mObjectStoreKey
.IsUnset());
609 mTransaction
->InvalidateCursorCaches();
611 IDBObjectStore::ValueWrapper
valueWrapper(aCx
, aValue
);
613 const Key
& primaryKey
= mData
.GetObjectStoreKey();
615 RefPtr
<IDBRequest
> request
;
617 IDBObjectStore
& objectStore
= GetSourceObjectStoreRef();
618 if (objectStore
.HasValidKeyPath()) {
619 if (!valueWrapper
.Clone(aCx
)) {
620 aRv
.Throw(NS_ERROR_DOM_DATA_CLONE_ERR
);
624 // Make sure the object given has the correct keyPath value set on it.
625 const KeyPath
& keyPath
= objectStore
.GetKeyPath();
628 aRv
= keyPath
.ExtractKey(aCx
, valueWrapper
.Value(), key
);
633 if (key
!= primaryKey
) {
634 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
638 request
= objectStore
.AddOrPut(aCx
, valueWrapper
,
639 /* aKey */ JS::UndefinedHandleValue
,
640 /* aOverwrite */ true,
641 /* aFromCursor */ true, aRv
);
646 JS::Rooted
<JS::Value
> keyVal(aCx
);
647 aRv
= primaryKey
.ToJSVal(aCx
, &keyVal
);
652 request
= objectStore
.AddOrPut(aCx
, valueWrapper
, keyVal
,
653 /* aOverwrite */ true,
654 /* aFromCursor */ true, aRv
);
660 request
->SetSource(this);
662 if (IsObjectStoreCursor
) {
663 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
664 "database(%s).transaction(%s).objectStore(%s)."
665 "cursor(%s).update(%s)",
666 "IDBCursor.update(%.0s%.0s%.0s%.0s%.0s)",
667 mTransaction
->LoggingSerialNumber(), request
->LoggingSerialNumber(),
668 IDB_LOG_STRINGIFY(mTransaction
->Database()),
669 IDB_LOG_STRINGIFY(*mTransaction
), IDB_LOG_STRINGIFY(&objectStore
),
670 IDB_LOG_STRINGIFY(mDirection
),
671 IDB_LOG_STRINGIFY(&objectStore
, primaryKey
));
673 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
674 "database(%s).transaction(%s).objectStore(%s)."
675 "index(%s).cursor(%s).update(%s)",
676 "IDBCursor.update(%.0s%.0s%.0s%.0s%.0s%.0s)",
677 mTransaction
->LoggingSerialNumber(), request
->LoggingSerialNumber(),
678 IDB_LOG_STRINGIFY(mTransaction
->Database()),
679 IDB_LOG_STRINGIFY(*mTransaction
), IDB_LOG_STRINGIFY(&objectStore
),
680 IDB_LOG_STRINGIFY(mSource
), IDB_LOG_STRINGIFY(mDirection
),
681 IDB_LOG_STRINGIFY(&objectStore
, primaryKey
));
686 // XXX: Just to work around a bug in gcc, which otherwise claims 'control
687 // reaches end of non-void function', which is not true.
692 template <IDBCursor::Type CursorType
>
693 RefPtr
<IDBRequest
> IDBTypedCursor
<CursorType
>::Delete(JSContext
* const aCx
,
695 AssertIsOnOwningThread();
697 if (!mTransaction
->IsActive()) {
698 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
702 if (!mTransaction
->IsWriteAllowed()) {
703 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR
);
707 if (IsSourceDeleted() || !mHaveValue
|| IsKeyOnlyCursor
|| mContinueCalled
) {
708 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
712 if constexpr (!IsKeyOnlyCursor
) {
713 MOZ_ASSERT(!mData
.mKey
.IsUnset());
715 mTransaction
->InvalidateCursorCaches();
717 const Key
& primaryKey
= mData
.GetObjectStoreKey();
719 JS::Rooted
<JS::Value
> key(aCx
);
720 aRv
= primaryKey
.ToJSVal(aCx
, &key
);
721 if (NS_WARN_IF(aRv
.Failed())) {
725 auto& objectStore
= GetSourceObjectStoreRef();
726 RefPtr
<IDBRequest
> request
=
727 objectStore
.DeleteInternal(aCx
, key
, /* aFromCursor */ true, aRv
);
732 request
->SetSource(this);
734 if (IsObjectStoreCursor
) {
735 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
736 "database(%s).transaction(%s).objectStore(%s)."
737 "cursor(%s).delete(%s)",
738 "IDBCursor.delete(%.0s%.0s%.0s%.0s%.0s)",
739 mTransaction
->LoggingSerialNumber(), request
->LoggingSerialNumber(),
740 IDB_LOG_STRINGIFY(mTransaction
->Database()),
741 IDB_LOG_STRINGIFY(*mTransaction
), IDB_LOG_STRINGIFY(&objectStore
),
742 IDB_LOG_STRINGIFY(mDirection
),
743 IDB_LOG_STRINGIFY(&objectStore
, primaryKey
));
745 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
746 "database(%s).transaction(%s).objectStore(%s)."
747 "index(%s).cursor(%s).delete(%s)",
748 "IDBCursor.delete(%.0s%.0s%.0s%.0s%.0s%.0s)",
749 mTransaction
->LoggingSerialNumber(), request
->LoggingSerialNumber(),
750 IDB_LOG_STRINGIFY(mTransaction
->Database()),
751 IDB_LOG_STRINGIFY(*mTransaction
), IDB_LOG_STRINGIFY(&objectStore
),
752 IDB_LOG_STRINGIFY(mSource
), IDB_LOG_STRINGIFY(mDirection
),
753 IDB_LOG_STRINGIFY(&objectStore
, primaryKey
));
758 // XXX: Just to work around a bug in gcc, which otherwise claims 'control
759 // reaches end of non-void function', which is not true.
764 template <IDBCursor::Type CursorType
>
765 void IDBTypedCursor
<CursorType
>::Reset(CursorData
<CursorType
>&& aCursorData
) {
766 this->AssertIsOnOwningThread();
770 mData
= std::move(aCursorData
);
772 mHaveValue
= !mData
.mKey
.IsUnset();
775 template <IDBCursor::Type CursorType
>
776 void IDBTypedCursor
<CursorType
>::InvalidateCachedResponses() {
777 AssertIsOnOwningThread();
779 // TODO: Can mBackgroundActor actually be empty at this point?
780 if (mBackgroundActor
) {
781 GetTypedBackgroundActorRef().InvalidateCachedResponses();
785 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor
)
786 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor
)
788 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor
)
789 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
790 NS_INTERFACE_MAP_ENTRY(nsISupports
)
793 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor
)
795 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor
)
796 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest
)
797 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
799 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor
)
800 MOZ_ASSERT_IF(!tmp
->mHaveCachedKey
, tmp
->mCachedKey
.isUndefined());
801 MOZ_ASSERT_IF(!tmp
->mHaveCachedPrimaryKey
,
802 tmp
->mCachedPrimaryKey
.isUndefined());
803 MOZ_ASSERT_IF(!tmp
->mHaveCachedValue
, tmp
->mCachedValue
.isUndefined());
805 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
806 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKey
)
807 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedPrimaryKey
)
808 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedValue
)
809 NS_IMPL_CYCLE_COLLECTION_TRACE_END
811 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor
)
812 // Unlinking is done in the subclasses.
813 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
815 // Don't unlink mRequest or mSource in
816 // NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED!
817 #define NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS_METHODS(_subclassName) \
818 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_subclassName, IDBCursor) \
819 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource) \
820 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \
822 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_subclassName, IDBCursor) \
823 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \
824 tmp->DropJSObjects(); \
825 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \
827 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(_subclassName) \
828 NS_INTERFACE_MAP_END_INHERITING(IDBCursor) \
830 NS_IMPL_ADDREF_INHERITED(_subclassName, IDBCursor) \
831 NS_IMPL_RELEASE_INHERITED(_subclassName, IDBCursor)
833 #define NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(_subclassName) \
834 NS_IMPL_CYCLE_COLLECTION_CLASS(_subclassName) \
835 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS_METHODS(_subclassName)
837 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBObjectStoreCursor
)
838 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBObjectStoreKeyCursor
)
839 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBIndexCursor
)
840 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBIndexKeyCursor
)
842 template <IDBCursor::Type CursorType
>
843 JSObject
* IDBTypedCursor
<CursorType
>::WrapObject(
844 JSContext
* const aCx
, JS::Handle
<JSObject
*> aGivenProto
) {
845 AssertIsOnOwningThread();
847 return IsKeyOnlyCursor
848 ? IDBCursor_Binding::Wrap(aCx
, this, aGivenProto
)
849 : IDBCursorWithValue_Binding::Wrap(aCx
, this, aGivenProto
);
852 template <IDBCursor::Type CursorType
>
853 template <typename
... DataArgs
>
854 IDBTypedCursor
<CursorType
>::IDBTypedCursor(
855 indexedDB::BackgroundCursorChild
<CursorType
>* const aBackgroundActor
,
856 DataArgs
&&... aDataArgs
)
857 : IDBCursor
{aBackgroundActor
},
858 mData
{std::forward
<DataArgs
>(aDataArgs
)...},
859 mSource(aBackgroundActor
->GetSource()) {}
861 template <IDBCursor::Type CursorType
>
862 bool IDBTypedCursor
<CursorType
>::IsLocaleAware() const {
863 if constexpr (IsObjectStoreCursor
) {
866 return !GetSourceRef().Locale().IsEmpty();
870 template class IDBTypedCursor
<IDBCursorType::ObjectStore
>;
871 template class IDBTypedCursor
<IDBCursorType::ObjectStoreKey
>;
872 template class IDBTypedCursor
<IDBCursorType::Index
>;
873 template class IDBTypedCursor
<IDBCursorType::IndexKey
>;
875 } // namespace mozilla::dom