Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
9 #include "IDBCursor.h"
11 #include "mozilla/storage.h"
12 #include "nsComponentManagerUtils.h"
13 #include "nsJSUtils.h"
14 #include "nsThreadUtils.h"
16 #include "AsyncConnectionHelper.h"
17 #include "IDBEvents.h"
18 #include "IDBIndex.h"
19 #include "IDBObjectStore.h"
20 #include "IDBTransaction.h"
21 #include "ProfilerHelpers.h"
22 #include "ReportInternalError.h"
23 #include "TransactionThreadPool.h"
25 #include "ipc/IndexedDBChild.h"
26 #include "ipc/IndexedDBParent.h"
28 #include "IndexedDatabaseInlines.h"
29 #include "mozilla/dom/BindingDeclarations.h"
30 #include "mozilla/dom/UnionTypes.h"
32 USING_INDEXEDDB_NAMESPACE
33 using namespace mozilla::dom::indexedDB::ipc;
34 using mozilla::dom::Optional;
35 using mozilla::dom::OwningIDBObjectStoreOrIDBIndex;
36 using mozilla::ErrorResult;
38 static_assert(sizeof(size_t) >= sizeof(IDBCursor::Direction),
39 "Relying on conversion between size_t and IDBCursor::Direction");
41 namespace {
43 class CursorHelper : public AsyncConnectionHelper
44 {
45 public:
46 CursorHelper(IDBCursor* aCursor)
47 : AsyncConnectionHelper(aCursor->Transaction(), aCursor->Request()),
48 mCursor(aCursor), mActor(nullptr)
49 {
50 NS_ASSERTION(aCursor, "Null cursor!");
51 }
53 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
55 virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread) MOZ_OVERRIDE;
57 virtual nsresult
58 PackArgumentsForParentProcess(CursorRequestParams& aParams) = 0;
60 virtual nsresult
61 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0;
63 protected:
64 virtual ~CursorHelper()
65 { }
67 nsRefPtr<IDBCursor> mCursor;
69 private:
70 IndexedDBCursorRequestChild* mActor;
71 };
73 } // anonymous namespace
75 BEGIN_INDEXEDDB_NAMESPACE
77 class ContinueHelper : public CursorHelper
78 {
79 public:
80 ContinueHelper(IDBCursor* aCursor,
81 int32_t aCount)
82 : CursorHelper(aCursor), mCount(aCount)
83 {
84 MOZ_ASSERT(NS_IsMainThread());
85 MOZ_ASSERT(aCursor);
86 MOZ_ASSERT(aCount > 0);
87 }
89 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
90 MOZ_OVERRIDE;
92 virtual nsresult GetSuccessResult(JSContext* aCx,
93 JS::MutableHandle<JS::Value> aVal)
94 MOZ_OVERRIDE;
96 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
98 virtual nsresult
99 PackArgumentsForParentProcess(CursorRequestParams& aParams) MOZ_OVERRIDE;
101 virtual ChildProcessSendResult
102 SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
104 virtual nsresult
105 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
106 MOZ_OVERRIDE;
108 protected:
109 virtual ~ContinueHelper()
110 {
111 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
112 }
114 virtual nsresult
115 BindArgumentsToStatement(mozIStorageStatement* aStatement) = 0;
117 virtual nsresult
118 GatherResultsFromStatement(mozIStorageStatement* aStatement) = 0;
120 void UpdateCursorState()
121 {
122 mCursor->mCachedKey = JSVAL_VOID;
123 mCursor->mCachedPrimaryKey = JSVAL_VOID;
124 mCursor->mCachedValue = JSVAL_VOID;
125 mCursor->mHaveCachedKey = false;
126 mCursor->mHaveCachedPrimaryKey = false;
127 mCursor->mHaveCachedValue = false;
128 mCursor->mContinueCalled = false;
130 if (mKey.IsUnset()) {
131 mCursor->mHaveValue = false;
132 } else {
133 MOZ_ASSERT(mCursor->mType == IDBCursor::OBJECTSTORE ||
134 mCursor->mType == IDBCursor::OBJECTSTOREKEY ||
135 !mObjectKey.IsUnset());
137 // Set new values.
138 mCursor->mKey = mKey;
139 mCursor->mObjectKey = mObjectKey;
140 mCursor->mContinueToKey.Unset();
142 mCursor->mCloneReadInfo = Move(mCloneReadInfo);
143 mCloneReadInfo.mCloneBuffer.clear();
144 }
145 }
147 int32_t mCount;
148 Key mKey;
149 Key mObjectKey;
150 StructuredCloneReadInfo mCloneReadInfo;
151 };
153 class ContinueObjectStoreHelper : public ContinueHelper
154 {
155 public:
156 ContinueObjectStoreHelper(IDBCursor* aCursor,
157 uint32_t aCount)
158 : ContinueHelper(aCursor, aCount)
159 { }
161 protected:
162 virtual ~ContinueObjectStoreHelper()
163 { }
165 private:
166 nsresult BindArgumentsToStatement(mozIStorageStatement* aStatement);
167 nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
168 };
170 class ContinueObjectStoreKeyHelper : public ContinueObjectStoreHelper
171 {
172 public:
173 ContinueObjectStoreKeyHelper(IDBCursor* aCursor,
174 uint32_t aCount)
175 : ContinueObjectStoreHelper(aCursor, aCount)
176 { }
178 private:
179 virtual ~ContinueObjectStoreKeyHelper()
180 { }
182 virtual nsresult
183 GatherResultsFromStatement(mozIStorageStatement* aStatement) MOZ_OVERRIDE;
184 };
186 class ContinueIndexHelper : public ContinueHelper
187 {
188 public:
189 ContinueIndexHelper(IDBCursor* aCursor,
190 uint32_t aCount)
191 : ContinueHelper(aCursor, aCount)
192 { }
194 protected:
195 virtual ~ContinueIndexHelper()
196 { }
198 private:
199 nsresult BindArgumentsToStatement(mozIStorageStatement* aStatement);
200 nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
201 };
203 class ContinueIndexObjectHelper : public ContinueIndexHelper
204 {
205 public:
206 ContinueIndexObjectHelper(IDBCursor* aCursor,
207 uint32_t aCount)
208 : ContinueIndexHelper(aCursor, aCount)
209 { }
211 private:
212 virtual ~ContinueIndexObjectHelper()
213 { }
215 nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
216 };
218 END_INDEXEDDB_NAMESPACE
220 // static
221 already_AddRefed<IDBCursor>
222 IDBCursor::Create(IDBRequest* aRequest,
223 IDBTransaction* aTransaction,
224 IDBObjectStore* aObjectStore,
225 Direction aDirection,
226 const Key& aRangeKey,
227 const nsACString& aContinueQuery,
228 const nsACString& aContinueToQuery,
229 const Key& aKey,
230 StructuredCloneReadInfo&& aCloneReadInfo)
231 {
232 NS_ASSERTION(aObjectStore, "Null pointer!");
233 NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
235 nsRefPtr<IDBCursor> cursor =
236 IDBCursor::CreateCommon(aRequest, aTransaction, aObjectStore, aDirection,
237 aRangeKey, aContinueQuery, aContinueToQuery);
238 NS_ASSERTION(cursor, "This shouldn't fail!");
240 cursor->mObjectStore = aObjectStore;
241 cursor->mType = OBJECTSTORE;
242 cursor->mKey = aKey;
243 cursor->mCloneReadInfo = Move(aCloneReadInfo);
245 return cursor.forget();
246 }
248 // static
249 already_AddRefed<IDBCursor>
250 IDBCursor::Create(IDBRequest* aRequest,
251 IDBTransaction* aTransaction,
252 IDBObjectStore* aObjectStore,
253 Direction aDirection,
254 const Key& aRangeKey,
255 const nsACString& aContinueQuery,
256 const nsACString& aContinueToQuery,
257 const Key& aKey)
258 {
259 MOZ_ASSERT(aObjectStore);
260 MOZ_ASSERT(!aKey.IsUnset());
262 nsRefPtr<IDBCursor> cursor =
263 IDBCursor::CreateCommon(aRequest, aTransaction, aObjectStore, aDirection,
264 aRangeKey, aContinueQuery, aContinueToQuery);
265 NS_ASSERTION(cursor, "This shouldn't fail!");
267 cursor->mObjectStore = aObjectStore;
268 cursor->mType = OBJECTSTOREKEY;
269 cursor->mKey = aKey;
271 return cursor.forget();
272 }
274 // static
275 already_AddRefed<IDBCursor>
276 IDBCursor::Create(IDBRequest* aRequest,
277 IDBTransaction* aTransaction,
278 IDBIndex* aIndex,
279 Direction aDirection,
280 const Key& aRangeKey,
281 const nsACString& aContinueQuery,
282 const nsACString& aContinueToQuery,
283 const Key& aKey,
284 const Key& aObjectKey)
285 {
286 NS_ASSERTION(aIndex, "Null pointer!");
287 NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
288 NS_ASSERTION(!aObjectKey.IsUnset(), "Bad key!");
290 nsRefPtr<IDBCursor> cursor =
291 IDBCursor::CreateCommon(aRequest, aTransaction, aIndex->ObjectStore(),
292 aDirection, aRangeKey, aContinueQuery,
293 aContinueToQuery);
294 NS_ASSERTION(cursor, "This shouldn't fail!");
296 cursor->mIndex = aIndex;
297 cursor->mType = INDEXKEY;
298 cursor->mKey = aKey,
299 cursor->mObjectKey = aObjectKey;
301 return cursor.forget();
302 }
304 // static
305 already_AddRefed<IDBCursor>
306 IDBCursor::Create(IDBRequest* aRequest,
307 IDBTransaction* aTransaction,
308 IDBIndex* aIndex,
309 Direction aDirection,
310 const Key& aRangeKey,
311 const nsACString& aContinueQuery,
312 const nsACString& aContinueToQuery,
313 const Key& aKey,
314 const Key& aObjectKey,
315 StructuredCloneReadInfo&& aCloneReadInfo)
316 {
317 NS_ASSERTION(aIndex, "Null pointer!");
318 NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
320 nsRefPtr<IDBCursor> cursor =
321 IDBCursor::CreateCommon(aRequest, aTransaction, aIndex->ObjectStore(),
322 aDirection, aRangeKey, aContinueQuery,
323 aContinueToQuery);
324 NS_ASSERTION(cursor, "This shouldn't fail!");
326 cursor->mObjectStore = aIndex->ObjectStore();
327 cursor->mIndex = aIndex;
328 cursor->mType = INDEXOBJECT;
329 cursor->mKey = aKey;
330 cursor->mObjectKey = aObjectKey;
331 cursor->mCloneReadInfo = Move(aCloneReadInfo);
333 return cursor.forget();
334 }
336 // static
337 IDBCursor::Direction
338 IDBCursor::ConvertDirection(mozilla::dom::IDBCursorDirection aDirection)
339 {
340 switch (aDirection) {
341 case mozilla::dom::IDBCursorDirection::Next:
342 return NEXT;
344 case mozilla::dom::IDBCursorDirection::Nextunique:
345 return NEXT_UNIQUE;
347 case mozilla::dom::IDBCursorDirection::Prev:
348 return PREV;
350 case mozilla::dom::IDBCursorDirection::Prevunique:
351 return PREV_UNIQUE;
353 default:
354 MOZ_ASSUME_UNREACHABLE("Unknown direction!");
355 }
356 }
358 // static
359 already_AddRefed<IDBCursor>
360 IDBCursor::CreateCommon(IDBRequest* aRequest,
361 IDBTransaction* aTransaction,
362 IDBObjectStore* aObjectStore,
363 Direction aDirection,
364 const Key& aRangeKey,
365 const nsACString& aContinueQuery,
366 const nsACString& aContinueToQuery)
367 {
368 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
369 NS_ASSERTION(aRequest, "Null pointer!");
370 NS_ASSERTION(aTransaction, "Null pointer!");
371 NS_ASSERTION(aObjectStore, "Null pointer!");
372 NS_ASSERTION(!aContinueQuery.IsEmpty() ||
373 !IndexedDatabaseManager::IsMainProcess(),
374 "Empty query!");
375 NS_ASSERTION(!aContinueToQuery.IsEmpty() ||
376 !IndexedDatabaseManager::IsMainProcess(),
377 "Empty query!");
379 nsRefPtr<IDBCursor> cursor = new IDBCursor();
381 IDBDatabase* database = aTransaction->Database();
382 cursor->mScriptOwner = database->GetScriptOwner();
384 if (cursor->mScriptOwner) {
385 mozilla::HoldJSObjects(cursor.get());
386 cursor->mRooted = true;
387 }
389 cursor->mRequest = aRequest;
390 cursor->mTransaction = aTransaction;
391 cursor->mObjectStore = aObjectStore;
392 cursor->mDirection = aDirection;
393 cursor->mContinueQuery = aContinueQuery;
394 cursor->mContinueToQuery = aContinueToQuery;
395 cursor->mRangeKey = aRangeKey;
397 return cursor.forget();
398 }
400 IDBCursor::IDBCursor()
401 : mScriptOwner(nullptr),
402 mType(OBJECTSTORE),
403 mDirection(IDBCursor::NEXT),
404 mCachedKey(JSVAL_VOID),
405 mCachedPrimaryKey(JSVAL_VOID),
406 mCachedValue(JSVAL_VOID),
407 mActorChild(nullptr),
408 mActorParent(nullptr),
409 mHaveCachedKey(false),
410 mHaveCachedPrimaryKey(false),
411 mHaveCachedValue(false),
412 mRooted(false),
413 mContinueCalled(false),
414 mHaveValue(true)
415 {
416 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
418 SetIsDOMBinding();
419 }
421 IDBCursor::~IDBCursor()
422 {
423 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
425 NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
426 if (mActorChild) {
427 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
428 mActorChild->Send__delete__(mActorChild);
429 NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
430 }
432 DropJSObjects();
433 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
434 }
436 void
437 IDBCursor::DropJSObjects()
438 {
439 if (!mRooted) {
440 return;
441 }
442 mScriptOwner = nullptr;
443 mCachedKey = JSVAL_VOID;
444 mCachedPrimaryKey = JSVAL_VOID;
445 mCachedValue = JSVAL_VOID;
446 mHaveCachedKey = false;
447 mHaveCachedPrimaryKey = false;
448 mHaveCachedValue = false;
449 mRooted = false;
450 mHaveValue = false;
451 mozilla::DropJSObjects(this);
452 }
454 void
455 IDBCursor::ContinueInternal(const Key& aKey, int32_t aCount, ErrorResult& aRv)
456 {
457 MOZ_ASSERT(NS_IsMainThread());
458 MOZ_ASSERT(aCount > 0);
460 if (!mTransaction->IsOpen()) {
461 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
462 return;
463 }
465 if (!mHaveValue || mContinueCalled) {
466 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
467 return;
468 }
470 mContinueToKey = aKey;
472 MOZ_ASSERT(mRequest->ReadyState() == IDBRequestReadyState::Done);
474 mRequest->Reset();
476 nsRefPtr<ContinueHelper> helper;
477 switch (mType) {
478 case OBJECTSTORE:
479 helper = new ContinueObjectStoreHelper(this, aCount);
480 break;
482 case OBJECTSTOREKEY:
483 helper = new ContinueObjectStoreKeyHelper(this, aCount);
484 break;
486 case INDEXKEY:
487 helper = new ContinueIndexHelper(this, aCount);
488 break;
490 case INDEXOBJECT:
491 helper = new ContinueIndexObjectHelper(this, aCount);
492 break;
494 default:
495 MOZ_ASSUME_UNREACHABLE("Unknown cursor type!");
496 }
498 nsresult rv = helper->DispatchToTransactionPool();
499 if (NS_FAILED(rv)) {
500 IDB_WARNING("Failed to dispatch!");
501 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
502 return;
503 }
505 mContinueCalled = true;
506 }
508 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor)
510 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor)
511 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
512 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
513 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
514 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore)
515 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndex)
516 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
518 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
519 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
520 NS_ASSERTION(tmp->mHaveCachedKey || JSVAL_IS_VOID(tmp->mCachedKey),
521 "Should have a cached key");
522 NS_ASSERTION(tmp->mHaveCachedPrimaryKey ||
523 JSVAL_IS_VOID(tmp->mCachedPrimaryKey),
524 "Should have a cached primary key");
525 NS_ASSERTION(tmp->mHaveCachedValue || JSVAL_IS_VOID(tmp->mCachedValue),
526 "Should have a cached value");
527 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptOwner)
528 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKey)
529 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedPrimaryKey)
530 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedValue)
531 NS_IMPL_CYCLE_COLLECTION_TRACE_END
533 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
534 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
535 // Don't unlink mObjectStore, mIndex, or mTransaction!
536 tmp->DropJSObjects();
537 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequest)
538 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
540 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor)
541 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
542 NS_INTERFACE_MAP_ENTRY(nsISupports)
543 NS_INTERFACE_MAP_END
545 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor)
546 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor)
548 JSObject*
549 IDBCursor::WrapObject(JSContext* aCx)
550 {
551 MOZ_ASSERT(NS_IsMainThread());
553 switch (mType) {
554 case OBJECTSTORE:
555 case INDEXOBJECT:
556 return IDBCursorWithValueBinding::Wrap(aCx, this);
558 case OBJECTSTOREKEY:
559 case INDEXKEY:
560 return IDBCursorBinding::Wrap(aCx, this);
562 default:
563 MOZ_ASSUME_UNREACHABLE("Bad type!");
564 }
565 }
567 mozilla::dom::IDBCursorDirection
568 IDBCursor::GetDirection() const
569 {
570 MOZ_ASSERT(NS_IsMainThread());
572 switch (mDirection) {
573 case NEXT:
574 return mozilla::dom::IDBCursorDirection::Next;
576 case NEXT_UNIQUE:
577 return mozilla::dom::IDBCursorDirection::Nextunique;
579 case PREV:
580 return mozilla::dom::IDBCursorDirection::Prev;
582 case PREV_UNIQUE:
583 return mozilla::dom::IDBCursorDirection::Prevunique;
585 default:
586 MOZ_ASSUME_UNREACHABLE("Bad direction!");
587 }
588 }
590 void
591 IDBCursor::GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const
592 {
593 MOZ_ASSERT(NS_IsMainThread());
595 switch (mType) {
596 case OBJECTSTORE:
597 case OBJECTSTOREKEY:
598 MOZ_ASSERT(mObjectStore);
599 aSource.SetAsIDBObjectStore() = mObjectStore;
600 break;
602 case INDEXKEY:
603 case INDEXOBJECT:
604 MOZ_ASSERT(mIndex);
605 aSource.SetAsIDBIndex() = mIndex;
606 break;
608 default:
609 MOZ_ASSUME_UNREACHABLE("Bad type!");
610 }
611 }
613 void
614 IDBCursor::GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
615 ErrorResult& aRv)
616 {
617 MOZ_ASSERT(NS_IsMainThread());
618 MOZ_ASSERT(!mKey.IsUnset() || !mHaveValue);
620 if (!mHaveValue) {
621 aResult.setUndefined();
622 return;
623 }
625 if (!mHaveCachedKey) {
626 if (!mRooted) {
627 mozilla::HoldJSObjects(this);
628 mRooted = true;
629 }
631 aRv = mKey.ToJSVal(aCx, mCachedKey);
632 if (NS_WARN_IF(aRv.Failed())) {
633 return;
634 }
636 mHaveCachedKey = true;
637 }
639 JS::ExposeValueToActiveJS(mCachedKey);
640 aResult.set(mCachedKey);
641 }
643 void
644 IDBCursor::GetPrimaryKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
645 ErrorResult& aRv)
646 {
647 MOZ_ASSERT(NS_IsMainThread());
649 if (!mHaveValue) {
650 aResult.setUndefined();
651 return;
652 }
654 if (!mHaveCachedPrimaryKey) {
655 if (!mRooted) {
656 mozilla::HoldJSObjects(this);
657 mRooted = true;
658 }
660 const Key& key =
661 (mType == OBJECTSTORE || mType == OBJECTSTOREKEY) ? mKey : mObjectKey;
662 MOZ_ASSERT(!key.IsUnset());
664 aRv = key.ToJSVal(aCx, mCachedPrimaryKey);
665 if (NS_WARN_IF(aRv.Failed())) {
666 return;
667 }
669 mHaveCachedPrimaryKey = true;
670 }
672 JS::ExposeValueToActiveJS(mCachedPrimaryKey);
673 aResult.set(mCachedPrimaryKey);
674 }
676 void
677 IDBCursor::GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
678 ErrorResult& aRv)
679 {
680 MOZ_ASSERT(NS_IsMainThread());
681 MOZ_ASSERT(mType == OBJECTSTORE || mType == INDEXOBJECT);
683 if (!mHaveValue) {
684 aResult.setUndefined();
685 return;
686 }
688 if (!mHaveCachedValue) {
689 if (!mRooted) {
690 mozilla::HoldJSObjects(this);
691 mRooted = true;
692 }
694 JS::Rooted<JS::Value> val(aCx);
695 if (!IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, &val)) {
696 aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
697 return;
698 }
700 mCloneReadInfo.mCloneBuffer.clear();
702 mCachedValue = val;
703 mHaveCachedValue = true;
704 }
706 JS::ExposeValueToActiveJS(mCachedValue);
707 aResult.set(mCachedValue);
708 }
710 void
711 IDBCursor::Continue(JSContext* aCx,
712 JS::Handle<JS::Value> aKey,
713 ErrorResult &aRv)
714 {
715 MOZ_ASSERT(NS_IsMainThread());
717 Key key;
718 aRv = key.SetFromJSVal(aCx, aKey);
719 ENSURE_SUCCESS_VOID(aRv);
721 if (!key.IsUnset()) {
722 switch (mDirection) {
723 case IDBCursor::NEXT:
724 case IDBCursor::NEXT_UNIQUE:
725 if (key <= mKey) {
726 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
727 return;
728 }
729 break;
731 case IDBCursor::PREV:
732 case IDBCursor::PREV_UNIQUE:
733 if (key >= mKey) {
734 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
735 return;
736 }
737 break;
739 default:
740 MOZ_ASSUME_UNREACHABLE("Unknown direction type!");
741 }
742 }
744 ContinueInternal(key, 1, aRv);
745 if (aRv.Failed()) {
746 return;
747 }
749 #ifdef IDB_PROFILER_USE_MARKS
750 if (mType == OBJECTSTORE || mType == OBJECTSTOREKEY) {
751 IDB_PROFILER_MARK("IndexedDB Request %llu: "
752 "database(%s).transaction(%s).objectStore(%s).cursor(%s)."
753 "continue(%s)",
754 "IDBRequest[%llu] MT IDBCursor.continue()",
755 Request()->GetSerialNumber(),
756 IDB_PROFILER_STRING(Transaction()->Database()),
757 IDB_PROFILER_STRING(Transaction()),
758 IDB_PROFILER_STRING(mObjectStore),
759 IDB_PROFILER_STRING(mDirection),
760 key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
761 }
762 else {
763 IDB_PROFILER_MARK("IndexedDB Request %llu: "
764 "database(%s).transaction(%s).objectStore(%s).index(%s)."
765 "cursor(%s).continue(%s)",
766 "IDBRequest[%llu] MT IDBCursor.continue()",
767 Request()->GetSerialNumber(),
768 IDB_PROFILER_STRING(Transaction()->Database()),
769 IDB_PROFILER_STRING(Transaction()),
770 IDB_PROFILER_STRING(mObjectStore),
771 IDB_PROFILER_STRING(mIndex),
772 IDB_PROFILER_STRING(mDirection),
773 key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
774 }
775 #endif
776 }
778 already_AddRefed<IDBRequest>
779 IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
780 ErrorResult& aRv)
781 {
782 MOZ_ASSERT(NS_IsMainThread());
784 if (!mTransaction->IsOpen()) {
785 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
786 return nullptr;
787 }
789 if (!mTransaction->IsWriteAllowed()) {
790 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
791 return nullptr;
792 }
794 if (!mHaveValue || mType == OBJECTSTOREKEY || mType == INDEXKEY) {
795 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
796 return nullptr;
797 }
799 MOZ_ASSERT(mObjectStore);
800 MOZ_ASSERT(!mKey.IsUnset());
801 MOZ_ASSERT(mType == OBJECTSTORE || mType == INDEXOBJECT);
802 MOZ_ASSERT_IF(mType == INDEXOBJECT, !mObjectKey.IsUnset());
804 const Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
806 nsRefPtr<IDBRequest> request;
807 if (mObjectStore->HasValidKeyPath()) {
808 // Make sure the object given has the correct keyPath value set on it.
809 const KeyPath& keyPath = mObjectStore->GetKeyPath();
810 Key key;
812 aRv = keyPath.ExtractKey(aCx, aValue, key);
813 if (aRv.Failed()) {
814 return nullptr;
815 }
817 if (key != objectKey) {
818 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
819 return nullptr;
820 }
822 request = mObjectStore->Put(aCx, aValue, JS::UndefinedHandleValue, aRv);
823 if (aRv.Failed()) {
824 return nullptr;
825 }
826 }
827 else {
828 JS::Rooted<JS::Value> keyVal(aCx);
829 aRv = objectKey.ToJSVal(aCx, &keyVal);
830 ENSURE_SUCCESS(aRv, nullptr);
832 request = mObjectStore->Put(aCx, aValue, keyVal, aRv);
833 if (aRv.Failed()) {
834 return nullptr;
835 }
836 }
838 #ifdef IDB_PROFILER_USE_MARKS
839 {
840 uint64_t requestSerial =
841 static_cast<IDBRequest*>(request.get())->GetSerialNumber();
842 if (mType == OBJECTSTORE) {
843 IDB_PROFILER_MARK("IndexedDB Request %llu: "
844 "database(%s).transaction(%s).objectStore(%s)."
845 "cursor(%s).update(%s)",
846 "IDBRequest[%llu] MT IDBCursor.update()",
847 requestSerial,
848 IDB_PROFILER_STRING(mTransaction->Database()),
849 IDB_PROFILER_STRING(mTransaction),
850 IDB_PROFILER_STRING(mObjectStore),
851 IDB_PROFILER_STRING(mDirection),
852 mObjectStore->HasValidKeyPath() ? "" :
853 IDB_PROFILER_STRING(objectKey));
854 }
855 else {
856 IDB_PROFILER_MARK("IndexedDB Request %llu: "
857 "database(%s).transaction(%s).objectStore(%s)."
858 "index(%s).cursor(%s).update(%s)",
859 "IDBRequest[%llu] MT IDBCursor.update()",
860 requestSerial,
861 IDB_PROFILER_STRING(mTransaction->Database()),
862 IDB_PROFILER_STRING(mTransaction),
863 IDB_PROFILER_STRING(mObjectStore),
864 IDB_PROFILER_STRING(mIndex),
865 IDB_PROFILER_STRING(mDirection),
866 mObjectStore->HasValidKeyPath() ? "" :
867 IDB_PROFILER_STRING(objectKey));
868 }
869 }
870 #endif
872 return request.forget();
873 }
875 already_AddRefed<IDBRequest>
876 IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
877 {
878 MOZ_ASSERT(NS_IsMainThread());
880 if (!mTransaction->IsOpen()) {
881 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
882 return nullptr;
883 }
885 if (!mTransaction->IsWriteAllowed()) {
886 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
887 return nullptr;
888 }
890 if (!mHaveValue || mType == OBJECTSTOREKEY || mType == INDEXKEY) {
891 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
892 return nullptr;
893 }
895 MOZ_ASSERT(mObjectStore);
896 MOZ_ASSERT(mType == OBJECTSTORE || mType == INDEXOBJECT);
897 MOZ_ASSERT(!mKey.IsUnset());
899 const Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
901 JS::Rooted<JS::Value> key(aCx);
902 aRv = objectKey.ToJSVal(aCx, &key);
903 ENSURE_SUCCESS(aRv, nullptr);
905 nsRefPtr<IDBRequest> request = mObjectStore->Delete(aCx, key, aRv);
906 ENSURE_SUCCESS(aRv, nullptr);
908 #ifdef IDB_PROFILER_USE_MARKS
909 {
910 uint64_t requestSerial = request->GetSerialNumber();
911 if (mType == OBJECTSTORE) {
912 IDB_PROFILER_MARK("IndexedDB Request %llu: "
913 "database(%s).transaction(%s).objectStore(%s)."
914 "cursor(%s).delete(%s)",
915 "IDBRequest[%llu] MT IDBCursor.delete()",
916 requestSerial,
917 IDB_PROFILER_STRING(mTransaction->Database()),
918 IDB_PROFILER_STRING(mTransaction),
919 IDB_PROFILER_STRING(mObjectStore),
920 IDB_PROFILER_STRING(mDirection),
921 mObjectStore->HasValidKeyPath() ? "" :
922 IDB_PROFILER_STRING(objectKey));
923 }
924 else {
925 IDB_PROFILER_MARK("IndexedDB Request %llu: "
926 "database(%s).transaction(%s).objectStore(%s)."
927 "index(%s).cursor(%s).delete(%s)",
928 "IDBRequest[%llu] MT IDBCursor.delete()",
929 requestSerial,
930 IDB_PROFILER_STRING(mTransaction->Database()),
931 IDB_PROFILER_STRING(mTransaction),
932 IDB_PROFILER_STRING(mObjectStore),
933 IDB_PROFILER_STRING(mIndex),
934 IDB_PROFILER_STRING(mDirection),
935 mObjectStore->HasValidKeyPath() ? "" :
936 IDB_PROFILER_STRING(objectKey));
937 }
938 }
939 #endif
941 return request.forget();
942 }
944 void
945 IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv)
946 {
947 MOZ_ASSERT(NS_IsMainThread());
949 if (aCount < 1) {
950 aRv.ThrowTypeError(MSG_INVALID_ADVANCE_COUNT);
951 return;
952 }
954 Key key;
955 ContinueInternal(key, int32_t(aCount), aRv);
956 ENSURE_SUCCESS_VOID(aRv);
958 #ifdef IDB_PROFILER_USE_MARKS
959 {
960 if (mType == OBJECTSTORE || mType == OBJECTSTOREKEY) {
961 IDB_PROFILER_MARK("IndexedDB Request %llu: "
962 "database(%s).transaction(%s).objectStore(%s)."
963 "cursor(%s).advance(%ld)",
964 "IDBRequest[%llu] MT IDBCursor.advance()",
965 Request()->GetSerialNumber(),
966 IDB_PROFILER_STRING(Transaction()->Database()),
967 IDB_PROFILER_STRING(Transaction()),
968 IDB_PROFILER_STRING(mObjectStore),
969 IDB_PROFILER_STRING(mDirection), aCount);
970 }
971 else {
972 IDB_PROFILER_MARK("IndexedDB Request %llu: "
973 "database(%s).transaction(%s).objectStore(%s)."
974 "index(%s).cursor(%s).advance(%ld)",
975 "IDBRequest[%llu] MT IDBCursor.advance()",
976 Request()->GetSerialNumber(),
977 IDB_PROFILER_STRING(Transaction()->Database()),
978 IDB_PROFILER_STRING(Transaction()),
979 IDB_PROFILER_STRING(mObjectStore),
980 IDB_PROFILER_STRING(mIndex),
981 IDB_PROFILER_STRING(mDirection), aCount);
982 }
983 }
984 #endif
985 }
987 void
988 CursorHelper::ReleaseMainThreadObjects()
989 {
990 mCursor = nullptr;
991 AsyncConnectionHelper::ReleaseMainThreadObjects();
992 }
994 nsresult
995 CursorHelper::Dispatch(nsIEventTarget* aDatabaseThread)
996 {
997 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
999 PROFILER_MAIN_THREAD_LABEL("IndexedDB", "CursorHelper::Dispatch");
1001 if (IndexedDatabaseManager::IsMainProcess()) {
1002 return AsyncConnectionHelper::Dispatch(aDatabaseThread);
1003 }
1005 // If we've been invalidated then there's no point sending anything to the
1006 // parent process.
1007 if (mCursor->Transaction()->Database()->IsInvalidated()) {
1008 IDB_REPORT_INTERNAL_ERR();
1009 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1010 }
1012 IndexedDBCursorChild* cursorActor = mCursor->GetActorChild();
1013 NS_ASSERTION(cursorActor, "Must have an actor here!");
1015 CursorRequestParams params;
1016 nsresult rv = PackArgumentsForParentProcess(params);
1017 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1019 NoDispatchEventTarget target;
1020 rv = AsyncConnectionHelper::Dispatch(&target);
1021 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1023 mActor = new IndexedDBCursorRequestChild(this, mCursor, params.type());
1024 cursorActor->SendPIndexedDBRequestConstructor(mActor, params);
1026 return NS_OK;
1027 }
1029 nsresult
1030 ContinueHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
1031 {
1032 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
1033 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1035 PROFILER_LABEL("IndexedDB", "ContinueHelper::DoDatabaseWork");
1037 // We need to pick a query based on whether or not the cursor's mContinueToKey
1038 // is set. If it is unset then othing was passed to continue so we'll grab the
1039 // next item in the database that is greater than (less than, if we're running
1040 // a PREV cursor) the current key. If it is set then a key was passed to
1041 // continue so we'll grab the next item in the database that is greater than
1042 // (less than, if we're running a PREV cursor) or equal to the key that was
1043 // specified.
1045 nsAutoCString query;
1046 if (mCursor->mContinueToKey.IsUnset()) {
1047 query.Assign(mCursor->mContinueQuery);
1048 }
1049 else {
1050 query.Assign(mCursor->mContinueToQuery);
1051 }
1052 NS_ASSERTION(!query.IsEmpty(), "Bad query!");
1054 query.AppendInt(mCount);
1056 nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
1057 IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1059 mozStorageStatementScoper scoper(stmt);
1061 nsresult rv = BindArgumentsToStatement(stmt);
1062 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1064 NS_ASSERTION(mCount > 0, "Not ok!");
1066 bool hasResult;
1067 for (int32_t index = 0; index < mCount; index++) {
1068 rv = stmt->ExecuteStep(&hasResult);
1069 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1071 if (!hasResult) {
1072 break;
1073 }
1074 }
1076 if (hasResult) {
1077 rv = GatherResultsFromStatement(stmt);
1078 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1079 }
1080 else {
1081 mKey.Unset();
1082 }
1084 return NS_OK;
1085 }
1087 nsresult
1088 ContinueHelper::GetSuccessResult(JSContext* aCx,
1089 JS::MutableHandle<JS::Value> aVal)
1090 {
1091 UpdateCursorState();
1093 if (mKey.IsUnset()) {
1094 aVal.setNull();
1095 }
1096 else {
1097 nsresult rv = WrapNative(aCx, mCursor, aVal);
1098 NS_ENSURE_SUCCESS(rv, rv);
1099 }
1101 return NS_OK;
1102 }
1104 void
1105 ContinueHelper::ReleaseMainThreadObjects()
1106 {
1107 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
1108 CursorHelper::ReleaseMainThreadObjects();
1109 }
1111 nsresult
1112 ContinueHelper::PackArgumentsForParentProcess(CursorRequestParams& aParams)
1113 {
1114 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1115 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1117 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1118 "ContinueHelper::PackArgumentsForParentProcess");
1120 ContinueParams params;
1122 params.key() = mCursor->mContinueToKey;
1123 params.count() = uint32_t(mCount);
1125 aParams = params;
1126 return NS_OK;
1127 }
1129 AsyncConnectionHelper::ChildProcessSendResult
1130 ContinueHelper::SendResponseToChildProcess(nsresult aResultCode)
1131 {
1132 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1133 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1135 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1136 "ContinueHelper::SendResponseToChildProcess");
1138 IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
1139 NS_ASSERTION(actor, "How did we get this far without an actor?");
1141 InfallibleTArray<PBlobParent*> blobsParent;
1143 if (NS_SUCCEEDED(aResultCode)) {
1144 IDBDatabase* database = mTransaction->Database();
1145 NS_ASSERTION(database, "This should never be null!");
1147 ContentParent* contentParent = database->GetContentParent();
1148 NS_ASSERTION(contentParent, "This should never be null!");
1150 FileManager* fileManager = database->Manager();
1151 NS_ASSERTION(fileManager, "This should never be null!");
1153 const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
1155 aResultCode =
1156 IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
1157 blobsParent);
1158 if (NS_FAILED(aResultCode)) {
1159 NS_WARNING("ConvertBlobsToActors failed!");
1160 }
1161 }
1163 ResponseValue response;
1164 if (NS_FAILED(aResultCode)) {
1165 response = aResultCode;
1166 }
1167 else {
1168 ContinueResponse continueResponse;
1169 continueResponse.key() = mKey;
1170 continueResponse.objectKey() = mObjectKey;
1171 continueResponse.cloneInfo() = mCloneReadInfo;
1172 continueResponse.blobsParent().SwapElements(blobsParent);
1173 response = continueResponse;
1174 }
1176 if (!actor->SendResponse(response)) {
1177 return Error;
1178 }
1180 UpdateCursorState();
1182 return Success_Sent;
1183 }
1185 nsresult
1186 ContinueHelper::UnpackResponseFromParentProcess(
1187 const ResponseValue& aResponseValue)
1188 {
1189 NS_ASSERTION(aResponseValue.type() == ResponseValue::TContinueResponse,
1190 "Bad response type!");
1192 const ContinueResponse& response = aResponseValue.get_ContinueResponse();
1194 mKey = response.key();
1195 mObjectKey = response.objectKey();
1197 const SerializedStructuredCloneReadInfo& cloneInfo = response.cloneInfo();
1199 NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
1200 (cloneInfo.dataLength && cloneInfo.data),
1201 "Inconsistent clone info!");
1203 if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
1204 IDB_WARNING("Failed to copy clone buffer!");
1205 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1206 }
1208 IDBObjectStore::ConvertActorsToBlobs(response.blobsChild(),
1209 mCloneReadInfo.mFiles);
1210 return NS_OK;
1211 }
1213 nsresult
1214 ContinueObjectStoreHelper::BindArgumentsToStatement(
1215 mozIStorageStatement* aStatement)
1216 {
1217 MOZ_ASSERT(!NS_IsMainThread());
1218 MOZ_ASSERT(aStatement);
1220 // Bind object store id.
1221 nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
1222 mCursor->mObjectStore->Id());
1223 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1225 NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
1226 NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
1228 // Bind current key.
1229 const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
1230 mCursor->mKey :
1231 mCursor->mContinueToKey;
1233 rv = currentKey.BindToStatement(aStatement, currentKeyName);
1234 NS_ENSURE_SUCCESS(rv, rv);
1236 // Bind range key if it is specified.
1237 const Key& rangeKey = mCursor->mRangeKey;
1239 if (!rangeKey.IsUnset()) {
1240 rv = rangeKey.BindToStatement(aStatement, rangeKeyName);
1241 NS_ENSURE_SUCCESS(rv, rv);
1242 }
1244 return NS_OK;
1245 }
1247 nsresult
1248 ContinueObjectStoreHelper::GatherResultsFromStatement(
1249 mozIStorageStatement* aStatement)
1250 {
1251 MOZ_ASSERT(!NS_IsMainThread());
1252 MOZ_ASSERT(aStatement);
1254 // Figure out what kind of key we have next.
1255 nsresult rv = mKey.SetFromStatement(aStatement, 0);
1256 NS_ENSURE_SUCCESS(rv, rv);
1258 rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 1, 2,
1259 mDatabase,
1260 mCloneReadInfo);
1261 NS_ENSURE_SUCCESS(rv, rv);
1263 return NS_OK;
1264 }
1266 nsresult
1267 ContinueObjectStoreKeyHelper::GatherResultsFromStatement(
1268 mozIStorageStatement* aStatement)
1269 {
1270 MOZ_ASSERT(!NS_IsMainThread());
1271 MOZ_ASSERT(aStatement);
1273 nsresult rv = mKey.SetFromStatement(aStatement, 0);
1274 NS_ENSURE_SUCCESS(rv, rv);
1276 return NS_OK;
1277 }
1279 nsresult
1280 ContinueIndexHelper::BindArgumentsToStatement(mozIStorageStatement* aStatement)
1281 {
1282 // Bind index id.
1283 nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
1284 mCursor->mIndex->Id());
1285 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1287 NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
1289 // Bind current key.
1290 const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
1291 mCursor->mKey :
1292 mCursor->mContinueToKey;
1294 rv = currentKey.BindToStatement(aStatement, currentKeyName);
1295 NS_ENSURE_SUCCESS(rv, rv);
1297 // Bind range key if it is specified.
1298 if (!mCursor->mRangeKey.IsUnset()) {
1299 NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
1300 rv = mCursor->mRangeKey.BindToStatement(aStatement, rangeKeyName);
1301 NS_ENSURE_SUCCESS(rv, rv);
1302 }
1304 // Bind object key if duplicates are allowed and we're not continuing to a
1305 // specific key.
1306 if ((mCursor->mDirection == IDBCursor::NEXT ||
1307 mCursor->mDirection == IDBCursor::PREV) &&
1308 mCursor->mContinueToKey.IsUnset()) {
1309 NS_ASSERTION(!mCursor->mObjectKey.IsUnset(), "Bad key!");
1311 NS_NAMED_LITERAL_CSTRING(objectKeyName, "object_key");
1312 rv = mCursor->mObjectKey.BindToStatement(aStatement, objectKeyName);
1313 NS_ENSURE_SUCCESS(rv, rv);
1314 }
1316 return NS_OK;
1317 }
1319 nsresult
1320 ContinueIndexHelper::GatherResultsFromStatement(
1321 mozIStorageStatement* aStatement)
1322 {
1323 nsresult rv = mKey.SetFromStatement(aStatement, 0);
1324 NS_ENSURE_SUCCESS(rv, rv);
1326 rv = mObjectKey.SetFromStatement(aStatement, 1);
1327 NS_ENSURE_SUCCESS(rv, rv);
1329 return NS_OK;
1330 }
1332 nsresult
1333 ContinueIndexObjectHelper::GatherResultsFromStatement(
1334 mozIStorageStatement* aStatement)
1335 {
1336 nsresult rv = mKey.SetFromStatement(aStatement, 0);
1337 NS_ENSURE_SUCCESS(rv, rv);
1339 rv = mObjectKey.SetFromStatement(aStatement, 1);
1340 NS_ENSURE_SUCCESS(rv, rv);
1342 rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 2, 3,
1343 mDatabase, mCloneReadInfo);
1344 NS_ENSURE_SUCCESS(rv, rv);
1346 return NS_OK;
1347 }