IDBCursor.cpp (27366B)
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/. */ 6 7 #include "IDBCursor.h" 8 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 "ProfilerHelpers.h" 16 #include "ReportInternalError.h" 17 #include "mozilla/ErrorResult.h" 18 #include "mozilla/HoldDropJSObjects.h" 19 #include "mozilla/dom/UnionTypes.h" 20 #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h" 21 #include "nsString.h" 22 23 // Include this last to avoid path problems on Windows. 24 #include "ActorsChild.h" 25 26 namespace mozilla::dom { 27 28 using namespace indexedDB; 29 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); 47 48 mTransaction->RegisterCursor(*this); 49 } 50 51 template <IDBCursor::Type CursorType> 52 IDBTypedCursor<CursorType>::~IDBTypedCursor() { 53 AssertIsOnOwningThread(); 54 55 mTransaction->UnregisterCursor(*this); 56 57 DropJSObjects(); 58 59 if (mBackgroundActor) { 60 (*mBackgroundActor)->SendDeleteMeInternal(); 61 MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!"); 62 } 63 64 // Let's explicitly not leave any dangling CheckedUnsafePtr. 65 mTransaction = nullptr; 66 } 67 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()); 75 76 return MakeRefPtr<IDBObjectStoreCursor>(aBackgroundActor, std::move(aKey), 77 std::move(aCloneInfo)); 78 } 79 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()); 87 88 return MakeRefPtr<IDBObjectStoreKeyCursor>(aBackgroundActor, std::move(aKey)); 89 } 90 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()); 99 100 return MakeRefPtr<IDBIndexCursor>(aBackgroundActor, std::move(aKey), 101 std::move(aSortKey), std::move(aPrimaryKey), 102 std::move(aCloneInfo)); 103 } 104 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()); 113 114 return MakeRefPtr<IDBIndexKeyCursor>(aBackgroundActor, std::move(aKey), 115 std::move(aSortKey), 116 std::move(aPrimaryKey)); 117 } 118 119 #ifdef DEBUG 120 121 void IDBCursor::AssertIsOnOwningThread() const { 122 MOZ_ASSERT(mTransaction); 123 mTransaction->AssertIsOnOwningThread(); 124 } 125 126 #endif // DEBUG 127 128 template <IDBCursor::Type CursorType> 129 void IDBTypedCursor<CursorType>::DropJSObjects() { 130 AssertIsOnOwningThread(); 131 132 Reset(); 133 134 if (!mRooted) { 135 return; 136 } 137 138 mRooted = false; 139 140 mozilla::DropJSObjects(this); 141 } 142 143 template <IDBCursor::Type CursorType> 144 bool IDBTypedCursor<CursorType>::IsSourceDeleted() const { 145 AssertIsOnOwningThread(); 146 MOZ_ASSERT(mTransaction); 147 MOZ_ASSERT(mTransaction->IsActive()); 148 149 const auto* const sourceObjectStore = [this]() -> const IDBObjectStore* { 150 if constexpr (IsObjectStoreCursor) { 151 return mSource; 152 } else { 153 if (GetSourceRef().IsDeleted()) { 154 return nullptr; 155 } 156 157 const auto* const res = GetSourceRef().ObjectStore(); 158 MOZ_ASSERT(res); 159 return res; 160 } 161 }(); 162 163 return !sourceObjectStore || sourceObjectStore->IsDeleted(); 164 } 165 166 void IDBCursor::ResetBase() { 167 AssertIsOnOwningThread(); 168 169 mCachedKey.setUndefined(); 170 mCachedPrimaryKey.setUndefined(); 171 mCachedValue.setUndefined(); 172 173 mHaveCachedKey = false; 174 mHaveCachedPrimaryKey = false; 175 mHaveCachedValue = false; 176 mHaveValue = false; 177 mContinueCalled = false; 178 } 179 180 template <IDBCursor::Type CursorType> 181 void IDBTypedCursor<CursorType>::Reset() { 182 AssertIsOnOwningThread(); 183 184 if constexpr (!IsKeyOnlyCursor) { 185 IDBObjectStore::ClearCloneReadInfo(mData.mCloneInfo); 186 } 187 188 ResetBase(); 189 } 190 191 nsIGlobalObject* IDBCursor::GetParentObject() const { 192 AssertIsOnOwningThread(); 193 MOZ_ASSERT(mTransaction); 194 195 return mTransaction->GetParentObject(); 196 } 197 198 IDBCursorDirection IDBCursor::GetDirection() const { 199 AssertIsOnOwningThread(); 200 201 switch (mDirection) { 202 case Direction::Next: 203 return IDBCursorDirection::Next; 204 205 case Direction::Nextunique: 206 return IDBCursorDirection::Nextunique; 207 208 case Direction::Prev: 209 return IDBCursorDirection::Prev; 210 211 case Direction::Prevunique: 212 return IDBCursorDirection::Prevunique; 213 214 default: 215 MOZ_CRASH("Bad direction!"); 216 } 217 } 218 219 RefPtr<IDBRequest> IDBCursor::Request() const { 220 AssertIsOnOwningThread(); 221 return mRequest; 222 } 223 224 template <IDBCursor::Type CursorType> 225 void IDBTypedCursor<CursorType>::GetSource( 226 OwningIDBObjectStoreOrIDBIndex& aSource) const { 227 AssertIsOnOwningThread(); 228 229 if constexpr (IsObjectStoreCursor) { 230 aSource.SetAsIDBObjectStore() = mSource; 231 } else { 232 aSource.SetAsIDBIndex() = mSource; 233 } 234 } 235 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); 242 243 if (!mHaveValue) { 244 aResult.setUndefined(); 245 return; 246 } 247 248 if (!mHaveCachedKey) { 249 if (!mRooted) { 250 mozilla::HoldJSObjects(this); 251 mRooted = true; 252 } 253 254 aRv = mData.mKey.ToJSVal(aCx, mCachedKey); 255 if (NS_WARN_IF(aRv.Failed())) { 256 return; 257 } 258 259 mHaveCachedKey = true; 260 } 261 262 aResult.set(mCachedKey); 263 } 264 265 template <IDBCursor::Type CursorType> 266 void IDBTypedCursor<CursorType>::GetPrimaryKey( 267 JSContext* const aCx, JS::MutableHandle<JS::Value> aResult, 268 ErrorResult& aRv) { 269 AssertIsOnOwningThread(); 270 271 if (!mHaveValue) { 272 aResult.setUndefined(); 273 return; 274 } 275 276 if (!mHaveCachedPrimaryKey) { 277 if (!mRooted) { 278 mozilla::HoldJSObjects(this); 279 mRooted = true; 280 } 281 282 const Key& key = mData.GetObjectStoreKey(); 283 284 MOZ_ASSERT(!key.IsUnset()); 285 286 aRv = key.ToJSVal(aCx, mCachedPrimaryKey); 287 if (NS_WARN_IF(aRv.Failed())) { 288 return; 289 } 290 291 mHaveCachedPrimaryKey = true; 292 } 293 294 aResult.set(mCachedPrimaryKey); 295 } 296 297 template <IDBCursor::Type CursorType> 298 void IDBTypedCursor<CursorType>::GetValue(JSContext* const aCx, 299 JS::MutableHandle<JS::Value> aResult, 300 ErrorResult& aRv) { 301 AssertIsOnOwningThread(); 302 303 if constexpr (!IsKeyOnlyCursor) { 304 if (!mHaveValue) { 305 aResult.setUndefined(); 306 return; 307 } 308 309 if (!mHaveCachedValue) { 310 if (!mRooted) { 311 mozilla::HoldJSObjects(this); 312 mRooted = true; 313 } 314 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; 320 } 321 322 // XXX This seems redundant, sine mData.mCloneInfo is moved above. 323 IDBObjectStore::ClearCloneReadInfo(mData.mCloneInfo); 324 325 mCachedValue = val; 326 mHaveCachedValue = true; 327 } 328 329 aResult.set(mCachedValue); 330 } else { 331 MOZ_CRASH("This shouldn't be callable on a key-only cursor."); 332 } 333 } 334 335 template <IDBCursor::Type CursorType> 336 void IDBTypedCursor<CursorType>::Continue(JSContext* const aCx, 337 JS::Handle<JS::Value> aKey, 338 ErrorResult& aRv) { 339 AssertIsOnOwningThread(); 340 341 if (!mTransaction->IsActive()) { 342 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 343 return; 344 } 345 346 if (IsSourceDeleted() || !mHaveValue || mContinueCalled) { 347 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 348 return; 349 } 350 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; 357 } 358 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; 365 } 366 key = result.unwrap(); 367 } 368 } 369 370 const Key& sortKey = mData.GetSortKey(IsLocaleAware()); 371 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; 379 } 380 break; 381 382 case Direction::Prev: 383 case Direction::Prevunique: 384 if (key >= sortKey) { 385 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); 386 return; 387 } 388 break; 389 390 default: 391 MOZ_CRASH("Unknown direction type!"); 392 } 393 } 394 395 const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); 396 mRequest->SetLoggingSerialNumber(requestSerialNumber); 397 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)); 418 } 419 420 GetTypedBackgroundActorRef().SendContinueInternal( 421 mTransaction->NextRequestId(), ContinueParams(key), mData); 422 423 mContinueCalled = true; 424 } 425 426 template <IDBCursor::Type CursorType> 427 void IDBTypedCursor<CursorType>::ContinuePrimaryKey( 428 JSContext* const aCx, JS::Handle<JS::Value> aKey, 429 JS::Handle<JS::Value> aPrimaryKey, ErrorResult& aRv) { 430 AssertIsOnOwningThread(); 431 432 if (!mTransaction->IsActive()) { 433 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 434 return; 435 } 436 437 if (IsSourceDeleted()) { 438 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 439 return; 440 } 441 442 if (IsObjectStoreCursor || 443 (mDirection != Direction::Next && mDirection != Direction::Prev)) { 444 aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); 445 return; 446 } 447 448 if constexpr (!IsObjectStoreCursor) { 449 if (!mHaveValue || mContinueCalled) { 450 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 451 return; 452 } 453 454 Key key; 455 auto result = key.SetFromJSVal(aCx, aKey); 456 if (result.isErr()) { 457 aRv = result.unwrapErr().ExtractErrorResult( 458 InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>); 459 return; 460 } 461 462 if (IsLocaleAware() && !key.IsUnset()) { 463 auto result = key.ToLocaleAwareKey(GetSourceRef().Locale()); 464 if (result.isErr()) { 465 aRv.Throw(result.inspectErr()); 466 return; 467 } 468 key = result.unwrap(); 469 } 470 471 if (key.IsUnset()) { 472 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); 473 return; 474 } 475 476 Key primaryKey; 477 result = primaryKey.SetFromJSVal(aCx, aPrimaryKey); 478 if (result.isErr()) { 479 aRv = result.unwrapErr().ExtractErrorResult( 480 InvalidMapsTo<NS_ERROR_DOM_INDEXEDDB_DATA_ERR>); 481 return; 482 } 483 484 if (primaryKey.IsUnset()) { 485 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); 486 return; 487 } 488 489 const Key& sortKey = mData.GetSortKey(IsLocaleAware()); 490 491 switch (mDirection) { 492 case Direction::Next: 493 if (key < sortKey || 494 (key == sortKey && primaryKey <= mData.mObjectStoreKey)) { 495 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); 496 return; 497 } 498 break; 499 500 case Direction::Prev: 501 if (key > sortKey || 502 (key == sortKey && primaryKey >= mData.mObjectStoreKey)) { 503 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); 504 return; 505 } 506 break; 507 508 default: 509 MOZ_CRASH("Unknown direction type!"); 510 } 511 512 const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); 513 mRequest->SetLoggingSerialNumber(requestSerialNumber); 514 515 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 516 "database(%s).transaction(%s).objectStore(%s)." 517 "index(%s).cursor(%s).continuePrimaryKey(%s, %s)", 518 "IDBCursor.continuePrimaryKey(%.0s%.0s%.0s%.0s%.0s%.0s%.0s)", 519 mTransaction->LoggingSerialNumber(), requestSerialNumber, 520 IDB_LOG_STRINGIFY(mTransaction->Database()), 521 IDB_LOG_STRINGIFY(*mTransaction), 522 IDB_LOG_STRINGIFY(&GetSourceObjectStoreRef()), 523 IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection), 524 IDB_LOG_STRINGIFY(key), IDB_LOG_STRINGIFY(primaryKey)); 525 526 GetTypedBackgroundActorRef().SendContinueInternal( 527 mTransaction->NextRequestId(), 528 ContinuePrimaryKeyParams(key, primaryKey), mData); 529 530 mContinueCalled = true; 531 } 532 } 533 534 template <IDBCursor::Type CursorType> 535 void IDBTypedCursor<CursorType>::Advance(const uint32_t aCount, 536 ErrorResult& aRv) { 537 AssertIsOnOwningThread(); 538 539 if (!aCount) { 540 aRv.ThrowTypeError("0 (Zero) is not a valid advance count."); 541 return; 542 } 543 544 if (!mTransaction->IsActive()) { 545 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 546 return; 547 } 548 549 if (IsSourceDeleted() || !mHaveValue || mContinueCalled) { 550 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 551 return; 552 } 553 554 const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); 555 mRequest->SetLoggingSerialNumber(requestSerialNumber); 556 557 if constexpr (IsObjectStoreCursor) { 558 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 559 "database(%s).transaction(%s).objectStore(%s)." 560 "cursor(%s).advance(%" PRIi32 ")", 561 "IDBCursor.advance(%.0s%.0s%.0s%.0s%" PRIi32 ")", 562 mTransaction->LoggingSerialNumber(), requestSerialNumber, 563 IDB_LOG_STRINGIFY(mTransaction->Database()), 564 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(mSource), 565 IDB_LOG_STRINGIFY(mDirection), aCount); 566 } else { 567 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 568 "database(%s).transaction(%s).objectStore(%s)." 569 "index(%s).cursor(%s).advance(%" PRIi32 ")", 570 "IDBCursor.advance(%.0s%.0s%.0s%.0s%.0s%" PRIi32 ")", 571 mTransaction->LoggingSerialNumber(), requestSerialNumber, 572 IDB_LOG_STRINGIFY(mTransaction->Database()), 573 IDB_LOG_STRINGIFY(*mTransaction), 574 IDB_LOG_STRINGIFY(GetSourceRef().ObjectStore()), 575 IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection), aCount); 576 } 577 578 GetTypedBackgroundActorRef().SendContinueInternal( 579 mTransaction->NextRequestId(), AdvanceParams(aCount), mData); 580 581 mContinueCalled = true; 582 } 583 584 template <IDBCursor::Type CursorType> 585 RefPtr<IDBRequest> IDBTypedCursor<CursorType>::Update( 586 JSContext* const aCx, JS::Handle<JS::Value> aValue, ErrorResult& aRv) { 587 AssertIsOnOwningThread(); 588 589 if (!mTransaction->IsActive()) { 590 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 591 return nullptr; 592 } 593 594 if (!mTransaction->IsWriteAllowed()) { 595 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); 596 return nullptr; 597 } 598 599 if (mTransaction->GetMode() == IDBTransaction::Mode::Cleanup || 600 IsSourceDeleted() || !mHaveValue || IsKeyOnlyCursor || mContinueCalled) { 601 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 602 return nullptr; 603 } 604 605 if constexpr (!IsKeyOnlyCursor) { 606 MOZ_ASSERT(!mData.mKey.IsUnset()); 607 if constexpr (!IsObjectStoreCursor) { 608 MOZ_ASSERT(!mData.mObjectStoreKey.IsUnset()); 609 } 610 611 mTransaction->InvalidateCursorCaches(); 612 613 IDBObjectStore::ValueWrapper valueWrapper(aCx, aValue); 614 615 const Key& primaryKey = mData.GetObjectStoreKey(); 616 617 RefPtr<IDBRequest> request; 618 619 IDBObjectStore& objectStore = GetSourceObjectStoreRef(); 620 if (objectStore.HasValidKeyPath()) { 621 if (!valueWrapper.Clone(aCx)) { 622 aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR); 623 return nullptr; 624 } 625 626 // Make sure the object given has the correct keyPath value set on it. 627 const KeyPath& keyPath = objectStore.GetKeyPath(); 628 Key key; 629 630 aRv = keyPath.ExtractKey(aCx, valueWrapper.Value(), key); 631 if (aRv.Failed()) { 632 return nullptr; 633 } 634 635 if (key != primaryKey) { 636 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); 637 return nullptr; 638 } 639 640 request = objectStore.AddOrPut(aCx, valueWrapper, 641 /* aKey */ JS::UndefinedHandleValue, 642 /* aOverwrite */ true, 643 /* aFromCursor */ true, aRv); 644 if (aRv.Failed()) { 645 return nullptr; 646 } 647 } else { 648 JS::Rooted<JS::Value> keyVal(aCx); 649 aRv = primaryKey.ToJSVal(aCx, &keyVal); 650 if (aRv.Failed()) { 651 return nullptr; 652 } 653 654 request = objectStore.AddOrPut(aCx, valueWrapper, keyVal, 655 /* aOverwrite */ true, 656 /* aFromCursor */ true, aRv); 657 if (aRv.Failed()) { 658 return nullptr; 659 } 660 } 661 662 request->SetSource(this); 663 664 if (IsObjectStoreCursor) { 665 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 666 "database(%s).transaction(%s).objectStore(%s)." 667 "cursor(%s).update(%s)", 668 "IDBCursor.update(%.0s%.0s%.0s%.0s%.0s)", 669 mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(), 670 IDB_LOG_STRINGIFY(mTransaction->Database()), 671 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(&objectStore), 672 IDB_LOG_STRINGIFY(mDirection), 673 IDB_LOG_STRINGIFY(&objectStore, primaryKey)); 674 } else { 675 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 676 "database(%s).transaction(%s).objectStore(%s)." 677 "index(%s).cursor(%s).update(%s)", 678 "IDBCursor.update(%.0s%.0s%.0s%.0s%.0s%.0s)", 679 mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(), 680 IDB_LOG_STRINGIFY(mTransaction->Database()), 681 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(&objectStore), 682 IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection), 683 IDB_LOG_STRINGIFY(&objectStore, primaryKey)); 684 } 685 686 return request; 687 } else { 688 // XXX: Just to work around a bug in gcc, which otherwise claims 'control 689 // reaches end of non-void function', which is not true. 690 return nullptr; 691 } 692 } 693 694 template <IDBCursor::Type CursorType> 695 RefPtr<IDBRequest> IDBTypedCursor<CursorType>::Delete(JSContext* const aCx, 696 ErrorResult& aRv) { 697 AssertIsOnOwningThread(); 698 699 if (!mTransaction->IsActive()) { 700 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 701 return nullptr; 702 } 703 704 if (!mTransaction->IsWriteAllowed()) { 705 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); 706 return nullptr; 707 } 708 709 if (IsSourceDeleted() || !mHaveValue || IsKeyOnlyCursor || mContinueCalled) { 710 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 711 return nullptr; 712 } 713 714 if constexpr (!IsKeyOnlyCursor) { 715 MOZ_ASSERT(!mData.mKey.IsUnset()); 716 717 mTransaction->InvalidateCursorCaches(); 718 719 const Key& primaryKey = mData.GetObjectStoreKey(); 720 721 JS::Rooted<JS::Value> key(aCx); 722 aRv = primaryKey.ToJSVal(aCx, &key); 723 if (NS_WARN_IF(aRv.Failed())) { 724 return nullptr; 725 } 726 727 auto& objectStore = GetSourceObjectStoreRef(); 728 RefPtr<IDBRequest> request = 729 objectStore.DeleteInternal(aCx, key, /* aFromCursor */ true, aRv); 730 if (aRv.Failed()) { 731 return nullptr; 732 } 733 734 request->SetSource(this); 735 736 if (IsObjectStoreCursor) { 737 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 738 "database(%s).transaction(%s).objectStore(%s)." 739 "cursor(%s).delete(%s)", 740 "IDBCursor.delete(%.0s%.0s%.0s%.0s%.0s)", 741 mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(), 742 IDB_LOG_STRINGIFY(mTransaction->Database()), 743 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(&objectStore), 744 IDB_LOG_STRINGIFY(mDirection), 745 IDB_LOG_STRINGIFY(&objectStore, primaryKey)); 746 } else { 747 IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST( 748 "database(%s).transaction(%s).objectStore(%s)." 749 "index(%s).cursor(%s).delete(%s)", 750 "IDBCursor.delete(%.0s%.0s%.0s%.0s%.0s%.0s)", 751 mTransaction->LoggingSerialNumber(), request->LoggingSerialNumber(), 752 IDB_LOG_STRINGIFY(mTransaction->Database()), 753 IDB_LOG_STRINGIFY(*mTransaction), IDB_LOG_STRINGIFY(&objectStore), 754 IDB_LOG_STRINGIFY(mSource), IDB_LOG_STRINGIFY(mDirection), 755 IDB_LOG_STRINGIFY(&objectStore, primaryKey)); 756 } 757 758 return request; 759 } else { 760 // XXX: Just to work around a bug in gcc, which otherwise claims 'control 761 // reaches end of non-void function', which is not true. 762 return nullptr; 763 } 764 } 765 766 template <IDBCursor::Type CursorType> 767 void IDBTypedCursor<CursorType>::Reset(CursorData<CursorType>&& aCursorData) { 768 this->AssertIsOnOwningThread(); 769 770 Reset(); 771 772 mData = std::move(aCursorData); 773 774 mHaveValue = !mData.mKey.IsUnset(); 775 } 776 777 template <IDBCursor::Type CursorType> 778 void IDBTypedCursor<CursorType>::InvalidateCachedResponses() { 779 AssertIsOnOwningThread(); 780 781 // TODO: Can mBackgroundActor actually be empty at this point? 782 if (mBackgroundActor) { 783 GetTypedBackgroundActorRef().InvalidateCachedResponses(); 784 } 785 } 786 787 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor) 788 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor) 789 790 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor) 791 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 792 NS_INTERFACE_MAP_ENTRY(nsISupports) 793 NS_INTERFACE_MAP_END 794 795 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor) 796 797 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor) 798 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest) 799 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 800 801 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor) 802 MOZ_ASSERT_IF(!tmp->mHaveCachedKey, tmp->mCachedKey.isUndefined()); 803 MOZ_ASSERT_IF(!tmp->mHaveCachedPrimaryKey, 804 tmp->mCachedPrimaryKey.isUndefined()); 805 MOZ_ASSERT_IF(!tmp->mHaveCachedValue, tmp->mCachedValue.isUndefined()); 806 807 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER 808 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKey) 809 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedPrimaryKey) 810 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedValue) 811 NS_IMPL_CYCLE_COLLECTION_TRACE_END 812 813 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor) 814 // Unlinking is done in the subclasses. 815 NS_IMPL_CYCLE_COLLECTION_UNLINK_END 816 817 // Don't unlink mRequest or mSource in 818 // NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED! 819 #define NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS_METHODS(_subclassName) \ 820 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(_subclassName, IDBCursor) \ 821 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSource) \ 822 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END \ 823 \ 824 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(_subclassName, IDBCursor) \ 825 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER \ 826 tmp->DropJSObjects(); \ 827 NS_IMPL_CYCLE_COLLECTION_UNLINK_END \ 828 \ 829 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(_subclassName) \ 830 NS_INTERFACE_MAP_END_INHERITING(IDBCursor) \ 831 \ 832 NS_IMPL_ADDREF_INHERITED(_subclassName, IDBCursor) \ 833 NS_IMPL_RELEASE_INHERITED(_subclassName, IDBCursor) 834 835 #define NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(_subclassName) \ 836 NS_IMPL_CYCLE_COLLECTION_CLASS(_subclassName) \ 837 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS_METHODS(_subclassName) 838 839 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBObjectStoreCursor) 840 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBObjectStoreKeyCursor) 841 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBIndexCursor) 842 NS_IMPL_CYCLE_COLLECTION_IDBCURSOR_SUBCLASS(IDBIndexKeyCursor) 843 844 template <IDBCursor::Type CursorType> 845 JSObject* IDBTypedCursor<CursorType>::WrapObject( 846 JSContext* const aCx, JS::Handle<JSObject*> aGivenProto) { 847 AssertIsOnOwningThread(); 848 849 return IsKeyOnlyCursor 850 ? IDBCursor_Binding::Wrap(aCx, this, aGivenProto) 851 : IDBCursorWithValue_Binding::Wrap(aCx, this, aGivenProto); 852 } 853 854 template <IDBCursor::Type CursorType> 855 template <typename... DataArgs> 856 IDBTypedCursor<CursorType>::IDBTypedCursor( 857 indexedDB::BackgroundCursorChild<CursorType>* const aBackgroundActor, 858 DataArgs&&... aDataArgs) 859 : IDBCursor{aBackgroundActor}, 860 mData{std::forward<DataArgs>(aDataArgs)...}, 861 mSource(aBackgroundActor->GetSource()) {} 862 863 template <IDBCursor::Type CursorType> 864 bool IDBTypedCursor<CursorType>::IsLocaleAware() const { 865 if constexpr (IsObjectStoreCursor) { 866 return false; 867 } else { 868 return !GetSourceRef().Locale().IsEmpty(); 869 } 870 } 871 872 template class IDBTypedCursor<IDBCursorType::ObjectStore>; 873 template class IDBTypedCursor<IDBCursorType::ObjectStoreKey>; 874 template class IDBTypedCursor<IDBCursorType::Index>; 875 template class IDBTypedCursor<IDBCursorType::IndexKey>; 876 877 } // namespace mozilla::dom