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"
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"
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");
41 class CursorHelper
: public AsyncConnectionHelper
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
;
56 PackArgumentsForParentProcess(CursorRequestParams
& aParams
) = 0;
59 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
) = 0;
62 nsRefPtr
<IDBCursor
> mCursor
;
65 IndexedDBCursorRequestChild
* mActor
;
68 } // anonymous namespace
70 BEGIN_INDEXEDDB_NAMESPACE
72 class ContinueHelper
: public CursorHelper
75 ContinueHelper(IDBCursor
* aCursor
,
77 : CursorHelper(aCursor
), mCount(aCount
)
79 NS_ASSERTION(aCount
> 0, "Must have a count!");
84 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo
);
87 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
90 virtual nsresult
GetSuccessResult(JSContext
* aCx
,
91 JS::MutableHandle
<JS::Value
> aVal
) MOZ_OVERRIDE
;
93 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE
;
96 PackArgumentsForParentProcess(CursorRequestParams
& aParams
) MOZ_OVERRIDE
;
98 virtual ChildProcessSendResult
99 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
102 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
107 BindArgumentsToStatement(mozIStorageStatement
* aStatement
) = 0;
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;
126 NS_ASSERTION(mCursor
->mType
== IDBCursor::OBJECTSTORE
||
127 !mObjectKey
.IsUnset(), "Bad key!");
130 mCursor
->mKey
= mKey
;
131 mCursor
->mObjectKey
= mObjectKey
;
132 mCursor
->mContinueToKey
.Unset();
134 mCursor
->mCloneReadInfo
.Swap(mCloneReadInfo
);
135 mCloneReadInfo
.mCloneBuffer
.clear();
142 StructuredCloneReadInfo mCloneReadInfo
;
145 class ContinueObjectStoreHelper
: public ContinueHelper
148 ContinueObjectStoreHelper(IDBCursor
* aCursor
,
150 : ContinueHelper(aCursor
, aCount
)
154 nsresult
BindArgumentsToStatement(mozIStorageStatement
* aStatement
);
155 nsresult
GatherResultsFromStatement(mozIStorageStatement
* aStatement
);
158 class ContinueIndexHelper
: public ContinueHelper
161 ContinueIndexHelper(IDBCursor
* aCursor
,
163 : ContinueHelper(aCursor
, aCount
)
167 nsresult
BindArgumentsToStatement(mozIStorageStatement
* aStatement
);
168 nsresult
GatherResultsFromStatement(mozIStorageStatement
* aStatement
);
171 class ContinueIndexObjectHelper
: public ContinueIndexHelper
174 ContinueIndexObjectHelper(IDBCursor
* aCursor
,
176 : ContinueIndexHelper(aCursor
, aCount
)
180 nsresult
GatherResultsFromStatement(mozIStorageStatement
* aStatement
);
183 END_INDEXEDDB_NAMESPACE
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
,
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
;
208 cursor
->mCloneReadInfo
.Swap(aCloneReadInfo
);
210 return cursor
.forget();
214 already_AddRefed
<IDBCursor
>
215 IDBCursor::Create(IDBRequest
* aRequest
,
216 IDBTransaction
* aTransaction
,
218 Direction aDirection
,
219 const Key
& aRangeKey
,
220 const nsACString
& aContinueQuery
,
221 const nsACString
& aContinueToQuery
,
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
,
233 NS_ASSERTION(cursor
, "This shouldn't fail!");
235 cursor
->mIndex
= aIndex
;
236 cursor
->mType
= INDEXKEY
;
238 cursor
->mObjectKey
= aObjectKey
;
240 return cursor
.forget();
244 already_AddRefed
<IDBCursor
>
245 IDBCursor::Create(IDBRequest
* aRequest
,
246 IDBTransaction
* aTransaction
,
248 Direction aDirection
,
249 const Key
& aRangeKey
,
250 const nsACString
& aContinueQuery
,
251 const nsACString
& aContinueToQuery
,
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
,
263 NS_ASSERTION(cursor
, "This shouldn't fail!");
265 cursor
->mObjectStore
= aIndex
->ObjectStore();
266 cursor
->mIndex
= aIndex
;
267 cursor
->mType
= INDEXOBJECT
;
269 cursor
->mObjectKey
= aObjectKey
;
270 cursor
->mCloneReadInfo
.Swap(aCloneReadInfo
);
272 return cursor
.forget();
277 IDBCursor::ParseDirection(const nsAString
& aDirection
, Direction
* aResult
)
279 if (aDirection
.EqualsLiteral("next")) {
282 else if (aDirection
.EqualsLiteral("nextunique")) {
283 *aResult
= NEXT_UNIQUE
;
285 else if (aDirection
.EqualsLiteral("prev")) {
288 else if (aDirection
.EqualsLiteral("prevunique")) {
289 *aResult
= PREV_UNIQUE
;
292 return NS_ERROR_TYPE_ERR
;
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(),
315 NS_ASSERTION(!aContinueToQuery
.IsEmpty() ||
316 !IndexedDatabaseManager::IsMainProcess(),
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),
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),
353 mContinueCalled(false),
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?!");
365 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
366 mActorChild
->Send__delete__(mActorChild
);
367 NS_ASSERTION(!mActorChild
, "Should have cleared in Send__delete__!");
371 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo
);
375 IDBCursor::DropJSObjects()
380 mScriptOwner
= nullptr;
381 mCachedKey
= JSVAL_VOID
;
382 mCachedPrimaryKey
= JSVAL_VOID
;
383 mCachedValue
= JSVAL_VOID
;
384 mHaveCachedKey
= false;
385 mHaveCachedPrimaryKey
= false;
386 mHaveCachedValue
= false;
389 NS_DROP_JS_OBJECTS(this, IDBCursor
);
393 IDBCursor::ContinueInternal(const Key
& aKey
,
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
;
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!");
421 nsRefPtr
<ContinueHelper
> helper
;
424 helper
= new ContinueObjectStoreHelper(this, aCount
);
428 helper
= new ContinueIndexHelper(this, aCount
);
432 helper
= new ContinueIndexObjectHelper(this, aCount
);
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;
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
,
479 NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO_CONDITIONAL(IDBCursor
,
481 NS_INTERFACE_MAP_ENTRY(nsISupports
)
484 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor
)
485 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor
)
487 DOMCI_DATA(IDBCursor
, IDBCursor
)
488 DOMCI_DATA(IDBCursorWithValue
, IDBCursor
)
491 IDBCursor::GetDirection(nsAString
& aDirection
)
493 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
495 switch (mDirection
) {
497 aDirection
.AssignLiteral("next");
500 aDirection
.AssignLiteral("nextunique");
503 aDirection
.AssignLiteral("prev");
506 aDirection
.AssignLiteral("prevunique");
509 case DIRECTION_INVALID
:
511 NS_NOTREACHED("Bad direction value!");
512 return NS_ERROR_UNEXPECTED
;
519 IDBCursor::GetSource(nsISupports
** aSource
)
521 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
523 return mType
== OBJECTSTORE
?
524 CallQueryInterface(mObjectStore
, aSource
) :
525 CallQueryInterface(mIndex
, aSource
);
529 IDBCursor::GetKey(JSContext
* aCx
,
532 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
534 NS_ASSERTION(!mKey
.IsUnset() || !mHaveValue
, "Bad key!");
541 if (!mHaveCachedKey
) {
543 NS_HOLD_JS_OBJECTS(this, IDBCursor
);
547 nsresult rv
= mKey
.ToJSVal(aCx
, mCachedKey
);
548 NS_ENSURE_SUCCESS(rv
, rv
);
550 mHaveCachedKey
= true;
558 IDBCursor::GetPrimaryKey(JSContext
* aCx
,
561 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
564 *aValue
= JSVAL_VOID
;
568 if (!mHaveCachedPrimaryKey
) {
570 NS_HOLD_JS_OBJECTS(this, IDBCursor
);
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
;
592 IDBCursor::GetValue(JSContext
* aCx
,
595 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
596 NS_ASSERTION(mType
!= INDEXKEY
, "GetValue shouldn't exist on index keys");
599 *aValue
= JSVAL_VOID
;
603 if (!mHaveCachedValue
) {
605 NS_HOLD_JS_OBJECTS(this, IDBCursor
);
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();
617 mHaveCachedValue
= true;
620 *aValue
= mCachedValue
;
625 IDBCursor::Continue(const jsval
& aKey
,
628 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
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
:
639 return NS_ERROR_DOM_INDEXEDDB_DATA_ERR
;
643 case IDBCursor::PREV
:
644 case IDBCursor::PREV_UNIQUE
:
646 return NS_ERROR_DOM_INDEXEDDB_DATA_ERR
;
651 NS_NOTREACHED("Unknown direction type!");
655 rv
= ContinueInternal(key
, 1);
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)."
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
));
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
));
692 IDBCursor::Update(const jsval
& aValue
,
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!");
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();
726 rv
= keyPath
.ExtractKey(aCx
, aValue
, key
);
731 if (key
!= objectKey
) {
732 return NS_ERROR_DOM_INDEXEDDB_DATA_ERR
;
735 rv
= mObjectStore
->Put(aValue
, JSVAL_VOID
, aCx
, 0, getter_AddRefs(request
));
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
));
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()",
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
));
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()",
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
));
785 request
.forget(_retval
);
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
));
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()",
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
));
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()",
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
));
856 request
.forget(_retval
);
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
;
870 nsresult rv
= ContinueInternal(key
, int32_t(aCount
));
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
);
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
);
907 CursorHelper::ReleaseMainThreadObjects()
910 AsyncConnectionHelper::ReleaseMainThreadObjects();
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
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
);
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
964 if (mCursor
->mContinueToKey
.IsUnset()) {
965 query
.Assign(mCursor
->mContinueQuery
);
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!");
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
);
995 rv
= GatherResultsFromStatement(stmt
);
996 NS_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1006 ContinueHelper::GetSuccessResult(JSContext
* aCx
,
1007 JS::MutableHandle
<JS::Value
> aVal
)
1009 UpdateCursorState();
1011 if (mKey
.IsUnset()) {
1015 nsresult rv
= WrapNative(aCx
, mCursor
, aVal
);
1016 NS_ENSURE_SUCCESS(rv
, rv
);
1023 ContinueHelper::ReleaseMainThreadObjects()
1025 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo
);
1026 CursorHelper::ReleaseMainThreadObjects();
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
);
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
;
1074 IDBObjectStore::ConvertBlobsToActors(contentParent
, fileManager
, files
,
1076 if (NS_FAILED(aResultCode
)) {
1077 NS_WARNING("ConvertBlobsToActors failed!");
1081 ResponseValue response
;
1082 if (NS_FAILED(aResultCode
)) {
1083 response
= aResultCode
;
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
)) {
1098 UpdateCursorState();
1100 return Success_Sent
;
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
);
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() ?
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
);
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
);
1178 ContinueIndexHelper::BindArgumentsToStatement(mozIStorageStatement
* aStatement
)
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() ?
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
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
);
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
);
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
);