Coverage Report

Created: 2018-09-25 14:53

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