bug 700693 - OCSP stapling PSM changes r=bsmith
[gecko.git] / dom / indexedDB / IDBCursor.cpp
blob6e573b1854119bcdc77215b9febc6ff41328895f
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 "nsContentUtils.h"
14 #include "nsDOMClassInfoID.h"
15 #include "nsEventDispatcher.h"
16 #include "nsJSUtils.h"
17 #include "nsThreadUtils.h"
19 #include "AsyncConnectionHelper.h"
20 #include "IDBEvents.h"
21 #include "IDBIndex.h"
22 #include "IDBObjectStore.h"
23 #include "IDBTransaction.h"
24 #include "ProfilerHelpers.h"
25 #include "TransactionThreadPool.h"
27 #include "ipc/IndexedDBChild.h"
28 #include "ipc/IndexedDBParent.h"
30 #include "IndexedDatabaseInlines.h"
32 USING_INDEXEDDB_NAMESPACE
33 using namespace mozilla::dom::indexedDB::ipc;
35 MOZ_STATIC_ASSERT(sizeof(size_t) >= sizeof(IDBCursor::Direction),
36 "Relying on conversion between size_t and "
37 "IDBCursor::Direction");
39 namespace {
41 class CursorHelper : public AsyncConnectionHelper
43 public:
44 CursorHelper(IDBCursor* aCursor)
45 : AsyncConnectionHelper(aCursor->Transaction(), aCursor->Request()),
46 mCursor(aCursor), mActor(nullptr)
48 NS_ASSERTION(aCursor, "Null cursor!");
51 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
53 virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread) MOZ_OVERRIDE;
55 virtual nsresult
56 PackArgumentsForParentProcess(CursorRequestParams& aParams) = 0;
58 virtual nsresult
59 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0;
61 protected:
62 nsRefPtr<IDBCursor> mCursor;
64 private:
65 IndexedDBCursorRequestChild* mActor;
68 } // anonymous namespace
70 BEGIN_INDEXEDDB_NAMESPACE
72 class ContinueHelper : public CursorHelper
74 public:
75 ContinueHelper(IDBCursor* aCursor,
76 int32_t aCount)
77 : CursorHelper(aCursor), mCount(aCount)
79 NS_ASSERTION(aCount > 0, "Must have a count!");
82 ~ContinueHelper()
84 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
87 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
88 MOZ_OVERRIDE;
90 virtual nsresult GetSuccessResult(JSContext* aCx,
91 JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
93 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
95 virtual nsresult
96 PackArgumentsForParentProcess(CursorRequestParams& aParams) MOZ_OVERRIDE;
98 virtual ChildProcessSendResult
99 SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
101 virtual nsresult
102 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
103 MOZ_OVERRIDE;
105 protected:
106 virtual nsresult
107 BindArgumentsToStatement(mozIStorageStatement* aStatement) = 0;
109 virtual nsresult
110 GatherResultsFromStatement(mozIStorageStatement* aStatement) = 0;
112 void UpdateCursorState()
114 mCursor->mCachedKey = JSVAL_VOID;
115 mCursor->mCachedPrimaryKey = JSVAL_VOID;
116 mCursor->mCachedValue = JSVAL_VOID;
117 mCursor->mHaveCachedKey = false;
118 mCursor->mHaveCachedPrimaryKey = false;
119 mCursor->mHaveCachedValue = false;
120 mCursor->mContinueCalled = false;
122 if (mKey.IsUnset()) {
123 mCursor->mHaveValue = false;
125 else {
126 NS_ASSERTION(mCursor->mType == IDBCursor::OBJECTSTORE ||
127 !mObjectKey.IsUnset(), "Bad key!");
129 // Set new values.
130 mCursor->mKey = mKey;
131 mCursor->mObjectKey = mObjectKey;
132 mCursor->mContinueToKey.Unset();
134 mCursor->mCloneReadInfo.Swap(mCloneReadInfo);
135 mCloneReadInfo.mCloneBuffer.clear();
139 int32_t mCount;
140 Key mKey;
141 Key mObjectKey;
142 StructuredCloneReadInfo mCloneReadInfo;
145 class ContinueObjectStoreHelper : public ContinueHelper
147 public:
148 ContinueObjectStoreHelper(IDBCursor* aCursor,
149 uint32_t aCount)
150 : ContinueHelper(aCursor, aCount)
153 private:
154 nsresult BindArgumentsToStatement(mozIStorageStatement* aStatement);
155 nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
158 class ContinueIndexHelper : public ContinueHelper
160 public:
161 ContinueIndexHelper(IDBCursor* aCursor,
162 uint32_t aCount)
163 : ContinueHelper(aCursor, aCount)
166 private:
167 nsresult BindArgumentsToStatement(mozIStorageStatement* aStatement);
168 nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
171 class ContinueIndexObjectHelper : public ContinueIndexHelper
173 public:
174 ContinueIndexObjectHelper(IDBCursor* aCursor,
175 uint32_t aCount)
176 : ContinueIndexHelper(aCursor, aCount)
179 private:
180 nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
183 END_INDEXEDDB_NAMESPACE
185 // static
186 already_AddRefed<IDBCursor>
187 IDBCursor::Create(IDBRequest* aRequest,
188 IDBTransaction* aTransaction,
189 IDBObjectStore* aObjectStore,
190 Direction aDirection,
191 const Key& aRangeKey,
192 const nsACString& aContinueQuery,
193 const nsACString& aContinueToQuery,
194 const Key& aKey,
195 StructuredCloneReadInfo& aCloneReadInfo)
197 NS_ASSERTION(aObjectStore, "Null pointer!");
198 NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
200 nsRefPtr<IDBCursor> cursor =
201 IDBCursor::CreateCommon(aRequest, aTransaction, aObjectStore, aDirection,
202 aRangeKey, aContinueQuery, aContinueToQuery);
203 NS_ASSERTION(cursor, "This shouldn't fail!");
205 cursor->mObjectStore = aObjectStore;
206 cursor->mType = OBJECTSTORE;
207 cursor->mKey = aKey;
208 cursor->mCloneReadInfo.Swap(aCloneReadInfo);
210 return cursor.forget();
213 // static
214 already_AddRefed<IDBCursor>
215 IDBCursor::Create(IDBRequest* aRequest,
216 IDBTransaction* aTransaction,
217 IDBIndex* aIndex,
218 Direction aDirection,
219 const Key& aRangeKey,
220 const nsACString& aContinueQuery,
221 const nsACString& aContinueToQuery,
222 const Key& aKey,
223 const Key& aObjectKey)
225 NS_ASSERTION(aIndex, "Null pointer!");
226 NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
227 NS_ASSERTION(!aObjectKey.IsUnset(), "Bad key!");
229 nsRefPtr<IDBCursor> cursor =
230 IDBCursor::CreateCommon(aRequest, aTransaction, aIndex->ObjectStore(),
231 aDirection, aRangeKey, aContinueQuery,
232 aContinueToQuery);
233 NS_ASSERTION(cursor, "This shouldn't fail!");
235 cursor->mIndex = aIndex;
236 cursor->mType = INDEXKEY;
237 cursor->mKey = aKey,
238 cursor->mObjectKey = aObjectKey;
240 return cursor.forget();
243 // static
244 already_AddRefed<IDBCursor>
245 IDBCursor::Create(IDBRequest* aRequest,
246 IDBTransaction* aTransaction,
247 IDBIndex* aIndex,
248 Direction aDirection,
249 const Key& aRangeKey,
250 const nsACString& aContinueQuery,
251 const nsACString& aContinueToQuery,
252 const Key& aKey,
253 const Key& aObjectKey,
254 StructuredCloneReadInfo& aCloneReadInfo)
256 NS_ASSERTION(aIndex, "Null pointer!");
257 NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
259 nsRefPtr<IDBCursor> cursor =
260 IDBCursor::CreateCommon(aRequest, aTransaction, aIndex->ObjectStore(),
261 aDirection, aRangeKey, aContinueQuery,
262 aContinueToQuery);
263 NS_ASSERTION(cursor, "This shouldn't fail!");
265 cursor->mObjectStore = aIndex->ObjectStore();
266 cursor->mIndex = aIndex;
267 cursor->mType = INDEXOBJECT;
268 cursor->mKey = aKey;
269 cursor->mObjectKey = aObjectKey;
270 cursor->mCloneReadInfo.Swap(aCloneReadInfo);
272 return cursor.forget();
275 // static
276 nsresult
277 IDBCursor::ParseDirection(const nsAString& aDirection, Direction* aResult)
279 if (aDirection.EqualsLiteral("next")) {
280 *aResult = NEXT;
282 else if (aDirection.EqualsLiteral("nextunique")) {
283 *aResult = NEXT_UNIQUE;
285 else if (aDirection.EqualsLiteral("prev")) {
286 *aResult = PREV;
288 else if (aDirection.EqualsLiteral("prevunique")) {
289 *aResult = PREV_UNIQUE;
291 else {
292 return NS_ERROR_TYPE_ERR;
295 return NS_OK;
298 // static
299 already_AddRefed<IDBCursor>
300 IDBCursor::CreateCommon(IDBRequest* aRequest,
301 IDBTransaction* aTransaction,
302 IDBObjectStore* aObjectStore,
303 Direction aDirection,
304 const Key& aRangeKey,
305 const nsACString& aContinueQuery,
306 const nsACString& aContinueToQuery)
308 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
309 NS_ASSERTION(aRequest, "Null pointer!");
310 NS_ASSERTION(aTransaction, "Null pointer!");
311 NS_ASSERTION(aObjectStore, "Null pointer!");
312 NS_ASSERTION(!aContinueQuery.IsEmpty() ||
313 !IndexedDatabaseManager::IsMainProcess(),
314 "Empty query!");
315 NS_ASSERTION(!aContinueToQuery.IsEmpty() ||
316 !IndexedDatabaseManager::IsMainProcess(),
317 "Empty query!");
319 nsRefPtr<IDBCursor> cursor = new IDBCursor();
321 IDBDatabase* database = aTransaction->Database();
322 cursor->mScriptOwner = database->GetScriptOwner();
324 if (cursor->mScriptOwner) {
325 NS_HOLD_JS_OBJECTS(cursor, IDBCursor);
326 cursor->mRooted = true;
329 cursor->mRequest = aRequest;
330 cursor->mTransaction = aTransaction;
331 cursor->mObjectStore = aObjectStore;
332 cursor->mDirection = aDirection;
333 cursor->mContinueQuery = aContinueQuery;
334 cursor->mContinueToQuery = aContinueToQuery;
335 cursor->mRangeKey = aRangeKey;
337 return cursor.forget();
340 IDBCursor::IDBCursor()
341 : mScriptOwner(nullptr),
342 mType(OBJECTSTORE),
343 mDirection(IDBCursor::NEXT),
344 mCachedKey(JSVAL_VOID),
345 mCachedPrimaryKey(JSVAL_VOID),
346 mCachedValue(JSVAL_VOID),
347 mActorChild(nullptr),
348 mActorParent(nullptr),
349 mHaveCachedKey(false),
350 mHaveCachedPrimaryKey(false),
351 mHaveCachedValue(false),
352 mRooted(false),
353 mContinueCalled(false),
354 mHaveValue(true)
356 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
359 IDBCursor::~IDBCursor()
361 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
363 NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
364 if (mActorChild) {
365 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
366 mActorChild->Send__delete__(mActorChild);
367 NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
370 DropJSObjects();
371 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
374 void
375 IDBCursor::DropJSObjects()
377 if (!mRooted) {
378 return;
380 mScriptOwner = nullptr;
381 mCachedKey = JSVAL_VOID;
382 mCachedPrimaryKey = JSVAL_VOID;
383 mCachedValue = JSVAL_VOID;
384 mHaveCachedKey = false;
385 mHaveCachedPrimaryKey = false;
386 mHaveCachedValue = false;
387 mRooted = false;
388 mHaveValue = false;
389 NS_DROP_JS_OBJECTS(this, IDBCursor);
392 nsresult
393 IDBCursor::ContinueInternal(const Key& aKey,
394 int32_t aCount)
396 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
397 NS_ASSERTION(aCount > 0, "Must have a count!");
399 if (!mTransaction->IsOpen()) {
400 return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
403 if (!mHaveValue || mContinueCalled) {
404 return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
407 mContinueToKey = aKey;
409 #ifdef DEBUG
411 nsAutoString readyState;
412 if (NS_FAILED(mRequest->GetReadyState(readyState))) {
413 NS_ERROR("This should never fail!");
415 NS_ASSERTION(readyState.EqualsLiteral("done"), "Should be DONE!");
417 #endif
419 mRequest->Reset();
421 nsRefPtr<ContinueHelper> helper;
422 switch (mType) {
423 case OBJECTSTORE:
424 helper = new ContinueObjectStoreHelper(this, aCount);
425 break;
427 case INDEXKEY:
428 helper = new ContinueIndexHelper(this, aCount);
429 break;
431 case INDEXOBJECT:
432 helper = new ContinueIndexObjectHelper(this, aCount);
433 break;
435 default:
436 NS_NOTREACHED("Unknown cursor type!");
439 nsresult rv = helper->DispatchToTransactionPool();
440 NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
442 mContinueCalled = true;
443 return NS_OK;
446 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor)
447 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
448 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
449 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
450 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore)
451 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndex)
452 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
454 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
455 NS_ASSERTION(tmp->mHaveCachedKey || JSVAL_IS_VOID(tmp->mCachedKey),
456 "Should have a cached key");
457 NS_ASSERTION(tmp->mHaveCachedPrimaryKey ||
458 JSVAL_IS_VOID(tmp->mCachedPrimaryKey),
459 "Should have a cached primary key");
460 NS_ASSERTION(tmp->mHaveCachedValue || JSVAL_IS_VOID(tmp->mCachedValue),
461 "Should have a cached value");
462 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptOwner)
463 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKey)
464 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedPrimaryKey)
465 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedValue)
466 NS_IMPL_CYCLE_COLLECTION_TRACE_END
468 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
469 // Don't unlink mObjectStore, mIndex, or mTransaction!
470 tmp->DropJSObjects();
471 NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequest)
472 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
474 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor)
475 NS_INTERFACE_MAP_ENTRY(nsIIDBCursor)
476 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIDBCursorWithValue, mType != INDEXKEY)
477 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBCursorWithValue,
478 mType != INDEXKEY)
479 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBCursor,
480 mType == INDEXKEY)
481 NS_INTERFACE_MAP_ENTRY(nsISupports)
482 NS_INTERFACE_MAP_END
484 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor)
485 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor)
487 DOMCI_DATA(IDBCursor, IDBCursor)
488 DOMCI_DATA(IDBCursorWithValue, IDBCursor)
490 NS_IMETHODIMP
491 IDBCursor::GetDirection(nsAString& aDirection)
493 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
495 switch (mDirection) {
496 case NEXT:
497 aDirection.AssignLiteral("next");
498 break;
499 case NEXT_UNIQUE:
500 aDirection.AssignLiteral("nextunique");
501 break;
502 case PREV:
503 aDirection.AssignLiteral("prev");
504 break;
505 case PREV_UNIQUE:
506 aDirection.AssignLiteral("prevunique");
507 break;
509 case DIRECTION_INVALID:
510 default:
511 NS_NOTREACHED("Bad direction value!");
512 return NS_ERROR_UNEXPECTED;
515 return NS_OK;
518 NS_IMETHODIMP
519 IDBCursor::GetSource(nsISupports** aSource)
521 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
523 return mType == OBJECTSTORE ?
524 CallQueryInterface(mObjectStore, aSource) :
525 CallQueryInterface(mIndex, aSource);
528 NS_IMETHODIMP
529 IDBCursor::GetKey(JSContext* aCx,
530 jsval* aKey)
532 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
534 NS_ASSERTION(!mKey.IsUnset() || !mHaveValue, "Bad key!");
536 if (!mHaveValue) {
537 *aKey = JSVAL_VOID;
538 return NS_OK;
541 if (!mHaveCachedKey) {
542 if (!mRooted) {
543 NS_HOLD_JS_OBJECTS(this, IDBCursor);
544 mRooted = true;
547 nsresult rv = mKey.ToJSVal(aCx, mCachedKey);
548 NS_ENSURE_SUCCESS(rv, rv);
550 mHaveCachedKey = true;
553 *aKey = mCachedKey;
554 return NS_OK;
557 NS_IMETHODIMP
558 IDBCursor::GetPrimaryKey(JSContext* aCx,
559 jsval* aValue)
561 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
563 if (!mHaveValue) {
564 *aValue = JSVAL_VOID;
565 return NS_OK;
568 if (!mHaveCachedPrimaryKey) {
569 if (!mRooted) {
570 NS_HOLD_JS_OBJECTS(this, IDBCursor);
571 mRooted = true;
574 JSAutoRequest ar(aCx);
576 NS_ASSERTION(mType == OBJECTSTORE ? !mKey.IsUnset() :
577 !mObjectKey.IsUnset(), "Bad key!");
579 const Key& key = mType == OBJECTSTORE ? mKey : mObjectKey;
581 nsresult rv = key.ToJSVal(aCx, mCachedPrimaryKey);
582 NS_ENSURE_SUCCESS(rv, rv);
584 mHaveCachedPrimaryKey = true;
587 *aValue = mCachedPrimaryKey;
588 return NS_OK;
591 NS_IMETHODIMP
592 IDBCursor::GetValue(JSContext* aCx,
593 jsval* aValue)
595 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
596 NS_ASSERTION(mType != INDEXKEY, "GetValue shouldn't exist on index keys");
598 if (!mHaveValue) {
599 *aValue = JSVAL_VOID;
600 return NS_OK;
603 if (!mHaveCachedValue) {
604 if (!mRooted) {
605 NS_HOLD_JS_OBJECTS(this, IDBCursor);
606 mRooted = true;
609 JS::Rooted<JS::Value> val(aCx);
610 if (!IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, &val)) {
611 return NS_ERROR_DOM_DATA_CLONE_ERR;
614 mCloneReadInfo.mCloneBuffer.clear();
616 mCachedValue = val;
617 mHaveCachedValue = true;
620 *aValue = mCachedValue;
621 return NS_OK;
624 NS_IMETHODIMP
625 IDBCursor::Continue(const jsval& aKey,
626 JSContext* aCx)
628 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
630 Key key;
631 nsresult rv = key.SetFromJSVal(aCx, aKey);
632 NS_ENSURE_SUCCESS(rv, rv);
634 if (!key.IsUnset()) {
635 switch (mDirection) {
636 case IDBCursor::NEXT:
637 case IDBCursor::NEXT_UNIQUE:
638 if (key <= mKey) {
639 return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
641 break;
643 case IDBCursor::PREV:
644 case IDBCursor::PREV_UNIQUE:
645 if (key >= mKey) {
646 return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
648 break;
650 default:
651 NS_NOTREACHED("Unknown direction type!");
655 rv = ContinueInternal(key, 1);
656 if (NS_FAILED(rv)) {
657 return rv;
660 #ifdef IDB_PROFILER_USE_MARKS
661 if (mType == OBJECTSTORE) {
662 IDB_PROFILER_MARK("IndexedDB Request %llu: "
663 "database(%s).transaction(%s).objectStore(%s).cursor(%s)."
664 "continue(%s)",
665 "IDBRequest[%llu] MT IDBCursor.continue()",
666 Request()->GetSerialNumber(),
667 IDB_PROFILER_STRING(Transaction()->Database()),
668 IDB_PROFILER_STRING(Transaction()),
669 IDB_PROFILER_STRING(mObjectStore),
670 IDB_PROFILER_STRING(mDirection),
671 key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
673 else {
674 IDB_PROFILER_MARK("IndexedDB Request %llu: "
675 "database(%s).transaction(%s).objectStore(%s).index(%s)."
676 "cursor(%s).continue(%s)",
677 "IDBRequest[%llu] MT IDBCursor.continue()",
678 Request()->GetSerialNumber(),
679 IDB_PROFILER_STRING(Transaction()->Database()),
680 IDB_PROFILER_STRING(Transaction()),
681 IDB_PROFILER_STRING(mObjectStore),
682 IDB_PROFILER_STRING(mIndex),
683 IDB_PROFILER_STRING(mDirection),
684 key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
686 #endif
688 return NS_OK;
691 NS_IMETHODIMP
692 IDBCursor::Update(const jsval& aValue,
693 JSContext* aCx,
694 nsIIDBRequest** _retval)
696 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
698 if (!mTransaction->IsOpen()) {
699 return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
702 if (!mTransaction->IsWriteAllowed()) {
703 return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
706 if (!mHaveValue || mType == INDEXKEY) {
707 return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
710 NS_ASSERTION(mObjectStore, "This cannot be null!");
711 NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
712 NS_ASSERTION(mType != INDEXOBJECT || !mObjectKey.IsUnset(), "Bad key!");
714 nsresult rv;
716 JSAutoRequest ar(aCx);
718 Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
720 nsCOMPtr<nsIIDBRequest> request;
721 if (mObjectStore->HasValidKeyPath()) {
722 // Make sure the object given has the correct keyPath value set on it.
723 const KeyPath& keyPath = mObjectStore->GetKeyPath();
724 Key key;
726 rv = keyPath.ExtractKey(aCx, aValue, key);
727 if (NS_FAILED(rv)) {
728 return rv;
731 if (key != objectKey) {
732 return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
735 rv = mObjectStore->Put(aValue, JSVAL_VOID, aCx, 0, getter_AddRefs(request));
736 if (NS_FAILED(rv)) {
737 return rv;
740 else {
741 JS::Rooted<JS::Value> keyVal(aCx);
742 rv = objectKey.ToJSVal(aCx, &keyVal);
743 NS_ENSURE_SUCCESS(rv, rv);
745 rv = mObjectStore->Put(aValue, keyVal, aCx, 1, getter_AddRefs(request));
746 if (NS_FAILED(rv)) {
747 return rv;
751 #ifdef IDB_PROFILER_USE_MARKS
753 uint64_t requestSerial =
754 static_cast<IDBRequest*>(request.get())->GetSerialNumber();
755 if (mType == OBJECTSTORE) {
756 IDB_PROFILER_MARK("IndexedDB Request %llu: "
757 "database(%s).transaction(%s).objectStore(%s)."
758 "cursor(%s).update(%s)",
759 "IDBRequest[%llu] MT IDBCursor.update()",
760 requestSerial,
761 IDB_PROFILER_STRING(mTransaction->Database()),
762 IDB_PROFILER_STRING(mTransaction),
763 IDB_PROFILER_STRING(mObjectStore),
764 IDB_PROFILER_STRING(mDirection),
765 mObjectStore->HasValidKeyPath() ? "" :
766 IDB_PROFILER_STRING(objectKey));
768 else {
769 IDB_PROFILER_MARK("IndexedDB Request %llu: "
770 "database(%s).transaction(%s).objectStore(%s)."
771 "index(%s).cursor(%s).update(%s)",
772 "IDBRequest[%llu] MT IDBCursor.update()",
773 requestSerial,
774 IDB_PROFILER_STRING(mTransaction->Database()),
775 IDB_PROFILER_STRING(mTransaction),
776 IDB_PROFILER_STRING(mObjectStore),
777 IDB_PROFILER_STRING(mIndex),
778 IDB_PROFILER_STRING(mDirection),
779 mObjectStore->HasValidKeyPath() ? "" :
780 IDB_PROFILER_STRING(objectKey));
783 #endif
785 request.forget(_retval);
786 return NS_OK;
789 NS_IMETHODIMP
790 IDBCursor::Delete(JSContext* aCx,
791 nsIIDBRequest** _retval)
793 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
795 if (!mTransaction->IsOpen()) {
796 return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
799 if (!mTransaction->IsWriteAllowed()) {
800 return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
803 if (!mHaveValue || mType == INDEXKEY) {
804 return NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR;
807 NS_ASSERTION(mObjectStore, "This cannot be null!");
808 NS_ASSERTION(!mKey.IsUnset() , "Bad key!");
810 Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
812 JS::Rooted<JS::Value> key(aCx);
813 nsresult rv = objectKey.ToJSVal(aCx, &key);
814 NS_ENSURE_SUCCESS(rv, rv);
816 nsCOMPtr<nsIIDBRequest> request;
817 rv = mObjectStore->Delete(key, aCx, getter_AddRefs(request));
818 if (NS_FAILED(rv)) {
819 return rv;
822 #ifdef IDB_PROFILER_USE_MARKS
824 uint64_t requestSerial =
825 static_cast<IDBRequest*>(request.get())->GetSerialNumber();
826 if (mType == OBJECTSTORE) {
827 IDB_PROFILER_MARK("IndexedDB Request %llu: "
828 "database(%s).transaction(%s).objectStore(%s)."
829 "cursor(%s).delete(%s)",
830 "IDBRequest[%llu] MT IDBCursor.delete()",
831 requestSerial,
832 IDB_PROFILER_STRING(mTransaction->Database()),
833 IDB_PROFILER_STRING(mTransaction),
834 IDB_PROFILER_STRING(mObjectStore),
835 IDB_PROFILER_STRING(mDirection),
836 mObjectStore->HasValidKeyPath() ? "" :
837 IDB_PROFILER_STRING(objectKey));
839 else {
840 IDB_PROFILER_MARK("IndexedDB Request %llu: "
841 "database(%s).transaction(%s).objectStore(%s)."
842 "index(%s).cursor(%s).delete(%s)",
843 "IDBRequest[%llu] MT IDBCursor.delete()",
844 requestSerial,
845 IDB_PROFILER_STRING(mTransaction->Database()),
846 IDB_PROFILER_STRING(mTransaction),
847 IDB_PROFILER_STRING(mObjectStore),
848 IDB_PROFILER_STRING(mIndex),
849 IDB_PROFILER_STRING(mDirection),
850 mObjectStore->HasValidKeyPath() ? "" :
851 IDB_PROFILER_STRING(objectKey));
854 #endif
856 request.forget(_retval);
857 return NS_OK;
860 NS_IMETHODIMP
861 IDBCursor::Advance(int64_t aCount)
863 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
865 if (aCount < 1 || aCount > UINT32_MAX) {
866 return NS_ERROR_TYPE_ERR;
869 Key key;
870 nsresult rv = ContinueInternal(key, int32_t(aCount));
871 if (NS_FAILED(rv)) {
872 return rv;
875 #ifdef IDB_PROFILER_USE_MARKS
877 if (mType == OBJECTSTORE) {
878 IDB_PROFILER_MARK("IndexedDB Request %llu: "
879 "database(%s).transaction(%s).objectStore(%s)."
880 "cursor(%s).advance(%ld)",
881 "IDBRequest[%llu] MT IDBCursor.advance()",
882 Request()->GetSerialNumber(),
883 IDB_PROFILER_STRING(Transaction()->Database()),
884 IDB_PROFILER_STRING(Transaction()),
885 IDB_PROFILER_STRING(mObjectStore),
886 IDB_PROFILER_STRING(mDirection), aCount);
888 else {
889 IDB_PROFILER_MARK("IndexedDB Request %llu: "
890 "database(%s).transaction(%s).objectStore(%s)."
891 "index(%s).cursor(%s).advance(%ld)",
892 "IDBRequest[%llu] MT IDBCursor.advance()",
893 Request()->GetSerialNumber(),
894 IDB_PROFILER_STRING(Transaction()->Database()),
895 IDB_PROFILER_STRING(Transaction()),
896 IDB_PROFILER_STRING(mObjectStore),
897 IDB_PROFILER_STRING(mIndex),
898 IDB_PROFILER_STRING(mDirection), aCount);
901 #endif
903 return NS_OK;
906 void
907 CursorHelper::ReleaseMainThreadObjects()
909 mCursor = nullptr;
910 AsyncConnectionHelper::ReleaseMainThreadObjects();
913 nsresult
914 CursorHelper::Dispatch(nsIEventTarget* aDatabaseThread)
916 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
918 PROFILER_MAIN_THREAD_LABEL("IndexedDB", "CursorHelper::Dispatch");
920 if (IndexedDatabaseManager::IsMainProcess()) {
921 return AsyncConnectionHelper::Dispatch(aDatabaseThread);
924 // If we've been invalidated then there's no point sending anything to the
925 // parent process.
926 if (mCursor->Transaction()->Database()->IsInvalidated()) {
927 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
930 IndexedDBCursorChild* cursorActor = mCursor->GetActorChild();
931 NS_ASSERTION(cursorActor, "Must have an actor here!");
933 CursorRequestParams params;
934 nsresult rv = PackArgumentsForParentProcess(params);
935 NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
937 NoDispatchEventTarget target;
938 rv = AsyncConnectionHelper::Dispatch(&target);
939 NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
941 mActor = new IndexedDBCursorRequestChild(this, mCursor, params.type());
942 cursorActor->SendPIndexedDBRequestConstructor(mActor, params);
944 return NS_OK;
947 nsresult
948 ContinueHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
950 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
951 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
953 PROFILER_LABEL("IndexedDB", "ContinueHelper::DoDatabaseWork");
955 // We need to pick a query based on whether or not the cursor's mContinueToKey
956 // is set. If it is unset then othing was passed to continue so we'll grab the
957 // next item in the database that is greater than (less than, if we're running
958 // a PREV cursor) the current key. If it is set then a key was passed to
959 // continue so we'll grab the next item in the database that is greater than
960 // (less than, if we're running a PREV cursor) or equal to the key that was
961 // specified.
963 nsAutoCString query;
964 if (mCursor->mContinueToKey.IsUnset()) {
965 query.Assign(mCursor->mContinueQuery);
967 else {
968 query.Assign(mCursor->mContinueToQuery);
970 NS_ASSERTION(!query.IsEmpty(), "Bad query!");
972 query.AppendInt(mCount);
974 nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
975 NS_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
977 mozStorageStatementScoper scoper(stmt);
979 nsresult rv = BindArgumentsToStatement(stmt);
980 NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
982 NS_ASSERTION(mCount > 0, "Not ok!");
984 bool hasResult;
985 for (int32_t index = 0; index < mCount; index++) {
986 rv = stmt->ExecuteStep(&hasResult);
987 NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
989 if (!hasResult) {
990 break;
994 if (hasResult) {
995 rv = GatherResultsFromStatement(stmt);
996 NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
998 else {
999 mKey.Unset();
1002 return NS_OK;
1005 nsresult
1006 ContinueHelper::GetSuccessResult(JSContext* aCx,
1007 JS::MutableHandle<JS::Value> aVal)
1009 UpdateCursorState();
1011 if (mKey.IsUnset()) {
1012 aVal.setNull();
1014 else {
1015 nsresult rv = WrapNative(aCx, mCursor, aVal);
1016 NS_ENSURE_SUCCESS(rv, rv);
1019 return NS_OK;
1022 void
1023 ContinueHelper::ReleaseMainThreadObjects()
1025 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
1026 CursorHelper::ReleaseMainThreadObjects();
1029 nsresult
1030 ContinueHelper::PackArgumentsForParentProcess(CursorRequestParams& aParams)
1032 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1033 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1035 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1036 "ContinueHelper::PackArgumentsForParentProcess");
1038 ContinueParams params;
1040 params.key() = mCursor->mContinueToKey;
1041 params.count() = uint32_t(mCount);
1043 aParams = params;
1044 return NS_OK;
1047 AsyncConnectionHelper::ChildProcessSendResult
1048 ContinueHelper::SendResponseToChildProcess(nsresult aResultCode)
1050 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1051 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1053 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1054 "ContinueHelper::SendResponseToChildProcess");
1056 IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
1057 NS_ASSERTION(actor, "How did we get this far without an actor?");
1059 InfallibleTArray<PBlobParent*> blobsParent;
1061 if (NS_SUCCEEDED(aResultCode)) {
1062 IDBDatabase* database = mTransaction->Database();
1063 NS_ASSERTION(database, "This should never be null!");
1065 ContentParent* contentParent = database->GetContentParent();
1066 NS_ASSERTION(contentParent, "This should never be null!");
1068 FileManager* fileManager = database->Manager();
1069 NS_ASSERTION(fileManager, "This should never be null!");
1071 const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
1073 aResultCode =
1074 IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
1075 blobsParent);
1076 if (NS_FAILED(aResultCode)) {
1077 NS_WARNING("ConvertBlobsToActors failed!");
1081 ResponseValue response;
1082 if (NS_FAILED(aResultCode)) {
1083 response = aResultCode;
1085 else {
1086 ContinueResponse continueResponse;
1087 continueResponse.key() = mKey;
1088 continueResponse.objectKey() = mObjectKey;
1089 continueResponse.cloneInfo() = mCloneReadInfo;
1090 continueResponse.blobsParent().SwapElements(blobsParent);
1091 response = continueResponse;
1094 if (!actor->SendResponse(response)) {
1095 return Error;
1098 UpdateCursorState();
1100 return Success_Sent;
1103 nsresult
1104 ContinueHelper::UnpackResponseFromParentProcess(
1105 const ResponseValue& aResponseValue)
1107 NS_ASSERTION(aResponseValue.type() == ResponseValue::TContinueResponse,
1108 "Bad response type!");
1110 const ContinueResponse& response = aResponseValue.get_ContinueResponse();
1112 mKey = response.key();
1113 mObjectKey = response.objectKey();
1115 const SerializedStructuredCloneReadInfo& cloneInfo = response.cloneInfo();
1117 NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
1118 (cloneInfo.dataLength && cloneInfo.data),
1119 "Inconsistent clone info!");
1121 if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
1122 NS_WARNING("Failed to copy clone buffer!");
1123 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1126 IDBObjectStore::ConvertActorsToBlobs(response.blobsChild(),
1127 mCloneReadInfo.mFiles);
1128 return NS_OK;
1131 nsresult
1132 ContinueObjectStoreHelper::BindArgumentsToStatement(
1133 mozIStorageStatement* aStatement)
1135 // Bind object store id.
1136 nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
1137 mCursor->mObjectStore->Id());
1138 NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1140 NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
1141 NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
1143 // Bind current key.
1144 const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
1145 mCursor->mKey :
1146 mCursor->mContinueToKey;
1148 rv = currentKey.BindToStatement(aStatement, currentKeyName);
1149 NS_ENSURE_SUCCESS(rv, rv);
1151 // Bind range key if it is specified.
1152 const Key& rangeKey = mCursor->mRangeKey;
1154 if (!rangeKey.IsUnset()) {
1155 rv = rangeKey.BindToStatement(aStatement, rangeKeyName);
1156 NS_ENSURE_SUCCESS(rv, rv);
1159 return NS_OK;
1162 nsresult
1163 ContinueObjectStoreHelper::GatherResultsFromStatement(
1164 mozIStorageStatement* aStatement)
1166 // Figure out what kind of key we have next.
1167 nsresult rv = mKey.SetFromStatement(aStatement, 0);
1168 NS_ENSURE_SUCCESS(rv, rv);
1170 rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 1, 2,
1171 mDatabase, mCloneReadInfo);
1172 NS_ENSURE_SUCCESS(rv, rv);
1174 return NS_OK;
1177 nsresult
1178 ContinueIndexHelper::BindArgumentsToStatement(mozIStorageStatement* aStatement)
1180 // Bind index id.
1181 nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
1182 mCursor->mIndex->Id());
1183 NS_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1185 NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
1187 // Bind current key.
1188 const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
1189 mCursor->mKey :
1190 mCursor->mContinueToKey;
1192 rv = currentKey.BindToStatement(aStatement, currentKeyName);
1193 NS_ENSURE_SUCCESS(rv, rv);
1195 // Bind range key if it is specified.
1196 if (!mCursor->mRangeKey.IsUnset()) {
1197 NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
1198 rv = mCursor->mRangeKey.BindToStatement(aStatement, rangeKeyName);
1199 NS_ENSURE_SUCCESS(rv, rv);
1202 // Bind object key if duplicates are allowed and we're not continuing to a
1203 // specific key.
1204 if ((mCursor->mDirection == IDBCursor::NEXT ||
1205 mCursor->mDirection == IDBCursor::PREV) &&
1206 mCursor->mContinueToKey.IsUnset()) {
1207 NS_ASSERTION(!mCursor->mObjectKey.IsUnset(), "Bad key!");
1209 NS_NAMED_LITERAL_CSTRING(objectKeyName, "object_key");
1210 rv = mCursor->mObjectKey.BindToStatement(aStatement, objectKeyName);
1211 NS_ENSURE_SUCCESS(rv, rv);
1214 return NS_OK;
1217 nsresult
1218 ContinueIndexHelper::GatherResultsFromStatement(
1219 mozIStorageStatement* aStatement)
1221 nsresult rv = mKey.SetFromStatement(aStatement, 0);
1222 NS_ENSURE_SUCCESS(rv, rv);
1224 rv = mObjectKey.SetFromStatement(aStatement, 1);
1225 NS_ENSURE_SUCCESS(rv, rv);
1227 return NS_OK;
1230 nsresult
1231 ContinueIndexObjectHelper::GatherResultsFromStatement(
1232 mozIStorageStatement* aStatement)
1234 nsresult rv = mKey.SetFromStatement(aStatement, 0);
1235 NS_ENSURE_SUCCESS(rv, rv);
1237 rv = mObjectKey.SetFromStatement(aStatement, 1);
1238 NS_ENSURE_SUCCESS(rv, rv);
1240 rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 2, 3,
1241 mDatabase, mCloneReadInfo);
1242 NS_ENSURE_SUCCESS(rv, rv);
1244 return NS_OK;