Source code

Revision control

Other Tools

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 "mozilla/ErrorResult.h"
16
#include "mozilla/dom/UnionTypes.h"
17
#include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h"
18
#include "nsString.h"
19
#include "ProfilerHelpers.h"
20
#include "ReportInternalError.h"
21
22
// Include this last to avoid path problems on Windows.
23
#include "ActorsChild.h"
24
25
namespace mozilla {
26
namespace dom {
27
28
using namespace indexedDB;
29
30
IDBCursor::IDBCursor(Type aType, BackgroundCursorChild* aBackgroundActor,
31
Key aKey)
32
: mBackgroundActor(aBackgroundActor),
33
mRequest(aBackgroundActor->GetRequest()),
34
mSourceObjectStore(aBackgroundActor->GetObjectStore()),
35
mSourceIndex(aBackgroundActor->GetIndex()),
36
mTransaction(mRequest->GetTransaction()),
37
mCachedKey(JS::UndefinedValue()),
38
mCachedPrimaryKey(JS::UndefinedValue()),
39
mCachedValue(JS::UndefinedValue()),
40
mKey(std::move(aKey)),
41
mType(aType),
42
mDirection(aBackgroundActor->GetDirection()),
43
mHaveCachedKey(false),
44
mHaveCachedPrimaryKey(false),
45
mHaveCachedValue(false),
46
mRooted(false),
47
mContinueCalled(false),
48
mHaveValue(true) {
49
MOZ_ASSERT(aBackgroundActor);
50
aBackgroundActor->AssertIsOnOwningThread();
51
MOZ_ASSERT(mRequest);
52
MOZ_ASSERT_IF(aType == Type_ObjectStore || aType == Type_ObjectStoreKey,
53
mSourceObjectStore);
54
MOZ_ASSERT_IF(aType == Type_Index || aType == Type_IndexKey, mSourceIndex);
55
MOZ_ASSERT(mTransaction);
56
MOZ_ASSERT(!aKey.IsUnset());
57
58
mTransaction->RegisterCursor(this);
59
}
60
61
bool IDBCursor::IsLocaleAware() const {
62
return mSourceIndex && !mSourceIndex->Locale().IsEmpty();
63
}
64
65
IDBCursor::~IDBCursor() {
66
AssertIsOnOwningThread();
67
68
mTransaction->UnregisterCursor(this);
69
70
DropJSObjects();
71
72
if (mBackgroundActor) {
73
mBackgroundActor->SendDeleteMeInternal();
74
MOZ_ASSERT(!mBackgroundActor, "SendDeleteMeInternal should have cleared!");
75
}
76
}
77
78
// static
79
already_AddRefed<IDBCursor> IDBCursor::Create(
80
BackgroundCursorChild* aBackgroundActor, Key aKey,
81
StructuredCloneReadInfo&& aCloneInfo) {
82
MOZ_ASSERT(aBackgroundActor);
83
aBackgroundActor->AssertIsOnOwningThread();
84
MOZ_ASSERT(aBackgroundActor->GetObjectStore());
85
MOZ_ASSERT(!aBackgroundActor->GetIndex());
86
MOZ_ASSERT(!aKey.IsUnset());
87
88
RefPtr<IDBCursor> cursor =
89
new IDBCursor(Type_ObjectStore, aBackgroundActor, std::move(aKey));
90
91
cursor->mCloneInfo = std::move(aCloneInfo);
92
93
return cursor.forget();
94
}
95
96
// static
97
already_AddRefed<IDBCursor> IDBCursor::Create(
98
BackgroundCursorChild* aBackgroundActor, Key aKey) {
99
MOZ_ASSERT(aBackgroundActor);
100
aBackgroundActor->AssertIsOnOwningThread();
101
MOZ_ASSERT(aBackgroundActor->GetObjectStore());
102
MOZ_ASSERT(!aBackgroundActor->GetIndex());
103
MOZ_ASSERT(!aKey.IsUnset());
104
105
RefPtr<IDBCursor> cursor =
106
new IDBCursor(Type_ObjectStoreKey, aBackgroundActor, std::move(aKey));
107
108
return cursor.forget();
109
}
110
111
// static
112
already_AddRefed<IDBCursor> IDBCursor::Create(
113
BackgroundCursorChild* aBackgroundActor, Key aKey, Key aSortKey,
114
Key aPrimaryKey, StructuredCloneReadInfo&& aCloneInfo) {
115
MOZ_ASSERT(aBackgroundActor);
116
aBackgroundActor->AssertIsOnOwningThread();
117
MOZ_ASSERT(aBackgroundActor->GetIndex());
118
MOZ_ASSERT(!aBackgroundActor->GetObjectStore());
119
MOZ_ASSERT(!aKey.IsUnset());
120
MOZ_ASSERT(!aPrimaryKey.IsUnset());
121
122
RefPtr<IDBCursor> cursor =
123
new IDBCursor(Type_Index, aBackgroundActor, std::move(aKey));
124
125
cursor->mSortKey = std::move(aSortKey);
126
cursor->mPrimaryKey = std::move(aPrimaryKey);
127
cursor->mCloneInfo = std::move(aCloneInfo);
128
129
return cursor.forget();
130
}
131
132
// static
133
already_AddRefed<IDBCursor> IDBCursor::Create(
134
BackgroundCursorChild* aBackgroundActor, Key aKey, Key aSortKey,
135
Key aPrimaryKey) {
136
MOZ_ASSERT(aBackgroundActor);
137
aBackgroundActor->AssertIsOnOwningThread();
138
MOZ_ASSERT(aBackgroundActor->GetIndex());
139
MOZ_ASSERT(!aBackgroundActor->GetObjectStore());
140
MOZ_ASSERT(!aKey.IsUnset());
141
MOZ_ASSERT(!aPrimaryKey.IsUnset());
142
143
RefPtr<IDBCursor> cursor =
144
new IDBCursor(Type_IndexKey, aBackgroundActor, std::move(aKey));
145
146
cursor->mSortKey = std::move(aSortKey);
147
cursor->mPrimaryKey = std::move(aPrimaryKey);
148
149
return cursor.forget();
150
}
151
152
// static
153
auto IDBCursor::ConvertDirection(IDBCursorDirection aDirection) -> Direction {
154
switch (aDirection) {
155
case mozilla::dom::IDBCursorDirection::Next:
156
return NEXT;
157
158
case mozilla::dom::IDBCursorDirection::Nextunique:
159
return NEXT_UNIQUE;
160
161
case mozilla::dom::IDBCursorDirection::Prev:
162
return PREV;
163
164
case mozilla::dom::IDBCursorDirection::Prevunique:
165
return PREV_UNIQUE;
166
167
default:
168
MOZ_CRASH("Unknown direction!");
169
}
170
}
171
172
#ifdef DEBUG
173
174
void IDBCursor::AssertIsOnOwningThread() const {
175
MOZ_ASSERT(mTransaction);
176
mTransaction->AssertIsOnOwningThread();
177
}
178
179
#endif // DEBUG
180
181
void IDBCursor::DropJSObjects() {
182
AssertIsOnOwningThread();
183
184
Reset();
185
186
if (!mRooted) {
187
return;
188
}
189
190
mRooted = false;
191
192
mozilla::DropJSObjects(this);
193
}
194
195
bool IDBCursor::IsSourceDeleted() const {
196
AssertIsOnOwningThread();
197
MOZ_ASSERT(mTransaction);
198
MOZ_ASSERT(mTransaction->CanAcceptRequests());
199
200
IDBObjectStore* sourceObjectStore;
201
if (mType == Type_Index || mType == Type_IndexKey) {
202
MOZ_ASSERT(mSourceIndex);
203
204
if (mSourceIndex->IsDeleted()) {
205
return true;
206
}
207
208
sourceObjectStore = mSourceIndex->ObjectStore();
209
MOZ_ASSERT(sourceObjectStore);
210
} else {
211
MOZ_ASSERT(mSourceObjectStore);
212
sourceObjectStore = mSourceObjectStore;
213
}
214
215
return sourceObjectStore->IsDeleted();
216
}
217
218
void IDBCursor::Reset() {
219
AssertIsOnOwningThread();
220
221
mCachedKey.setUndefined();
222
mCachedPrimaryKey.setUndefined();
223
mCachedValue.setUndefined();
224
IDBObjectStore::ClearCloneReadInfo(mCloneInfo);
225
226
mHaveCachedKey = false;
227
mHaveCachedPrimaryKey = false;
228
mHaveCachedValue = false;
229
mHaveValue = false;
230
mContinueCalled = false;
231
}
232
233
nsIGlobalObject* IDBCursor::GetParentObject() const {
234
AssertIsOnOwningThread();
235
MOZ_ASSERT(mTransaction);
236
237
return mTransaction->GetParentObject();
238
}
239
240
IDBCursorDirection IDBCursor::GetDirection() const {
241
AssertIsOnOwningThread();
242
243
switch (mDirection) {
244
case NEXT:
245
return IDBCursorDirection::Next;
246
247
case NEXT_UNIQUE:
248
return IDBCursorDirection::Nextunique;
249
250
case PREV:
251
return IDBCursorDirection::Prev;
252
253
case PREV_UNIQUE:
254
return IDBCursorDirection::Prevunique;
255
256
default:
257
MOZ_CRASH("Bad direction!");
258
}
259
}
260
261
IDBCursor::Type IDBCursor::GetType() const { return mType; }
262
263
void IDBCursor::GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const {
264
AssertIsOnOwningThread();
265
266
switch (mType) {
267
case Type_ObjectStore:
268
case Type_ObjectStoreKey:
269
MOZ_ASSERT(mSourceObjectStore);
270
aSource.SetAsIDBObjectStore() = mSourceObjectStore;
271
return;
272
273
case Type_Index:
274
case Type_IndexKey:
275
MOZ_ASSERT(mSourceIndex);
276
aSource.SetAsIDBIndex() = mSourceIndex;
277
return;
278
279
default:
280
MOZ_ASSERT_UNREACHABLE("Bad type!");
281
}
282
}
283
284
void IDBCursor::GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
285
ErrorResult& aRv) {
286
AssertIsOnOwningThread();
287
MOZ_ASSERT(!mKey.IsUnset() || !mHaveValue);
288
289
if (!mHaveValue) {
290
aResult.setUndefined();
291
return;
292
}
293
294
if (!mHaveCachedKey) {
295
if (!mRooted) {
296
mozilla::HoldJSObjects(this);
297
mRooted = true;
298
}
299
300
aRv = mKey.ToJSVal(aCx, mCachedKey);
301
if (NS_WARN_IF(aRv.Failed())) {
302
return;
303
}
304
305
mHaveCachedKey = true;
306
}
307
308
aResult.set(mCachedKey);
309
}
310
311
void IDBCursor::GetPrimaryKey(JSContext* aCx,
312
JS::MutableHandle<JS::Value> aResult,
313
ErrorResult& aRv) {
314
AssertIsOnOwningThread();
315
316
if (!mHaveValue) {
317
aResult.setUndefined();
318
return;
319
}
320
321
if (!mHaveCachedPrimaryKey) {
322
if (!mRooted) {
323
mozilla::HoldJSObjects(this);
324
mRooted = true;
325
}
326
327
const Key& key = (mType == Type_ObjectStore || mType == Type_ObjectStoreKey)
328
? mKey
329
: mPrimaryKey;
330
331
MOZ_ASSERT(!key.IsUnset());
332
333
aRv = key.ToJSVal(aCx, mCachedPrimaryKey);
334
if (NS_WARN_IF(aRv.Failed())) {
335
return;
336
}
337
338
mHaveCachedPrimaryKey = true;
339
}
340
341
aResult.set(mCachedPrimaryKey);
342
}
343
344
void IDBCursor::GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
345
ErrorResult& aRv) {
346
AssertIsOnOwningThread();
347
MOZ_ASSERT(mType == Type_ObjectStore || mType == Type_Index);
348
349
if (!mHaveValue) {
350
aResult.setUndefined();
351
return;
352
}
353
354
if (!mHaveCachedValue) {
355
if (!mRooted) {
356
mozilla::HoldJSObjects(this);
357
mRooted = true;
358
}
359
360
JS::Rooted<JS::Value> val(aCx);
361
if (NS_WARN_IF(!IDBObjectStore::DeserializeValue(aCx, mCloneInfo, &val))) {
362
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
363
return;
364
}
365
366
IDBObjectStore::ClearCloneReadInfo(mCloneInfo);
367
368
mCachedValue = val;
369
mHaveCachedValue = true;
370
}
371
372
aResult.set(mCachedValue);
373
}
374
375
void IDBCursor::Continue(JSContext* aCx, JS::Handle<JS::Value> aKey,
376
ErrorResult& aRv) {
377
AssertIsOnOwningThread();
378
379
if (!mTransaction->CanAcceptRequests()) {
380
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
381
return;
382
}
383
384
if (IsSourceDeleted() || !mHaveValue || mContinueCalled) {
385
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
386
return;
387
}
388
389
Key key;
390
auto result = key.SetFromJSVal(aCx, aKey, aRv);
391
if (!result.Is(Ok, aRv)) {
392
if (result.Is(Invalid, aRv)) {
393
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
394
}
395
return;
396
}
397
398
if (IsLocaleAware() && !key.IsUnset()) {
399
Key tmp;
400
result = key.ToLocaleAwareKey(tmp, mSourceIndex->Locale(), aRv);
401
if (!result.Is(Ok, aRv)) {
402
if (result.Is(Invalid, aRv)) {
403
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
404
}
405
return;
406
}
407
key = tmp;
408
}
409
410
const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
411
412
if (!key.IsUnset()) {
413
switch (mDirection) {
414
case NEXT:
415
case NEXT_UNIQUE:
416
if (key <= sortKey) {
417
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
418
return;
419
}
420
break;
421
422
case PREV:
423
case PREV_UNIQUE:
424
if (key >= sortKey) {
425
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
426
return;
427
}
428
break;
429
430
default:
431
MOZ_CRASH("Unknown direction type!");
432
}
433
}
434
435
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
436
mRequest->SetLoggingSerialNumber(requestSerialNumber);
437
438
if (mType == Type_ObjectStore || mType == Type_ObjectStoreKey) {
439
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
440
"database(%s).transaction(%s).objectStore(%s)."
441
"cursor(%s).continue(%s)",
442
"IDBCursor.continue()", mTransaction->LoggingSerialNumber(),
443
requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()),
444
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSourceObjectStore),
445
IDB_LOG_STRINGIFY(mDirection), IDB_LOG_STRINGIFY(key));
446
} else {
447
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
448
"database(%s).transaction(%s).objectStore(%s)."
449
"index(%s).cursor(%s).continue(%s)",
450
"IDBCursor.continue()", mTransaction->LoggingSerialNumber(),
451
requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()),
452
IDB_LOG_STRINGIFY(mTransaction),
453
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
454
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection),
455
IDB_LOG_STRINGIFY(key));
456
}
457
458
mBackgroundActor->SendContinueInternal(ContinueParams(key), mKey,
459
mPrimaryKey);
460
461
mContinueCalled = true;
462
}
463
464
void IDBCursor::ContinuePrimaryKey(JSContext* aCx, JS::Handle<JS::Value> aKey,
465
JS::Handle<JS::Value> aPrimaryKey,
466
ErrorResult& aRv) {
467
AssertIsOnOwningThread();
468
469
if (!mTransaction->CanAcceptRequests()) {
470
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
471
return;
472
}
473
474
if (IsSourceDeleted()) {
475
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
476
return;
477
}
478
479
if ((mType != Type_Index && mType != Type_IndexKey) ||
480
(mDirection != NEXT && mDirection != PREV)) {
481
aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
482
return;
483
}
484
485
if (!mHaveValue || mContinueCalled) {
486
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
487
return;
488
}
489
490
Key key;
491
auto result = key.SetFromJSVal(aCx, aKey, aRv);
492
if (!result.Is(Ok, aRv)) {
493
if (result.Is(Invalid, aRv)) {
494
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
495
}
496
return;
497
}
498
499
if (IsLocaleAware() && !key.IsUnset()) {
500
Key tmp;
501
result = key.ToLocaleAwareKey(tmp, mSourceIndex->Locale(), aRv);
502
if (!result.Is(Ok, aRv)) {
503
if (result.Is(Invalid, aRv)) {
504
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
505
}
506
return;
507
}
508
key = tmp;
509
}
510
511
if (key.IsUnset()) {
512
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
513
return;
514
}
515
516
Key primaryKey;
517
result = primaryKey.SetFromJSVal(aCx, aPrimaryKey, aRv);
518
if (!result.Is(Ok, aRv)) {
519
if (result.Is(Invalid, aRv)) {
520
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
521
}
522
return;
523
}
524
525
if (primaryKey.IsUnset()) {
526
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
527
return;
528
}
529
530
const Key& sortKey = IsLocaleAware() ? mSortKey : mKey;
531
532
switch (mDirection) {
533
case NEXT:
534
if (key < sortKey || (key == sortKey && primaryKey <= mPrimaryKey)) {
535
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
536
return;
537
}
538
break;
539
540
case PREV:
541
if (key > sortKey || (key == sortKey && primaryKey >= mPrimaryKey)) {
542
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
543
return;
544
}
545
break;
546
547
default:
548
MOZ_CRASH("Unknown direction type!");
549
}
550
551
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
552
mRequest->SetLoggingSerialNumber(requestSerialNumber);
553
554
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
555
"database(%s).transaction(%s).objectStore(%s)."
556
"index(%s).cursor(%s).continuePrimaryKey(%s, %s)",
557
"IDBCursor.continuePrimaryKey()", mTransaction->LoggingSerialNumber(),
558
requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()),
559
IDB_LOG_STRINGIFY(mTransaction),
560
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
561
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection),
562
IDB_LOG_STRINGIFY(key), IDB_LOG_STRINGIFY(primaryKey));
563
564
mBackgroundActor->SendContinueInternal(
565
ContinuePrimaryKeyParams(key, primaryKey), mKey, mPrimaryKey);
566
567
mContinueCalled = true;
568
}
569
570
void IDBCursor::Advance(uint32_t aCount, ErrorResult& aRv) {
571
AssertIsOnOwningThread();
572
573
if (!aCount) {
574
aRv.ThrowTypeError(u"0 (Zero) is not a valid advance count.");
575
return;
576
}
577
578
if (!mTransaction->CanAcceptRequests()) {
579
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
580
return;
581
}
582
583
if (IsSourceDeleted() || !mHaveValue || mContinueCalled) {
584
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
585
return;
586
}
587
588
const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber();
589
mRequest->SetLoggingSerialNumber(requestSerialNumber);
590
591
if (mType == Type_ObjectStore || mType == Type_ObjectStoreKey) {
592
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
593
"database(%s).transaction(%s).objectStore(%s)."
594
"cursor(%s).advance(%ld)",
595
"IDBCursor.advance()", mTransaction->LoggingSerialNumber(),
596
requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()),
597
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(mSourceObjectStore),
598
IDB_LOG_STRINGIFY(mDirection), aCount);
599
} else {
600
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
601
"database(%s).transaction(%s).objectStore(%s)."
602
"index(%s).cursor(%s).advance(%ld)",
603
"IDBCursor.advance()", mTransaction->LoggingSerialNumber(),
604
requestSerialNumber, IDB_LOG_STRINGIFY(mTransaction->Database()),
605
IDB_LOG_STRINGIFY(mTransaction),
606
IDB_LOG_STRINGIFY(mSourceIndex->ObjectStore()),
607
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection), aCount);
608
}
609
610
mBackgroundActor->SendContinueInternal(AdvanceParams(aCount), mKey,
611
mPrimaryKey);
612
613
mContinueCalled = true;
614
}
615
616
already_AddRefed<IDBRequest> IDBCursor::Update(JSContext* aCx,
617
JS::Handle<JS::Value> aValue,
618
ErrorResult& aRv) {
619
AssertIsOnOwningThread();
620
621
if (!mTransaction->CanAcceptRequests()) {
622
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
623
return nullptr;
624
}
625
626
if (!mTransaction->IsWriteAllowed()) {
627
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
628
return nullptr;
629
}
630
631
if (mTransaction->GetMode() == IDBTransaction::Mode::Cleanup ||
632
IsSourceDeleted() || !mHaveValue || mType == Type_ObjectStoreKey ||
633
mType == Type_IndexKey || mContinueCalled) {
634
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
635
return nullptr;
636
}
637
638
MOZ_ASSERT(mType == Type_ObjectStore || mType == Type_Index);
639
MOZ_ASSERT(!mKey.IsUnset());
640
MOZ_ASSERT_IF(mType == Type_Index, !mPrimaryKey.IsUnset());
641
642
mTransaction->InvalidateCursorCaches();
643
644
IDBObjectStore* objectStore;
645
if (mType == Type_ObjectStore) {
646
objectStore = mSourceObjectStore;
647
} else {
648
objectStore = mSourceIndex->ObjectStore();
649
}
650
651
MOZ_ASSERT(objectStore);
652
653
IDBObjectStore::ValueWrapper valueWrapper(aCx, aValue);
654
655
const Key& primaryKey = (mType == Type_ObjectStore) ? mKey : mPrimaryKey;
656
657
RefPtr<IDBRequest> request;
658
659
if (objectStore->HasValidKeyPath()) {
660
if (!valueWrapper.Clone(aCx)) {
661
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
662
return nullptr;
663
}
664
665
// Make sure the object given has the correct keyPath value set on it.
666
const KeyPath& keyPath = objectStore->GetKeyPath();
667
Key key;
668
669
aRv = keyPath.ExtractKey(aCx, valueWrapper.Value(), key);
670
if (aRv.Failed()) {
671
return nullptr;
672
}
673
674
if (key != primaryKey) {
675
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
676
return nullptr;
677
}
678
679
request = objectStore->AddOrPut(aCx, valueWrapper,
680
/* aKey */ JS::UndefinedHandleValue,
681
/* aOverwrite */ true,
682
/* aFromCursor */ true, aRv);
683
if (aRv.Failed()) {
684
return nullptr;
685
}
686
} else {
687
JS::Rooted<JS::Value> keyVal(aCx);
688
aRv = primaryKey.ToJSVal(aCx, &keyVal);
689
if (aRv.Failed()) {
690
return nullptr;
691
}
692
693
request = objectStore->AddOrPut(aCx, valueWrapper, keyVal,
694
/* aOverwrite */ true,
695
/* aFromCursor */ true, aRv);
696
if (aRv.Failed()) {
697
return nullptr;
698
}
699
}
700
701
request->SetSource(this);
702
703
if (mType == Type_ObjectStore) {
704
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
705
"database(%s).transaction(%s).objectStore(%s)."
706
"cursor(%s).update(%s)",
707
"IDBCursor.update()", mTransaction->LoggingSerialNumber(),
708
request->LoggingSerialNumber(),
709
IDB_LOG_STRINGIFY(mTransaction->Database()),
710
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore),
711
IDB_LOG_STRINGIFY(mDirection),
712
IDB_LOG_STRINGIFY(objectStore, primaryKey));
713
} else {
714
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
715
"database(%s).transaction(%s).objectStore(%s)."
716
"index(%s).cursor(%s).update(%s)",
717
"IDBCursor.update()", mTransaction->LoggingSerialNumber(),
718
request->LoggingSerialNumber(),
719
IDB_LOG_STRINGIFY(mTransaction->Database()),
720
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore),
721
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection),
722
IDB_LOG_STRINGIFY(objectStore, primaryKey));
723
}
724
725
return request.forget();
726
}
727
728
already_AddRefed<IDBRequest> IDBCursor::Delete(JSContext* aCx,
729
ErrorResult& aRv) {
730
AssertIsOnOwningThread();
731
732
if (!mTransaction->CanAcceptRequests()) {
733
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
734
return nullptr;
735
}
736
737
if (!mTransaction->IsWriteAllowed()) {
738
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
739
return nullptr;
740
}
741
742
if (IsSourceDeleted() || !mHaveValue || mType == Type_ObjectStoreKey ||
743
mType == Type_IndexKey || mContinueCalled) {
744
aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
745
return nullptr;
746
}
747
748
MOZ_ASSERT(mType == Type_ObjectStore || mType == Type_Index);
749
MOZ_ASSERT(!mKey.IsUnset());
750
751
mTransaction->InvalidateCursorCaches();
752
753
IDBObjectStore* const objectStore = mType == Type_ObjectStore
754
? mSourceObjectStore.get()
755
: mSourceIndex->ObjectStore();
756
757
MOZ_ASSERT(objectStore);
758
759
const Key& primaryKey = (mType == Type_ObjectStore) ? mKey : mPrimaryKey;
760
761
JS::Rooted<JS::Value> key(aCx);
762
aRv = primaryKey.ToJSVal(aCx, &key);
763
if (NS_WARN_IF(aRv.Failed())) {
764
return nullptr;
765
}
766
767
RefPtr<IDBRequest> request =
768
objectStore->DeleteInternal(aCx, key, /* aFromCursor */ true, aRv);
769
if (aRv.Failed()) {
770
return nullptr;
771
}
772
773
request->SetSource(this);
774
775
if (mType == Type_ObjectStore) {
776
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
777
"database(%s).transaction(%s).objectStore(%s)."
778
"cursor(%s).delete(%s)",
779
"IDBCursor.delete()", mTransaction->LoggingSerialNumber(),
780
request->LoggingSerialNumber(),
781
IDB_LOG_STRINGIFY(mTransaction->Database()),
782
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore),
783
IDB_LOG_STRINGIFY(mDirection),
784
IDB_LOG_STRINGIFY(objectStore, primaryKey));
785
} else {
786
IDB_LOG_MARK_CHILD_TRANSACTION_REQUEST(
787
"database(%s).transaction(%s).objectStore(%s)."
788
"index(%s).cursor(%s).delete(%s)",
789
"IDBCursor.delete()", mTransaction->LoggingSerialNumber(),
790
request->LoggingSerialNumber(),
791
IDB_LOG_STRINGIFY(mTransaction->Database()),
792
IDB_LOG_STRINGIFY(mTransaction), IDB_LOG_STRINGIFY(objectStore),
793
IDB_LOG_STRINGIFY(mSourceIndex), IDB_LOG_STRINGIFY(mDirection),
794
IDB_LOG_STRINGIFY(objectStore, primaryKey));
795
}
796
797
return request.forget();
798
}
799
800
void IDBCursor::Reset(Key&& aKey, StructuredCloneReadInfo&& aValue) {
801
AssertIsOnOwningThread();
802
MOZ_ASSERT(mType == Type_ObjectStore);
803
804
Reset();
805
806
mKey = std::move(aKey);
807
mCloneInfo = std::move(aValue);
808
809
mHaveValue = !mKey.IsUnset();
810
}
811
812
void IDBCursor::Reset(Key&& aKey) {
813
AssertIsOnOwningThread();
814
MOZ_ASSERT(mType == Type_ObjectStoreKey);
815
816
Reset();
817
818
mKey = std::move(aKey);
819
820
mHaveValue = !mKey.IsUnset();
821
}
822
823
void IDBCursor::Reset(Key&& aKey, Key&& aSortKey, Key&& aPrimaryKey,
824
StructuredCloneReadInfo&& aValue) {
825
AssertIsOnOwningThread();
826
MOZ_ASSERT(mType == Type_Index);
827
828
Reset();
829
830
mKey = std::move(aKey);
831
mSortKey = std::move(aSortKey);
832
mPrimaryKey = std::move(aPrimaryKey);
833
mCloneInfo = std::move(aValue);
834
835
mHaveValue = !mKey.IsUnset();
836
}
837
838
void IDBCursor::Reset(Key&& aKey, Key&& aSortKey, Key&& aPrimaryKey) {
839
AssertIsOnOwningThread();
840
MOZ_ASSERT(mType == Type_IndexKey);
841
842
Reset();
843
844
mKey = std::move(aKey);
845
mSortKey = std::move(aSortKey);
846
mPrimaryKey = std::move(aPrimaryKey);
847
848
mHaveValue = !mKey.IsUnset();
849
}
850
851
void IDBCursor::InvalidateCachedResponses() {
852
AssertIsOnOwningThread();
853
854
// TODO: In what case would mBackgroundActor be nullptr?
855
if (mBackgroundActor) {
856
mBackgroundActor->InvalidateCachedResponses();
857
}
858
}
859
860
NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor)
861
NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor)
862
863
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor)
864
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
865
NS_INTERFACE_MAP_ENTRY(nsISupports)
866
NS_INTERFACE_MAP_END
867
868
NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor)
869
870
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor)
871
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
872
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceObjectStore)
873
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSourceIndex)
874
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
875
876
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
877
MOZ_ASSERT_IF(!tmp->mHaveCachedKey, tmp->mCachedKey.isUndefined());
878
MOZ_ASSERT_IF(!tmp->mHaveCachedPrimaryKey,
879
tmp->mCachedPrimaryKey.isUndefined());
880
MOZ_ASSERT_IF(!tmp->mHaveCachedValue, tmp->mCachedValue.isUndefined());
881
882
NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
883
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKey)
884
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedPrimaryKey)
885
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedValue)
886
NS_IMPL_CYCLE_COLLECTION_TRACE_END
887
888
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
889
// Don't unlink mRequest, mSourceObjectStore, or mSourceIndex!
890
NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
891
tmp->DropJSObjects();
892
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
893
894
JSObject* IDBCursor::WrapObject(JSContext* aCx,
895
JS::Handle<JSObject*> aGivenProto) {
896
AssertIsOnOwningThread();
897
898
switch (mType) {
899
case Type_ObjectStore:
900
case Type_Index:
901
return IDBCursorWithValue_Binding::Wrap(aCx, this, aGivenProto);
902
903
case Type_ObjectStoreKey:
904
case Type_IndexKey:
905
return IDBCursor_Binding::Wrap(aCx, this, aGivenProto);
906
907
default:
908
MOZ_CRASH("Bad type!");
909
}
910
}
911
912
} // namespace dom
913
} // namespace mozilla