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