Bug 1878930 - s/RawBuffer/Span/: UniformData. r=gfx-reviewers,lsalzman
[gecko.git] / dom / indexedDB / IDBCursor.cpp
blob2fb6e987150fce95ef8e4f1abdb564384114391a
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!");
64 // Let's explicitly not leave any dangling CheckedUnsafePtr.
65 mTransaction = nullptr;
68 // static
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));
80 // static
81 RefPtr<IDBObjectStoreKeyCursor> IDBCursor::Create(
82 BackgroundCursorChild<Type::ObjectStoreKey>* const aBackgroundActor,
83 Key aKey) {
84 MOZ_ASSERT(aBackgroundActor);
85 aBackgroundActor->AssertIsOnOwningThread();
86 MOZ_ASSERT(!aKey.IsUnset());
88 return MakeRefPtr<IDBObjectStoreKeyCursor>(aBackgroundActor, std::move(aKey));
91 // static
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));
105 // static
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),
115 std::move(aSortKey),
116 std::move(aPrimaryKey));
119 #ifdef DEBUG
121 void IDBCursor::AssertIsOnOwningThread() const {
122 MOZ_ASSERT(mTransaction);
123 mTransaction->AssertIsOnOwningThread();
126 #endif // DEBUG
128 template <IDBCursor::Type CursorType>
129 void IDBTypedCursor<CursorType>::DropJSObjects() {
130 AssertIsOnOwningThread();
132 Reset();
134 if (!mRooted) {
135 return;
138 mRooted = false;
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) {
151 return mSource;
152 } else {
153 if (GetSourceRef().IsDeleted()) {
154 return nullptr;
157 const auto* const res = GetSourceRef().ObjectStore();
158 MOZ_ASSERT(res);
159 return res;
161 }();
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;
176 mHaveValue = 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);
188 ResetBase();
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;
214 default:
215 MOZ_CRASH("Bad direction!");
219 RefPtr<IDBRequest> IDBCursor::Request() const {
220 AssertIsOnOwningThread();
221 return mRequest;
224 template <IDBCursor::Type CursorType>
225 void IDBTypedCursor<CursorType>::GetSource(
226 OwningIDBObjectStoreOrIDBIndex& aSource) const {
227 AssertIsOnOwningThread();
229 if constexpr (IsObjectStoreCursor) {
230 aSource.SetAsIDBObjectStore() = mSource;
231 } else {
232 aSource.SetAsIDBIndex() = mSource;
236 template <IDBCursor::Type CursorType>
237 void IDBTypedCursor<CursorType>::GetKey(JSContext* const aCx,
238 JS::MutableHandle<JS::Value> aResult,
239 ErrorResult& aRv) {
240 AssertIsOnOwningThread();
241 MOZ_ASSERT(!mData.mKey.IsUnset() || !mHaveValue);
243 if (!mHaveValue) {
244 aResult.setUndefined();
245 return;
248 if (!mHaveCachedKey) {
249 if (!mRooted) {
250 mozilla::HoldJSObjects(this);
251 mRooted = true;
254 aRv = mData.mKey.ToJSVal(aCx, mCachedKey);
255 if (NS_WARN_IF(aRv.Failed())) {
256 return;
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,
268 ErrorResult& aRv) {
269 AssertIsOnOwningThread();
271 if (!mHaveValue) {
272 aResult.setUndefined();
273 return;
276 if (!mHaveCachedPrimaryKey) {
277 if (!mRooted) {
278 mozilla::HoldJSObjects(this);
279 mRooted = true;
282 const Key& key = mData.GetObjectStoreKey();
284 MOZ_ASSERT(!key.IsUnset());
286 aRv = key.ToJSVal(aCx, mCachedPrimaryKey);
287 if (NS_WARN_IF(aRv.Failed())) {
288 return;
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,
300 ErrorResult& aRv) {
301 AssertIsOnOwningThread();
303 if constexpr (!IsKeyOnlyCursor) {
304 if (!mHaveValue) {
305 aResult.setUndefined();
306 return;
309 if (!mHaveCachedValue) {
310 if (!mRooted) {
311 mozilla::HoldJSObjects(this);
312 mRooted = true;
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);
319 return;
322 // XXX This seems redundant, sine mData.mCloneInfo is moved above.
323 IDBObjectStore::ClearCloneReadInfo(mData.mCloneInfo);
325 mCachedValue = val;
326 mHaveCachedValue = true;
329 aResult.set(mCachedValue);
330 } else {
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,
338 ErrorResult& aRv) {
339 AssertIsOnOwningThread();
341 if (!mTransaction->IsActive()) {
342 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
343 return;
346 if (IsSourceDeleted() || !mHaveValue || mContinueCalled) {
347 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
348 return;
351 Key key;
352 auto result = key.SetFromJSVal(aCx, aKey);
353 if (result.isErr()) {
354 aRv = result.unwrapErr().ExtractErrorResult(
355 InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>);
356 return;
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());
364 return;
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);
378 return;
380 break;
382 case Direction::Prev:
383 case Direction::Prevunique:
384 if (key >= sortKey) {
385 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
386 return;
388 break;
390 default:
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));
407 } else {
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);
433 return;
436 if (IsSourceDeleted()) {
437 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
438 return;
441 if (IsObjectStoreCursor ||
442 (mDirection != Direction::Next && mDirection != Direction::Prev)) {
443 aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
444 return;
447 if constexpr (!IsObjectStoreCursor) {
448 if (!mHaveValue || mContinueCalled) {
449 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
450 return;
453 Key key;
454 auto result = key.SetFromJSVal(aCx, aKey);
455 if (result.isErr()) {
456 aRv = result.unwrapErr().ExtractErrorResult(
457 InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>);
458 return;
461 if (IsLocaleAware() && !key.IsUnset()) {
462 auto result = key.ToLocaleAwareKey(GetSourceRef().Locale());
463 if (result.isErr()) {
464 aRv.Throw(result.inspectErr());
465 return;
467 key = result.unwrap();
470 if (key.IsUnset()) {
471 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
472 return;
475 Key primaryKey;
476 result = primaryKey.SetFromJSVal(aCx, aPrimaryKey);
477 if (result.isErr()) {
478 aRv = result.unwrapErr().ExtractErrorResult(
479 InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>);
480 return;
483 if (primaryKey.IsUnset()) {
484 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
485 return;
488 const Key& sortKey = mData.GetSortKey(IsLocaleAware());
490 switch (mDirection) {
491 case Direction::Next:
492 if (key < sortKey ||
493 (key == sortKey && primaryKey <= mData.mObjectStoreKey)) {
494 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
495 return;
497 break;
499 case Direction::Prev:
500 if (key > sortKey ||
501 (key == sortKey && primaryKey >= mData.mObjectStoreKey)) {
502 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
503 return;
505 break;
507 default:
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,
534 ErrorResult& aRv) {
535 AssertIsOnOwningThread();
537 if (!aCount) {
538 aRv.ThrowTypeError("0 (Zero) is not a valid advance count.");
539 return;
542 if (!mTransaction->IsActive()) {
543 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
544 return;
547 if (IsSourceDeleted() || !mHaveValue || mContinueCalled) {
548 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
549 return;
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);
564 } else {
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),
577 mData);
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);
589 return nullptr;
592 if (!mTransaction->IsWriteAllowed()) {
593 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
594 return nullptr;
597 if (mTransaction->GetMode() == IDBTransaction::Mode::Cleanup ||
598 IsSourceDeleted() || !mHaveValue || IsKeyOnlyCursor || mContinueCalled) {
599 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
600 return nullptr;
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);
621 return nullptr;
624 // Make sure the object given has the correct keyPath value set on it.
625 const KeyPath& keyPath = objectStore.GetKeyPath();
626 Key key;
628 aRv = keyPath.ExtractKey(aCx, valueWrapper.Value(), key);
629 if (aRv.Failed()) {
630 return nullptr;
633 if (key != primaryKey) {
634 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
635 return nullptr;
638 request = objectStore.AddOrPut(aCx, valueWrapper,
639 /* aKey */ JS::UndefinedHandleValue,
640 /* aOverwrite */ true,
641 /* aFromCursor */ true, aRv);
642 if (aRv.Failed()) {
643 return nullptr;
645 } else {
646 JS::Rooted<JS::Value> keyVal(aCx);
647 aRv = primaryKey.ToJSVal(aCx, &keyVal);
648 if (aRv.Failed()) {
649 return nullptr;
652 request = objectStore.AddOrPut(aCx, valueWrapper, keyVal,
653 /* aOverwrite */ true,
654 /* aFromCursor */ true, aRv);
655 if (aRv.Failed()) {
656 return nullptr;
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));
672 } else {
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));
684 return request;
685 } else {
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.
688 return nullptr;
692 template <IDBCursor::Type CursorType>
693 RefPtr<IDBRequest> IDBTypedCursor<CursorType>::Delete(JSContext* const aCx,
694 ErrorResult& aRv) {
695 AssertIsOnOwningThread();
697 if (!mTransaction->IsActive()) {
698 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
699 return nullptr;
702 if (!mTransaction->IsWriteAllowed()) {
703 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
704 return nullptr;
707 if (IsSourceDeleted() || !mHaveValue || IsKeyOnlyCursor || mContinueCalled) {
708 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
709 return nullptr;
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())) {
722 return nullptr;
725 auto& objectStore = GetSourceObjectStoreRef();
726 RefPtr<IDBRequest> request =
727 objectStore.DeleteInternal(aCx, key, /* aFromCursor */ true, aRv);
728 if (aRv.Failed()) {
729 return nullptr;
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));
744 } else {
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));
756 return request;
757 } else {
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.
760 return nullptr;
764 template <IDBCursor::Type CursorType>
765 void IDBTypedCursor<CursorType>::Reset(CursorData<CursorType>&& aCursorData) {
766 this->AssertIsOnOwningThread();
768 Reset();
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)
791 NS_INTERFACE_MAP_END
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) {
864 return false;
865 } else {
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