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 "IDBObjectStore.h"
11 #include "mozilla/dom/ipc/nsIRemoteBlob.h"
12 #include "nsIOutputStream.h"
15 #include "jsfriendapi.h"
16 #include "mozilla/dom/ContentChild.h"
17 #include "mozilla/dom/IDBMutableFileBinding.h"
18 #include "mozilla/dom/nsIContentParent.h"
19 #include "mozilla/dom/StructuredCloneTags.h"
20 #include "mozilla/dom/TabChild.h"
21 #include "mozilla/dom/ipc/Blob.h"
22 #include "mozilla/dom/quota/FileStreams.h"
23 #include "mozilla/Endian.h"
24 #include "mozilla/storage.h"
25 #include "nsContentUtils.h"
26 #include "nsDOMClassInfo.h"
27 #include "nsDOMFile.h"
28 #include "mozilla/dom/DOMStringList.h"
29 #include "nsJSUtils.h"
30 #include "nsServiceManagerUtils.h"
31 #include "nsThreadUtils.h"
32 #include "snappy/snappy.h"
34 #include "AsyncConnectionHelper.h"
35 #include "IDBCursor.h"
36 #include "IDBEvents.h"
38 #include "IDBKeyRange.h"
39 #include "IDBMutableFile.h"
40 #include "IDBTransaction.h"
41 #include "DatabaseInfo.h"
43 #include "ProfilerHelpers.h"
44 #include "ReportInternalError.h"
46 #include "ipc/IndexedDBChild.h"
47 #include "ipc/IndexedDBParent.h"
49 #include "IndexedDatabaseInlines.h"
50 #include "nsCharSeparatedTokenizer.h"
52 #define FILE_COPY_BUFFER_SIZE 32768
54 USING_INDEXEDDB_NAMESPACE
55 using namespace mozilla::dom
;
56 using namespace mozilla::dom::indexedDB::ipc
;
57 using mozilla::dom::quota::FileOutputStream
;
58 using mozilla::ErrorResult
;
59 using mozilla::fallible_t
;
60 using mozilla::LittleEndian
;
62 using mozilla::NativeEndian
;
64 BEGIN_INDEXEDDB_NAMESPACE
66 struct MutableFileData
75 : tag(0), size(0), lastModifiedDate(UINT64_MAX
)
82 uint64_t lastModifiedDate
;
85 END_INDEXEDDB_NAMESPACE
91 IgnoreNothing(char16_t c
)
96 class ObjectStoreHelper
: public AsyncConnectionHelper
99 ObjectStoreHelper(IDBTransaction
* aTransaction
,
100 IDBRequest
* aRequest
,
101 IDBObjectStore
* aObjectStore
)
102 : AsyncConnectionHelper(aTransaction
, aRequest
), mObjectStore(aObjectStore
),
105 NS_ASSERTION(aTransaction
, "Null transaction!");
106 NS_ASSERTION(aRequest
, "Null request!");
107 NS_ASSERTION(aObjectStore
, "Null object store!");
110 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE
;
112 virtual nsresult
Dispatch(nsIEventTarget
* aDatabaseThread
) MOZ_OVERRIDE
;
115 PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
116 nsIContentChild
* aBlobCreator
) = 0;
119 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
) = 0;
122 nsRefPtr
<IDBObjectStore
> mObjectStore
;
125 IndexedDBObjectStoreRequestChild
* mActor
;
128 class NoRequestObjectStoreHelper
: public AsyncConnectionHelper
131 NoRequestObjectStoreHelper(IDBTransaction
* aTransaction
,
132 IDBObjectStore
* aObjectStore
)
133 : AsyncConnectionHelper(aTransaction
, nullptr), mObjectStore(aObjectStore
)
135 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
136 NS_ASSERTION(aTransaction
, "Null transaction!");
137 NS_ASSERTION(aObjectStore
, "Null object store!");
140 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE
;
142 virtual nsresult
UnpackResponseFromParentProcess(
143 const ResponseValue
& aResponseValue
)
146 virtual ChildProcessSendResult
147 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
149 virtual nsresult
OnSuccess() MOZ_OVERRIDE
;
151 virtual void OnError() MOZ_OVERRIDE
;
154 nsRefPtr
<IDBObjectStore
> mObjectStore
;
157 class AddHelper
: public ObjectStoreHelper
160 AddHelper(IDBTransaction
* aTransaction
,
161 IDBRequest
* aRequest
,
162 IDBObjectStore
* aObjectStore
,
163 StructuredCloneWriteInfo
&& aCloneWriteInfo
,
166 nsTArray
<IndexUpdateInfo
>& aIndexUpdateInfo
)
167 : ObjectStoreHelper(aTransaction
, aRequest
, aObjectStore
),
168 mCloneWriteInfo(Move(aCloneWriteInfo
)),
170 mOverwrite(aOverwrite
)
172 mIndexUpdateInfo
.SwapElements(aIndexUpdateInfo
);
177 IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo
);
180 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
183 virtual nsresult
GetSuccessResult(JSContext
* aCx
,
184 JS::MutableHandle
<JS::Value
> aVal
) MOZ_OVERRIDE
;
186 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE
;
189 PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
190 nsIContentChild
* aBlobCreator
) MOZ_OVERRIDE
;
192 virtual ChildProcessSendResult
193 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
196 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
200 // These may change in the autoincrement case.
201 StructuredCloneWriteInfo mCloneWriteInfo
;
203 nsTArray
<IndexUpdateInfo
> mIndexUpdateInfo
;
204 const bool mOverwrite
;
207 class GetHelper
: public ObjectStoreHelper
210 GetHelper(IDBTransaction
* aTransaction
,
211 IDBRequest
* aRequest
,
212 IDBObjectStore
* aObjectStore
,
213 IDBKeyRange
* aKeyRange
)
214 : ObjectStoreHelper(aTransaction
, aRequest
, aObjectStore
),
217 NS_ASSERTION(aKeyRange
, "Null key range!");
222 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo
);
225 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
228 virtual nsresult
GetSuccessResult(JSContext
* aCx
,
229 JS::MutableHandle
<JS::Value
> aVal
) MOZ_OVERRIDE
;
231 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE
;
234 PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
235 nsIContentChild
* aBlobCreator
) MOZ_OVERRIDE
;
237 virtual ChildProcessSendResult
238 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
241 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
246 nsRefPtr
<IDBKeyRange
> mKeyRange
;
250 StructuredCloneReadInfo mCloneReadInfo
;
253 class DeleteHelper
: public GetHelper
256 DeleteHelper(IDBTransaction
* aTransaction
,
257 IDBRequest
* aRequest
,
258 IDBObjectStore
* aObjectStore
,
259 IDBKeyRange
* aKeyRange
)
260 : GetHelper(aTransaction
, aRequest
, aObjectStore
, aKeyRange
)
263 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
266 virtual nsresult
GetSuccessResult(JSContext
* aCx
,
267 JS::MutableHandle
<JS::Value
> aVal
) MOZ_OVERRIDE
;
270 PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
271 nsIContentChild
* aBlobCreator
) MOZ_OVERRIDE
;
273 virtual ChildProcessSendResult
274 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
277 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
281 class ClearHelper
: public ObjectStoreHelper
284 ClearHelper(IDBTransaction
* aTransaction
,
285 IDBRequest
* aRequest
,
286 IDBObjectStore
* aObjectStore
)
287 : ObjectStoreHelper(aTransaction
, aRequest
, aObjectStore
)
290 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
294 PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
295 nsIContentChild
* aBlobCreator
) MOZ_OVERRIDE
;
297 virtual ChildProcessSendResult
298 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
301 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
305 class OpenCursorHelper
: public ObjectStoreHelper
308 OpenCursorHelper(IDBTransaction
* aTransaction
,
309 IDBRequest
* aRequest
,
310 IDBObjectStore
* aObjectStore
,
311 IDBKeyRange
* aKeyRange
,
312 IDBCursor::Direction aDirection
)
313 : ObjectStoreHelper(aTransaction
, aRequest
, aObjectStore
),
314 mKeyRange(aKeyRange
), mDirection(aDirection
)
319 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo
);
322 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
325 virtual nsresult
GetSuccessResult(JSContext
* aCx
,
326 JS::MutableHandle
<JS::Value
> aVal
) MOZ_OVERRIDE
;
328 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE
;
331 PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
332 nsIContentChild
* aBlobCreator
) MOZ_OVERRIDE
;
334 virtual ChildProcessSendResult
335 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
338 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
342 nsresult
EnsureCursor();
345 nsRefPtr
<IDBKeyRange
> mKeyRange
;
346 const IDBCursor::Direction mDirection
;
350 StructuredCloneReadInfo mCloneReadInfo
;
351 nsCString mContinueQuery
;
352 nsCString mContinueToQuery
;
355 // Only used in the parent process.
356 nsRefPtr
<IDBCursor
> mCursor
;
357 SerializedStructuredCloneReadInfo mSerializedCloneReadInfo
;
360 class OpenKeyCursorHelper MOZ_FINAL
: public ObjectStoreHelper
363 OpenKeyCursorHelper(IDBTransaction
* aTransaction
,
364 IDBRequest
* aRequest
,
365 IDBObjectStore
* aObjectStore
,
366 IDBKeyRange
* aKeyRange
,
367 IDBCursor::Direction aDirection
)
368 : ObjectStoreHelper(aTransaction
, aRequest
, aObjectStore
),
369 mKeyRange(aKeyRange
), mDirection(aDirection
)
373 DoDatabaseWork(mozIStorageConnection
* aConnection
) MOZ_OVERRIDE
;
376 GetSuccessResult(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aVal
)
380 ReleaseMainThreadObjects() MOZ_OVERRIDE
;
383 PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
384 nsIContentChild
* aBlobCreator
) MOZ_OVERRIDE
;
386 virtual ChildProcessSendResult
387 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
390 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
394 ~OpenKeyCursorHelper()
397 nsresult
EnsureCursor();
400 nsRefPtr
<IDBKeyRange
> mKeyRange
;
401 const IDBCursor::Direction mDirection
;
405 nsCString mContinueQuery
;
406 nsCString mContinueToQuery
;
409 // Only used in the parent process.
410 nsRefPtr
<IDBCursor
> mCursor
;
413 class CreateIndexHelper
: public NoRequestObjectStoreHelper
416 CreateIndexHelper(IDBTransaction
* aTransaction
, IDBIndex
* aIndex
)
417 : NoRequestObjectStoreHelper(aTransaction
, aIndex
->ObjectStore()),
420 if (sTLSIndex
== BAD_TLS_INDEX
) {
421 PR_NewThreadPrivateIndex(&sTLSIndex
, DestroyTLSEntry
);
424 NS_ASSERTION(sTLSIndex
!= BAD_TLS_INDEX
,
425 "PR_NewThreadPrivateIndex failed!");
428 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
431 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE
;
434 nsresult
InsertDataFromObjectStore(mozIStorageConnection
* aConnection
);
436 static void DestroyTLSEntry(void* aPtr
);
438 static unsigned sTLSIndex
;
441 nsRefPtr
<IDBIndex
> mIndex
;
444 unsigned CreateIndexHelper::sTLSIndex
= unsigned(BAD_TLS_INDEX
);
446 class DeleteIndexHelper
: public NoRequestObjectStoreHelper
449 DeleteIndexHelper(IDBTransaction
* aTransaction
,
450 IDBObjectStore
* aObjectStore
,
451 const nsAString
& aName
)
452 : NoRequestObjectStoreHelper(aTransaction
, aObjectStore
), mName(aName
)
455 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
463 class GetAllHelper
: public ObjectStoreHelper
466 GetAllHelper(IDBTransaction
* aTransaction
,
467 IDBRequest
* aRequest
,
468 IDBObjectStore
* aObjectStore
,
469 IDBKeyRange
* aKeyRange
,
470 const uint32_t aLimit
)
471 : ObjectStoreHelper(aTransaction
, aRequest
, aObjectStore
),
472 mKeyRange(aKeyRange
), mLimit(aLimit
)
477 for (uint32_t index
= 0; index
< mCloneReadInfos
.Length(); index
++) {
478 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos
[index
]);
482 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
485 virtual nsresult
GetSuccessResult(JSContext
* aCx
,
486 JS::MutableHandle
<JS::Value
> aVal
) MOZ_OVERRIDE
;
488 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE
;
491 PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
492 nsIContentChild
* aBlobCreator
) MOZ_OVERRIDE
;
494 virtual ChildProcessSendResult
495 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
498 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
503 nsRefPtr
<IDBKeyRange
> mKeyRange
;
504 const uint32_t mLimit
;
508 nsTArray
<StructuredCloneReadInfo
> mCloneReadInfos
;
511 class GetAllKeysHelper MOZ_FINAL
: public ObjectStoreHelper
514 GetAllKeysHelper(IDBTransaction
* aTransaction
,
515 IDBRequest
* aRequest
,
516 IDBObjectStore
* aObjectStore
,
517 IDBKeyRange
* aKeyRange
,
518 const uint32_t aLimit
)
519 : ObjectStoreHelper(aTransaction
, aRequest
, aObjectStore
),
520 mKeyRange(aKeyRange
), mLimit(aLimit
)
524 DoDatabaseWork(mozIStorageConnection
* aConnection
) MOZ_OVERRIDE
;
527 GetSuccessResult(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aVal
)
531 ReleaseMainThreadObjects() MOZ_OVERRIDE
;
534 PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
535 nsIContentChild
* aBlobCreator
) MOZ_OVERRIDE
;
537 virtual ChildProcessSendResult
538 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
541 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
548 nsRefPtr
<IDBKeyRange
> mKeyRange
;
549 const uint32_t mLimit
;
553 class CountHelper
: public ObjectStoreHelper
556 CountHelper(IDBTransaction
* aTransaction
,
557 IDBRequest
* aRequest
,
558 IDBObjectStore
* aObjectStore
,
559 IDBKeyRange
* aKeyRange
)
560 : ObjectStoreHelper(aTransaction
, aRequest
, aObjectStore
),
561 mKeyRange(aKeyRange
), mCount(0)
564 virtual nsresult
DoDatabaseWork(mozIStorageConnection
* aConnection
)
567 virtual nsresult
GetSuccessResult(JSContext
* aCx
,
568 JS::MutableHandle
<JS::Value
> aVal
) MOZ_OVERRIDE
;
570 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE
;
573 PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
574 nsIContentChild
* aBlobCreator
) MOZ_OVERRIDE
;
576 virtual ChildProcessSendResult
577 SendResponseToChildProcess(nsresult aResultCode
) MOZ_OVERRIDE
;
580 UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
584 nsRefPtr
<IDBKeyRange
> mKeyRange
;
588 class MOZ_STACK_CLASS AutoRemoveIndex
591 AutoRemoveIndex(ObjectStoreInfo
* aObjectStoreInfo
,
592 const nsAString
& aIndexName
)
593 : mObjectStoreInfo(aObjectStoreInfo
), mIndexName(aIndexName
)
598 if (mObjectStoreInfo
) {
599 for (uint32_t i
= 0; i
< mObjectStoreInfo
->indexes
.Length(); i
++) {
600 if (mObjectStoreInfo
->indexes
[i
].name
== mIndexName
) {
601 mObjectStoreInfo
->indexes
.RemoveElementAt(i
);
610 mObjectStoreInfo
= nullptr;
614 ObjectStoreInfo
* mObjectStoreInfo
;
618 class ThreadLocalJSRuntime
624 static const JSClass sGlobalClass
;
625 static const unsigned sRuntimeHeapSize
= 768 * 1024;
627 ThreadLocalJSRuntime()
628 : mRuntime(nullptr), mContext(nullptr), mGlobal(nullptr)
630 MOZ_COUNT_CTOR(ThreadLocalJSRuntime
);
635 mRuntime
= JS_NewRuntime(sRuntimeHeapSize
);
636 NS_ENSURE_TRUE(mRuntime
, NS_ERROR_OUT_OF_MEMORY
);
639 * Not setting this will cause JS_CHECK_RECURSION to report false
642 JS_SetNativeStackQuota(mRuntime
, 128 * sizeof(size_t) * 1024);
644 mContext
= JS_NewContext(mRuntime
, 0);
645 NS_ENSURE_TRUE(mContext
, NS_ERROR_OUT_OF_MEMORY
);
647 JSAutoRequest
ar(mContext
);
649 mGlobal
= JS_NewGlobalObject(mContext
, &sGlobalClass
, nullptr,
650 JS::FireOnNewGlobalHook
);
651 NS_ENSURE_TRUE(mGlobal
, NS_ERROR_OUT_OF_MEMORY
);
657 static ThreadLocalJSRuntime
*Create()
659 ThreadLocalJSRuntime
*entry
= new ThreadLocalJSRuntime();
660 NS_ENSURE_TRUE(entry
, nullptr);
662 if (NS_FAILED(entry
->Init())) {
670 JSContext
*Context() const
675 JSObject
*Global() const
680 ~ThreadLocalJSRuntime()
682 MOZ_COUNT_DTOR(ThreadLocalJSRuntime
);
685 JS_DestroyContext(mContext
);
689 JS_DestroyRuntime(mRuntime
);
694 const JSClass
ThreadLocalJSRuntime::sGlobalClass
= {
695 "IndexedDBTransactionThreadGlobal",
696 JSCLASS_GLOBAL_FLAGS
,
697 JS_PropertyStub
, JS_DeletePropertyStub
, JS_PropertyStub
, JS_StrictPropertyStub
,
698 JS_EnumerateStub
, JS_ResolveStub
, JS_ConvertStub
,
699 nullptr, nullptr, nullptr, nullptr,
700 JS_GlobalObjectTraceHook
704 already_AddRefed
<IDBRequest
>
705 GenerateRequest(IDBObjectStore
* aObjectStore
)
707 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
708 IDBDatabase
* database
= aObjectStore
->Transaction()->Database();
709 return IDBRequest::Create(aObjectStore
, database
,
710 aObjectStore
->Transaction());
713 struct MOZ_STACK_CLASS GetAddInfoClosure
715 IDBObjectStore
* mThis
;
716 StructuredCloneWriteInfo
& mCloneWriteInfo
;
717 JS::Handle
<JS::Value
> mValue
;
721 GetAddInfoCallback(JSContext
* aCx
, void* aClosure
)
723 GetAddInfoClosure
* data
= static_cast<GetAddInfoClosure
*>(aClosure
);
725 data
->mCloneWriteInfo
.mOffsetToKeyProp
= 0;
726 data
->mCloneWriteInfo
.mTransaction
= data
->mThis
->Transaction();
728 if (!IDBObjectStore::SerializeValue(aCx
, data
->mCloneWriteInfo
, data
->mValue
)) {
729 return NS_ERROR_DOM_DATA_CLONE_ERR
;
737 ActorFromRemoteBlob(nsIDOMBlob
* aBlob
)
739 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
740 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
742 nsRefPtr
<DOMFile
> blob
= static_cast<DOMFile
*>(aBlob
);
743 nsCOMPtr
<nsIRemoteBlob
> remoteBlob
= do_QueryInterface(blob
->Impl());
746 static_cast<BlobChild
*>(static_cast<PBlobChild
*>(remoteBlob
->GetPBlob()));
747 NS_ASSERTION(actor
, "Null actor?!");
755 ResolveMysteryFile(nsIDOMBlob
* aBlob
, const nsString
& aName
,
756 const nsString
& aContentType
, uint64_t aSize
,
757 uint64_t aLastModifiedDate
)
759 BlobChild
* actor
= ActorFromRemoteBlob(aBlob
);
761 return actor
->SetMysteryBlobInfo(aName
, aContentType
,
762 aSize
, aLastModifiedDate
);
769 ResolveMysteryBlob(nsIDOMBlob
* aBlob
, const nsString
& aContentType
,
772 BlobChild
* actor
= ActorFromRemoteBlob(aBlob
);
774 return actor
->SetMysteryBlobInfo(aContentType
, aSize
);
779 class MainThreadDeserializationTraits
782 static bool CreateAndWrapMutableFile(JSContext
* aCx
,
783 IDBDatabase
* aDatabase
,
784 StructuredCloneFile
& aFile
,
785 const MutableFileData
& aData
,
786 JS::MutableHandle
<JSObject
*> aResult
)
788 MOZ_ASSERT(NS_IsMainThread());
790 nsRefPtr
<FileInfo
>& fileInfo
= aFile
.mFileInfo
;
792 nsRefPtr
<IDBMutableFile
> mutableFile
= IDBMutableFile::Create(aData
.name
,
793 aData
.type
, aDatabase
, fileInfo
.forget());
795 JS::Rooted
<JSObject
*> result(aCx
, mutableFile
->WrapObject(aCx
));
796 if (NS_WARN_IF(!result
)) {
804 static JSObject
* CreateAndWrapBlobOrFile(JSContext
* aCx
,
805 IDBDatabase
* aDatabase
,
806 StructuredCloneFile
& aFile
,
807 const BlobOrFileData
& aData
)
809 MOZ_ASSERT(NS_IsMainThread());
811 MOZ_ASSERT(aData
.tag
== SCTAG_DOM_FILE
||
812 aData
.tag
== SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE
||
813 aData
.tag
== SCTAG_DOM_BLOB
);
817 nsRefPtr
<FileInfo
>& fileInfo
= aFile
.mFileInfo
;
819 nsCOMPtr
<nsIFile
> nativeFile
;
821 FileManager
* fileManager
= aDatabase
->Manager();
822 NS_ASSERTION(fileManager
, "This should never be null!");
824 nsCOMPtr
<nsIFile
> directory
= fileManager
->GetDirectory();
826 NS_WARNING("Failed to get directory!");
830 nativeFile
= fileManager
->GetFileForId(directory
, fileInfo
->Id());
832 NS_WARNING("Failed to get file!");
837 if (aData
.tag
== SCTAG_DOM_BLOB
) {
838 nsCOMPtr
<nsIDOMBlob
> domBlob
;
840 if (!ResolveMysteryBlob(aFile
.mFile
, aData
.type
, aData
.size
)) {
843 domBlob
= aFile
.mFile
;
846 domBlob
= DOMFile::CreateFromFile(aData
.type
, aData
.size
, nativeFile
,
850 JS::Rooted
<JS::Value
> wrappedBlob(aCx
);
851 rv
= nsContentUtils::WrapNative(aCx
, domBlob
, &NS_GET_IID(nsIDOMBlob
),
854 NS_WARNING("Failed to wrap native!");
858 return wrappedBlob
.toObjectOrNull();
861 nsCOMPtr
<nsIDOMFile
> domFile
;
863 if (!ResolveMysteryFile(aFile
.mFile
, aData
.name
, aData
.type
, aData
.size
,
864 aData
.lastModifiedDate
)) {
867 domFile
= do_QueryInterface(aFile
.mFile
);
868 NS_ASSERTION(domFile
, "This should never fail!");
871 domFile
= DOMFile::CreateFromFile(aData
.name
, aData
.type
, aData
.size
,
872 nativeFile
, fileInfo
);
875 JS::Rooted
<JS::Value
> wrappedFile(aCx
);
876 rv
= nsContentUtils::WrapNative(aCx
, domFile
, &NS_GET_IID(nsIDOMFile
),
879 NS_WARNING("Failed to wrap native!");
883 return wrappedFile
.toObjectOrNull();
888 class CreateIndexDeserializationTraits
891 static bool CreateAndWrapMutableFile(JSContext
* aCx
,
892 IDBDatabase
* aDatabase
,
893 StructuredCloneFile
& aFile
,
894 const MutableFileData
& aData
,
895 JS::MutableHandle
<JSObject
*> aResult
)
897 // MutableFile can't be used in index creation, so just make a dummy object.
898 JS::Rooted
<JSObject
*> obj(aCx
,
899 JS_NewObject(aCx
, nullptr, JS::NullPtr(), JS::NullPtr()));
901 if (NS_WARN_IF(!obj
)) {
909 static JSObject
* CreateAndWrapBlobOrFile(JSContext
* aCx
,
910 IDBDatabase
* aDatabase
,
911 StructuredCloneFile
& aFile
,
912 const BlobOrFileData
& aData
)
914 MOZ_ASSERT(aData
.tag
== SCTAG_DOM_FILE
||
915 aData
.tag
== SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE
||
916 aData
.tag
== SCTAG_DOM_BLOB
);
918 // The following properties are available for use in index creation
922 // File.lastModifiedDate
924 JS::Rooted
<JSObject
*> obj(aCx
,
925 JS_NewObject(aCx
, nullptr, JS::NullPtr(), JS::NullPtr()));
927 NS_WARNING("Failed to create object!");
931 // Technically these props go on the proto, but this detail won't change
932 // the results of index creation.
934 JS::Rooted
<JSString
*> type(aCx
,
935 JS_NewUCStringCopyN(aCx
, aData
.type
.get(), aData
.type
.Length()));
937 !JS_DefineProperty(aCx
, obj
, "size", double(aData
.size
), 0) ||
938 !JS_DefineProperty(aCx
, obj
, "type", type
, 0)) {
942 if (aData
.tag
== SCTAG_DOM_BLOB
) {
946 JS::Rooted
<JSString
*> name(aCx
,
947 JS_NewUCStringCopyN(aCx
, aData
.name
.get(), aData
.name
.Length()));
948 JS::Rooted
<JSObject
*> date(aCx
,
949 JS_NewDateObjectMsec(aCx
, aData
.lastModifiedDate
));
950 if (!name
|| !date
||
951 !JS_DefineProperty(aCx
, obj
, "name", name
, 0) ||
952 !JS_DefineProperty(aCx
, obj
, "lastModifiedDate", date
, 0)) {
960 } // anonymous namespace
962 const JSClass
IDBObjectStore::sDummyPropJSClass
= {
964 JS_PropertyStub
, JS_DeletePropertyStub
,
965 JS_PropertyStub
, JS_StrictPropertyStub
,
966 JS_EnumerateStub
, JS_ResolveStub
,
971 already_AddRefed
<IDBObjectStore
>
972 IDBObjectStore::Create(IDBTransaction
* aTransaction
,
973 ObjectStoreInfo
* aStoreInfo
,
974 const nsACString
& aDatabaseId
,
977 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
979 nsRefPtr
<IDBObjectStore
> objectStore
= new IDBObjectStore();
981 objectStore
->mTransaction
= aTransaction
;
982 objectStore
->mName
= aStoreInfo
->name
;
983 objectStore
->mId
= aStoreInfo
->id
;
984 objectStore
->mKeyPath
= aStoreInfo
->keyPath
;
985 objectStore
->mAutoIncrement
= aStoreInfo
->autoIncrement
;
986 objectStore
->mDatabaseId
= aDatabaseId
;
987 objectStore
->mInfo
= aStoreInfo
;
989 if (!IndexedDatabaseManager::IsMainProcess()) {
990 IndexedDBTransactionChild
* transactionActor
= aTransaction
->GetActorChild();
991 NS_ASSERTION(transactionActor
, "Must have an actor here!");
993 ObjectStoreConstructorParams params
;
996 CreateObjectStoreParams createParams
;
997 createParams
.info() = *aStoreInfo
;
998 params
= createParams
;
1001 GetObjectStoreParams getParams
;
1002 getParams
.name() = aStoreInfo
->name
;
1006 IndexedDBObjectStoreChild
* actor
=
1007 new IndexedDBObjectStoreChild(objectStore
);
1009 transactionActor
->SendPIndexedDBObjectStoreConstructor(actor
, params
);
1012 return objectStore
.forget();
1017 IDBObjectStore::AppendIndexUpdateInfo(
1019 const KeyPath
& aKeyPath
,
1023 JS::Handle
<JS::Value
> aVal
,
1024 nsTArray
<IndexUpdateInfo
>& aUpdateInfoArray
)
1030 rv
= aKeyPath
.ExtractKey(aCx
, aVal
, key
);
1032 // If an index's keypath doesn't match an object, we ignore that object.
1033 if (rv
== NS_ERROR_DOM_INDEXEDDB_DATA_ERR
|| key
.IsUnset()) {
1037 if (NS_FAILED(rv
)) {
1041 IndexUpdateInfo
* updateInfo
= aUpdateInfoArray
.AppendElement();
1042 updateInfo
->indexId
= aIndexID
;
1043 updateInfo
->indexUnique
= aUnique
;
1044 updateInfo
->value
= key
;
1049 JS::Rooted
<JS::Value
> val(aCx
);
1050 if (NS_FAILED(aKeyPath
.ExtractKeyAsJSVal(aCx
, aVal
, val
.address()))) {
1054 if (JS_IsArrayObject(aCx
, val
)) {
1055 JS::Rooted
<JSObject
*> array(aCx
, &val
.toObject());
1056 uint32_t arrayLength
;
1057 if (!JS_GetArrayLength(aCx
, array
, &arrayLength
)) {
1058 IDB_REPORT_INTERNAL_ERR();
1059 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
1062 for (uint32_t arrayIndex
= 0; arrayIndex
< arrayLength
; arrayIndex
++) {
1063 JS::Rooted
<JS::Value
> arrayItem(aCx
);
1064 if (!JS_GetElement(aCx
, array
, arrayIndex
, &arrayItem
)) {
1065 IDB_REPORT_INTERNAL_ERR();
1066 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
1070 if (NS_FAILED(value
.SetFromJSVal(aCx
, arrayItem
)) ||
1072 // Not a value we can do anything with, ignore it.
1076 IndexUpdateInfo
* updateInfo
= aUpdateInfoArray
.AppendElement();
1077 updateInfo
->indexId
= aIndexID
;
1078 updateInfo
->indexUnique
= aUnique
;
1079 updateInfo
->value
= value
;
1084 if (NS_FAILED(value
.SetFromJSVal(aCx
, val
)) ||
1086 // Not a value we can do anything with, ignore it.
1090 IndexUpdateInfo
* updateInfo
= aUpdateInfoArray
.AppendElement();
1091 updateInfo
->indexId
= aIndexID
;
1092 updateInfo
->indexUnique
= aUnique
;
1093 updateInfo
->value
= value
;
1101 IDBObjectStore::UpdateIndexes(IDBTransaction
* aTransaction
,
1102 int64_t aObjectStoreId
,
1103 const Key
& aObjectStoreKey
,
1105 int64_t aObjectDataId
,
1106 const nsTArray
<IndexUpdateInfo
>& aUpdateInfoArray
)
1108 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
1109 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1111 PROFILER_LABEL("IDBObjectStore", "UpdateIndexes",
1112 js::ProfileEntry::Category::STORAGE
);
1116 NS_ASSERTION(aObjectDataId
!= INT64_MIN
, "Bad objectData id!");
1118 NS_NAMED_LITERAL_CSTRING(objectDataId
, "object_data_id");
1121 nsCOMPtr
<mozIStorageStatement
> deleteStmt
=
1122 aTransaction
->GetCachedStatement(
1123 "DELETE FROM unique_index_data "
1124 "WHERE object_data_id = :object_data_id; "
1125 "DELETE FROM index_data "
1126 "WHERE object_data_id = :object_data_id");
1127 NS_ENSURE_TRUE(deleteStmt
, NS_ERROR_FAILURE
);
1129 mozStorageStatementScoper
scoper(deleteStmt
);
1131 rv
= deleteStmt
->BindInt64ByName(objectDataId
, aObjectDataId
);
1132 NS_ENSURE_SUCCESS(rv
, rv
);
1134 rv
= deleteStmt
->Execute();
1135 NS_ENSURE_SUCCESS(rv
, rv
);
1138 // Avoid lots of hash lookups for objectStores with lots of indexes by lazily
1139 // holding the necessary statements on the stack outside the loop.
1140 nsCOMPtr
<mozIStorageStatement
> insertUniqueStmt
;
1141 nsCOMPtr
<mozIStorageStatement
> insertStmt
;
1143 uint32_t infoCount
= aUpdateInfoArray
.Length();
1144 for (uint32_t i
= 0; i
< infoCount
; i
++) {
1145 const IndexUpdateInfo
& updateInfo
= aUpdateInfoArray
[i
];
1147 nsCOMPtr
<mozIStorageStatement
>& stmt
=
1148 updateInfo
.indexUnique
? insertUniqueStmt
: insertStmt
;
1151 stmt
= updateInfo
.indexUnique
?
1152 aTransaction
->GetCachedStatement(
1153 "INSERT INTO unique_index_data "
1154 "(index_id, object_data_id, object_data_key, value) "
1155 "VALUES (:index_id, :object_data_id, :object_data_key, :value)") :
1156 aTransaction
->GetCachedStatement(
1157 "INSERT OR IGNORE INTO index_data ("
1158 "index_id, object_data_id, object_data_key, value) "
1159 "VALUES (:index_id, :object_data_id, :object_data_key, :value)");
1161 NS_ENSURE_TRUE(stmt
, NS_ERROR_FAILURE
);
1163 mozStorageStatementScoper
scoper(stmt
);
1165 rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
1166 updateInfo
.indexId
);
1167 NS_ENSURE_SUCCESS(rv
, rv
);
1169 rv
= stmt
->BindInt64ByName(objectDataId
, aObjectDataId
);
1170 NS_ENSURE_SUCCESS(rv
, rv
);
1172 rv
= aObjectStoreKey
.BindToStatement(stmt
,
1173 NS_LITERAL_CSTRING("object_data_key"));
1174 NS_ENSURE_SUCCESS(rv
, rv
);
1176 rv
= updateInfo
.value
.BindToStatement(stmt
, NS_LITERAL_CSTRING("value"));
1177 NS_ENSURE_SUCCESS(rv
, rv
);
1179 rv
= stmt
->Execute();
1180 if (rv
== NS_ERROR_STORAGE_CONSTRAINT
&& updateInfo
.indexUnique
) {
1181 // If we're inserting multiple entries for the same unique index, then
1182 // we might have failed to insert due to colliding with another entry for
1183 // the same index in which case we should ignore it.
1185 for (int32_t j
= (int32_t)i
- 1;
1186 j
>= 0 && aUpdateInfoArray
[j
].indexId
== updateInfo
.indexId
;
1188 if (updateInfo
.value
== aUpdateInfoArray
[j
].value
) {
1189 // We found a key with the same value for the same index. So we
1190 // must have had a collision with a value we just inserted.
1197 if (NS_FAILED(rv
)) {
1207 IDBObjectStore::GetStructuredCloneReadInfoFromStatement(
1208 mozIStorageStatement
* aStatement
,
1209 uint32_t aDataIndex
,
1210 uint32_t aFileIdsIndex
,
1211 IDBDatabase
* aDatabase
,
1212 StructuredCloneReadInfo
& aInfo
)
1214 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
1215 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1217 PROFILER_LABEL("IDBObjectStore", "GetStructuredCloneReadInfoFromStatement",
1218 js::ProfileEntry::Category::STORAGE
);
1223 NS_ASSERTION(NS_SUCCEEDED(aStatement
->GetTypeOfIndex(aDataIndex
, &type
)) &&
1224 type
== mozIStorageStatement::VALUE_TYPE_BLOB
,
1229 const uint8_t* blobData
;
1230 uint32_t blobDataLength
;
1231 nsresult rv
= aStatement
->GetSharedBlob(aDataIndex
, &blobDataLength
,
1233 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1235 const char* compressed
= reinterpret_cast<const char*>(blobData
);
1236 size_t compressedLength
= size_t(blobDataLength
);
1238 static const fallible_t fallible
= fallible_t();
1240 size_t uncompressedLength
;
1241 if (!snappy::GetUncompressedLength(compressed
, compressedLength
,
1242 &uncompressedLength
)) {
1243 IDB_WARNING("Snappy can't determine uncompressed length!");
1244 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
1247 nsAutoArrayPtr
<char> uncompressed(new (fallible
) char[uncompressedLength
]);
1248 NS_ENSURE_TRUE(uncompressed
, NS_ERROR_OUT_OF_MEMORY
);
1250 if (!snappy::RawUncompress(compressed
, compressedLength
,
1251 uncompressed
.get())) {
1252 IDB_WARNING("Snappy can't determine uncompressed length!");
1253 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
1256 JSAutoStructuredCloneBuffer
& buffer
= aInfo
.mCloneBuffer
;
1257 if (!buffer
.copy(reinterpret_cast<const uint64_t *>(uncompressed
.get()),
1258 uncompressedLength
)) {
1259 IDB_REPORT_INTERNAL_ERR();
1260 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
1264 rv
= aStatement
->GetIsNull(aFileIdsIndex
, &isNull
);
1265 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1269 rv
= aStatement
->GetString(aFileIdsIndex
, ids
);
1270 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1272 nsAutoTArray
<int64_t, 10> array
;
1273 rv
= ConvertFileIdsToArray(ids
, array
);
1274 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1276 FileManager
* fileManager
= aDatabase
->Manager();
1278 for (uint32_t i
= 0; i
< array
.Length(); i
++) {
1279 const int64_t& id
= array
[i
];
1281 nsRefPtr
<FileInfo
> fileInfo
= fileManager
->GetFileInfo(id
);
1282 NS_ASSERTION(fileInfo
, "Null file info!");
1284 StructuredCloneFile
* file
= aInfo
.mFiles
.AppendElement();
1285 file
->mFileInfo
.swap(fileInfo
);
1289 aInfo
.mDatabase
= aDatabase
;
1296 IDBObjectStore::ClearCloneWriteInfo(StructuredCloneWriteInfo
& aWriteInfo
)
1298 // This is kind of tricky, we only want to release stuff on the main thread,
1299 // but we can end up being called on other threads if we have already been
1300 // cleared on the main thread.
1301 if (!aWriteInfo
.mCloneBuffer
.data() && !aWriteInfo
.mFiles
.Length()) {
1305 // If there's something to clear, we should be on the main thread.
1306 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1308 ClearStructuredCloneBuffer(aWriteInfo
.mCloneBuffer
);
1309 aWriteInfo
.mFiles
.Clear();
1314 IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo
& aReadInfo
)
1316 // This is kind of tricky, we only want to release stuff on the main thread,
1317 // but we can end up being called on other threads if we have already been
1318 // cleared on the main thread.
1319 if (!aReadInfo
.mCloneBuffer
.data() && !aReadInfo
.mFiles
.Length()) {
1323 // If there's something to clear, we should be on the main thread.
1324 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1326 ClearStructuredCloneBuffer(aReadInfo
.mCloneBuffer
);
1327 aReadInfo
.mFiles
.Clear();
1332 IDBObjectStore::ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer
& aBuffer
)
1334 if (aBuffer
.data()) {
1341 IDBObjectStore::DeserializeValue(JSContext
* aCx
,
1342 StructuredCloneReadInfo
& aCloneReadInfo
,
1343 JS::MutableHandle
<JS::Value
> aValue
)
1345 NS_ASSERTION(NS_IsMainThread(),
1346 "Should only be deserializing on the main thread!");
1347 NS_ASSERTION(aCx
, "A JSContext is required!");
1349 JSAutoStructuredCloneBuffer
& buffer
= aCloneReadInfo
.mCloneBuffer
;
1351 if (!buffer
.data()) {
1352 aValue
.setUndefined();
1356 JSAutoRequest
ar(aCx
);
1358 JSStructuredCloneCallbacks callbacks
= {
1359 IDBObjectStore::StructuredCloneReadCallback
<MainThreadDeserializationTraits
>,
1367 return buffer
.read(aCx
, aValue
, &callbacks
, &aCloneReadInfo
);
1372 IDBObjectStore::SerializeValue(JSContext
* aCx
,
1373 StructuredCloneWriteInfo
& aCloneWriteInfo
,
1374 JS::Handle
<JS::Value
> aValue
)
1376 NS_ASSERTION(NS_IsMainThread(),
1377 "Should only be serializing on the main thread!");
1378 NS_ASSERTION(aCx
, "A JSContext is required!");
1380 JSAutoRequest
ar(aCx
);
1382 JSStructuredCloneCallbacks callbacks
= {
1384 StructuredCloneWriteCallback
,
1391 JSAutoStructuredCloneBuffer
& buffer
= aCloneWriteInfo
.mCloneBuffer
;
1393 return buffer
.write(aCx
, aValue
, &callbacks
, &aCloneWriteInfo
);
1397 StructuredCloneReadString(JSStructuredCloneReader
* aReader
,
1401 if (!JS_ReadBytes(aReader
, &length
, sizeof(uint32_t))) {
1402 NS_WARNING("Failed to read length!");
1405 length
= NativeEndian::swapFromLittleEndian(length
);
1407 if (!aString
.SetLength(length
, fallible_t())) {
1408 NS_WARNING("Out of memory?");
1411 char* buffer
= aString
.BeginWriting();
1413 if (!JS_ReadBytes(aReader
, buffer
, length
)) {
1414 NS_WARNING("Failed to read type!");
1423 IDBObjectStore::ReadMutableFile(JSStructuredCloneReader
* aReader
,
1424 MutableFileData
* aRetval
)
1426 static_assert(SCTAG_DOM_MUTABLEFILE
== 0xFFFF8004,
1428 MOZ_ASSERT(aReader
&& aRetval
);
1431 if (!StructuredCloneReadString(aReader
, type
)) {
1434 CopyUTF8toUTF16(type
, aRetval
->type
);
1437 if (!StructuredCloneReadString(aReader
, name
)) {
1440 CopyUTF8toUTF16(name
, aRetval
->name
);
1447 IDBObjectStore::ReadBlobOrFile(JSStructuredCloneReader
* aReader
,
1449 BlobOrFileData
* aRetval
)
1451 static_assert(SCTAG_DOM_BLOB
== 0xFFFF8001 &&
1452 SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE
== 0xFFFF8002 &&
1453 SCTAG_DOM_FILE
== 0xFFFF8005,
1455 MOZ_ASSERT(aReader
&& aRetval
);
1456 MOZ_ASSERT(aTag
== SCTAG_DOM_FILE
||
1457 aTag
== SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE
||
1458 aTag
== SCTAG_DOM_BLOB
);
1460 aRetval
->tag
= aTag
;
1462 // If it's not a MutableFile, it's a Blob or a File.
1464 if (!JS_ReadBytes(aReader
, &size
, sizeof(uint64_t))) {
1465 NS_WARNING("Failed to read size!");
1468 aRetval
->size
= NativeEndian::swapFromLittleEndian(size
);
1471 if (!StructuredCloneReadString(aReader
, type
)) {
1474 CopyUTF8toUTF16(type
, aRetval
->type
);
1477 if (aTag
== SCTAG_DOM_BLOB
) {
1481 NS_ASSERTION(aTag
== SCTAG_DOM_FILE
||
1482 aTag
== SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE
, "Huh?!");
1484 uint64_t lastModifiedDate
;
1485 if (aTag
== SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE
) {
1486 lastModifiedDate
= UINT64_MAX
;
1489 if(!JS_ReadBytes(aReader
, &lastModifiedDate
, sizeof(lastModifiedDate
))) {
1490 NS_WARNING("Failed to read lastModifiedDate");
1493 lastModifiedDate
= NativeEndian::swapFromLittleEndian(lastModifiedDate
);
1495 aRetval
->lastModifiedDate
= lastModifiedDate
;
1498 if (!StructuredCloneReadString(aReader
, name
)) {
1501 CopyUTF8toUTF16(name
, aRetval
->name
);
1507 template <class Traits
>
1509 IDBObjectStore::StructuredCloneReadCallback(JSContext
* aCx
,
1510 JSStructuredCloneReader
* aReader
,
1515 // We need to statically assert that our tag values are what we expect
1516 // so that if people accidentally change them they notice.
1517 static_assert(SCTAG_DOM_BLOB
== 0xFFFF8001 &&
1518 SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE
== 0xFFFF8002 &&
1519 SCTAG_DOM_MUTABLEFILE
== 0xFFFF8004 &&
1520 SCTAG_DOM_FILE
== 0xFFFF8005,
1521 "You changed our structured clone tag values and just ate "
1522 "everyone's IndexedDB data. I hope you are happy.");
1524 if (aTag
== SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE
||
1525 aTag
== SCTAG_DOM_MUTABLEFILE
||
1526 aTag
== SCTAG_DOM_BLOB
||
1527 aTag
== SCTAG_DOM_FILE
) {
1528 StructuredCloneReadInfo
* cloneReadInfo
=
1529 reinterpret_cast<StructuredCloneReadInfo
*>(aClosure
);
1531 if (aData
>= cloneReadInfo
->mFiles
.Length()) {
1532 NS_ERROR("Bad blob index!");
1536 StructuredCloneFile
& file
= cloneReadInfo
->mFiles
[aData
];
1537 IDBDatabase
* database
= cloneReadInfo
->mDatabase
;
1539 if (aTag
== SCTAG_DOM_MUTABLEFILE
) {
1540 MutableFileData data
;
1541 if (!ReadMutableFile(aReader
, &data
)) {
1545 JS::Rooted
<JSObject
*> result(aCx
);
1546 if (NS_WARN_IF(!Traits::CreateAndWrapMutableFile(aCx
,
1557 BlobOrFileData data
;
1558 if (!ReadBlobOrFile(aReader
, aTag
, &data
)) {
1562 return Traits::CreateAndWrapBlobOrFile(aCx
, database
, file
, data
);
1565 const JSStructuredCloneCallbacks
* runtimeCallbacks
=
1566 js::GetContextStructuredCloneCallbacks(aCx
);
1568 if (runtimeCallbacks
) {
1569 return runtimeCallbacks
->read(aCx
, aReader
, aTag
, aData
, nullptr);
1577 IDBObjectStore::StructuredCloneWriteCallback(JSContext
* aCx
,
1578 JSStructuredCloneWriter
* aWriter
,
1579 JS::Handle
<JSObject
*> aObj
,
1582 StructuredCloneWriteInfo
* cloneWriteInfo
=
1583 reinterpret_cast<StructuredCloneWriteInfo
*>(aClosure
);
1585 if (JS_GetClass(aObj
) == &sDummyPropJSClass
) {
1586 NS_ASSERTION(cloneWriteInfo
->mOffsetToKeyProp
== 0,
1587 "We should not have been here before!");
1588 cloneWriteInfo
->mOffsetToKeyProp
= js_GetSCOffset(aWriter
);
1592 return JS_WriteBytes(aWriter
, &value
, sizeof(value
));
1595 IDBTransaction
* transaction
= cloneWriteInfo
->mTransaction
;
1596 FileManager
* fileManager
= transaction
->Database()->Manager();
1598 IDBMutableFile
* mutableFile
= nullptr;
1599 if (NS_SUCCEEDED(UNWRAP_OBJECT(IDBMutableFile
, aObj
, mutableFile
))) {
1600 nsRefPtr
<FileInfo
> fileInfo
= mutableFile
->GetFileInfo();
1601 MOZ_ASSERT(fileInfo
);
1603 // Throw when trying to store mutable files across databases.
1604 if (fileInfo
->Manager() != fileManager
) {
1608 NS_ConvertUTF16toUTF8
convType(mutableFile
->Type());
1609 uint32_t convTypeLength
=
1610 NativeEndian::swapToLittleEndian(convType
.Length());
1612 NS_ConvertUTF16toUTF8
convName(mutableFile
->Name());
1613 uint32_t convNameLength
=
1614 NativeEndian::swapToLittleEndian(convName
.Length());
1616 if (!JS_WriteUint32Pair(aWriter
, SCTAG_DOM_MUTABLEFILE
,
1617 cloneWriteInfo
->mFiles
.Length()) ||
1618 !JS_WriteBytes(aWriter
, &convTypeLength
, sizeof(uint32_t)) ||
1619 !JS_WriteBytes(aWriter
, convType
.get(), convType
.Length()) ||
1620 !JS_WriteBytes(aWriter
, &convNameLength
, sizeof(uint32_t)) ||
1621 !JS_WriteBytes(aWriter
, convName
.get(), convName
.Length())) {
1625 StructuredCloneFile
* file
= cloneWriteInfo
->mFiles
.AppendElement();
1626 file
->mFileInfo
= fileInfo
.forget();
1631 nsCOMPtr
<nsIXPConnectWrappedNative
> wrappedNative
;
1632 nsContentUtils::XPConnect()->
1633 GetWrappedNativeOfJSObject(aCx
, aObj
, getter_AddRefs(wrappedNative
));
1635 if (wrappedNative
) {
1636 nsISupports
* supports
= wrappedNative
->Native();
1638 nsCOMPtr
<nsIDOMBlob
> blob
= do_QueryInterface(supports
);
1640 nsCOMPtr
<nsIInputStream
> inputStream
;
1642 // Check if it is a blob created from this db or the blob was already
1643 // stored in this db
1644 nsRefPtr
<FileInfo
> fileInfo
= transaction
->GetFileInfo(blob
);
1645 if (!fileInfo
&& fileManager
) {
1646 fileInfo
= blob
->GetFileInfo(fileManager
);
1649 fileInfo
= fileManager
->GetNewFileInfo();
1651 NS_WARNING("Failed to get new file info!");
1655 if (NS_FAILED(blob
->GetInternalStream(getter_AddRefs(inputStream
)))) {
1656 NS_WARNING("Failed to get internal steam!");
1660 transaction
->AddFileInfo(blob
, fileInfo
);
1665 if (NS_FAILED(blob
->GetSize(&size
))) {
1666 NS_WARNING("Failed to get size!");
1669 size
= NativeEndian::swapToLittleEndian(size
);
1672 if (NS_FAILED(blob
->GetType(type
))) {
1673 NS_WARNING("Failed to get type!");
1676 NS_ConvertUTF16toUTF8
convType(type
);
1677 uint32_t convTypeLength
=
1678 NativeEndian::swapToLittleEndian(convType
.Length());
1680 nsCOMPtr
<nsIDOMFile
> file
= do_QueryInterface(blob
);
1682 if (!JS_WriteUint32Pair(aWriter
, file
? SCTAG_DOM_FILE
: SCTAG_DOM_BLOB
,
1683 cloneWriteInfo
->mFiles
.Length()) ||
1684 !JS_WriteBytes(aWriter
, &size
, sizeof(size
)) ||
1685 !JS_WriteBytes(aWriter
, &convTypeLength
, sizeof(convTypeLength
)) ||
1686 !JS_WriteBytes(aWriter
, convType
.get(), convType
.Length())) {
1691 uint64_t lastModifiedDate
= 0;
1692 if (NS_FAILED(file
->GetMozLastModifiedDate(&lastModifiedDate
))) {
1693 NS_WARNING("Failed to get last modified date!");
1697 lastModifiedDate
= NativeEndian::swapToLittleEndian(lastModifiedDate
);
1700 if (NS_FAILED(file
->GetName(name
))) {
1701 NS_WARNING("Failed to get name!");
1704 NS_ConvertUTF16toUTF8
convName(name
);
1705 uint32_t convNameLength
=
1706 NativeEndian::swapToLittleEndian(convName
.Length());
1708 if (!JS_WriteBytes(aWriter
, &lastModifiedDate
, sizeof(lastModifiedDate
)) ||
1709 !JS_WriteBytes(aWriter
, &convNameLength
, sizeof(convNameLength
)) ||
1710 !JS_WriteBytes(aWriter
, convName
.get(), convName
.Length())) {
1715 StructuredCloneFile
* cloneFile
= cloneWriteInfo
->mFiles
.AppendElement();
1716 cloneFile
->mFile
= blob
.forget();
1717 cloneFile
->mFileInfo
= fileInfo
.forget();
1718 cloneFile
->mInputStream
= inputStream
.forget();
1724 // try using the runtime callbacks
1725 const JSStructuredCloneCallbacks
* runtimeCallbacks
=
1726 js::GetContextStructuredCloneCallbacks(aCx
);
1727 if (runtimeCallbacks
) {
1728 return runtimeCallbacks
->write(aCx
, aWriter
, aObj
, nullptr);
1736 IDBObjectStore::ConvertFileIdsToArray(const nsAString
& aFileIds
,
1737 nsTArray
<int64_t>& aResult
)
1739 nsCharSeparatedTokenizerTemplate
<IgnoreNothing
> tokenizer(aFileIds
, ' ');
1741 while (tokenizer
.hasMoreTokens()) {
1742 nsString
token(tokenizer
.nextToken());
1744 NS_ASSERTION(!token
.IsEmpty(), "Should be a valid id!");
1747 int32_t id
= token
.ToInteger(&rv
);
1748 NS_ENSURE_SUCCESS(rv
, rv
);
1750 int64_t* element
= aResult
.AppendElement();
1759 IDBObjectStore::ConvertActorsToBlobs(
1760 const InfallibleTArray
<PBlobChild
*>& aActors
,
1761 nsTArray
<StructuredCloneFile
>& aFiles
)
1763 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1764 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1765 NS_ASSERTION(aFiles
.IsEmpty(), "Should be empty!");
1767 if (!aActors
.IsEmpty()) {
1768 NS_ASSERTION(ContentChild::GetSingleton(), "This should never be null!");
1770 uint32_t length
= aActors
.Length();
1771 aFiles
.SetCapacity(length
);
1773 for (uint32_t index
= 0; index
< length
; index
++) {
1774 BlobChild
* actor
= static_cast<BlobChild
*>(aActors
[index
]);
1776 StructuredCloneFile
* file
= aFiles
.AppendElement();
1777 file
->mFile
= actor
->GetBlob();
1784 IDBObjectStore::ConvertBlobsToActors(
1785 nsIContentParent
* aContentParent
,
1786 FileManager
* aFileManager
,
1787 const nsTArray
<StructuredCloneFile
>& aFiles
,
1788 InfallibleTArray
<PBlobParent
*>& aActors
)
1790 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1791 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1792 NS_ASSERTION(aContentParent
, "Null contentParent!");
1793 NS_ASSERTION(aFileManager
, "Null file manager!");
1795 if (!aFiles
.IsEmpty()) {
1796 nsCOMPtr
<nsIFile
> directory
= aFileManager
->GetDirectory();
1798 IDB_WARNING("Failed to get directory!");
1799 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
1802 uint32_t fileCount
= aFiles
.Length();
1803 aActors
.SetCapacity(fileCount
);
1805 for (uint32_t index
= 0; index
< fileCount
; index
++) {
1806 const StructuredCloneFile
& file
= aFiles
[index
];
1807 NS_ASSERTION(file
.mFileInfo
, "This should never be null!");
1809 nsCOMPtr
<nsIFile
> nativeFile
=
1810 aFileManager
->GetFileForId(directory
, file
.mFileInfo
->Id());
1812 IDB_WARNING("Failed to get file!");
1813 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
1816 nsCOMPtr
<nsIDOMBlob
> blob
= DOMFile::CreateFromFile(nativeFile
,
1820 aContentParent
->GetOrCreateActorForBlob(blob
);
1822 // This can only fail if the child has crashed.
1823 IDB_REPORT_INTERNAL_ERR();
1824 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
1827 aActors
.AppendElement(actor
);
1834 IDBObjectStore::IDBObjectStore()
1837 mCachedKeyPath(JSVAL_VOID
),
1839 mAutoIncrement(false),
1840 mActorChild(nullptr),
1841 mActorParent(nullptr)
1843 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1848 IDBObjectStore::~IDBObjectStore()
1850 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1851 NS_ASSERTION(!mActorParent
, "Actor parent owns us, how can we be dying?!");
1853 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1854 mActorChild
->Send__delete__(mActorChild
);
1855 NS_ASSERTION(!mActorChild
, "Should have cleared in Send__delete__!");
1859 mCachedKeyPath
= JSVAL_VOID
;
1860 mozilla::DropJSObjects(this);
1865 IDBObjectStore::GetAddInfo(JSContext
* aCx
,
1866 JS::Handle
<JS::Value
> aValue
,
1867 JS::Handle
<JS::Value
> aKeyVal
,
1868 StructuredCloneWriteInfo
& aCloneWriteInfo
,
1870 nsTArray
<IndexUpdateInfo
>& aUpdateInfoArray
)
1874 // Return DATA_ERR if a key was passed in and this objectStore uses inline
1876 if (!aKeyVal
.isUndefined() && HasValidKeyPath()) {
1877 return NS_ERROR_DOM_INDEXEDDB_DATA_ERR
;
1880 JSAutoRequest
ar(aCx
);
1882 if (!HasValidKeyPath()) {
1883 // Out-of-line keys must be passed in.
1884 rv
= aKey
.SetFromJSVal(aCx
, aKeyVal
);
1885 if (NS_FAILED(rv
)) {
1889 else if (!mAutoIncrement
) {
1890 rv
= GetKeyPath().ExtractKey(aCx
, aValue
, aKey
);
1891 if (NS_FAILED(rv
)) {
1896 // Return DATA_ERR if no key was specified this isn't an autoIncrement
1898 if (aKey
.IsUnset() && !mAutoIncrement
) {
1899 return NS_ERROR_DOM_INDEXEDDB_DATA_ERR
;
1902 // Figure out indexes and the index values to update here.
1903 uint32_t count
= mInfo
->indexes
.Length();
1904 aUpdateInfoArray
.SetCapacity(count
); // Pretty good estimate
1905 for (uint32_t indexesIndex
= 0; indexesIndex
< count
; indexesIndex
++) {
1906 const IndexInfo
& indexInfo
= mInfo
->indexes
[indexesIndex
];
1908 rv
= AppendIndexUpdateInfo(indexInfo
.id
, indexInfo
.keyPath
,
1909 indexInfo
.unique
, indexInfo
.multiEntry
, aCx
,
1910 aValue
, aUpdateInfoArray
);
1911 NS_ENSURE_SUCCESS(rv
, rv
);
1914 GetAddInfoClosure data
= {this, aCloneWriteInfo
, aValue
};
1916 if (mAutoIncrement
&& HasValidKeyPath()) {
1917 NS_ASSERTION(aKey
.IsUnset(), "Shouldn't have gotten the key yet!");
1919 rv
= GetKeyPath().ExtractOrCreateKey(aCx
, aValue
, aKey
,
1920 &GetAddInfoCallback
, &data
);
1923 rv
= GetAddInfoCallback(aCx
, &data
);
1929 already_AddRefed
<IDBRequest
>
1930 IDBObjectStore::AddOrPut(JSContext
* aCx
, JS::Handle
<JS::Value
> aValue
,
1931 JS::Handle
<JS::Value
> aKey
,
1932 bool aOverwrite
, ErrorResult
& aRv
)
1934 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1936 if (!mTransaction
->IsOpen()) {
1937 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
1941 if (!IsWriteAllowed()) {
1942 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR
);
1946 StructuredCloneWriteInfo cloneWriteInfo
;
1948 nsTArray
<IndexUpdateInfo
> updateInfo
;
1950 JS::Rooted
<JS::Value
> value(aCx
, aValue
);
1951 aRv
= GetAddInfo(aCx
, value
, aKey
, cloneWriteInfo
, key
, updateInfo
);
1956 nsRefPtr
<IDBRequest
> request
= GenerateRequest(this);
1958 IDB_WARNING("Failed to generate request!");
1959 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1963 nsRefPtr
<AddHelper
> helper
=
1964 new AddHelper(mTransaction
, request
, this, Move(cloneWriteInfo
), key
,
1965 aOverwrite
, updateInfo
);
1967 nsresult rv
= helper
->DispatchToTransactionPool();
1968 if (NS_FAILED(rv
)) {
1969 IDB_WARNING("Failed to dispatch!");
1970 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
1974 #ifdef IDB_PROFILER_USE_MARKS
1976 IDB_PROFILER_MARK("IndexedDB Request %llu: "
1977 "database(%s).transaction(%s).objectStore(%s).%s(%s)",
1978 "IDBRequest[%llu] MT IDBObjectStore.put()",
1979 request
->GetSerialNumber(),
1980 IDB_PROFILER_STRING(Transaction()->Database()),
1981 IDB_PROFILER_STRING(Transaction()),
1982 IDB_PROFILER_STRING(this),
1983 key
.IsUnset() ? "" : IDB_PROFILER_STRING(key
));
1986 IDB_PROFILER_MARK("IndexedDB Request %llu: "
1987 "database(%s).transaction(%s).objectStore(%s).add(%s)",
1988 "IDBRequest[%llu] MT IDBObjectStore.add()",
1989 request
->GetSerialNumber(),
1990 IDB_PROFILER_STRING(Transaction()->Database()),
1991 IDB_PROFILER_STRING(Transaction()),
1992 IDB_PROFILER_STRING(this),
1993 key
.IsUnset() ? "" : IDB_PROFILER_STRING(key
));
1997 return request
.forget();
2001 IDBObjectStore::AddOrPutInternal(
2002 const SerializedStructuredCloneWriteInfo
& aCloneWriteInfo
,
2004 const InfallibleTArray
<IndexUpdateInfo
>& aUpdateInfoArray
,
2005 const nsTArray
<nsCOMPtr
<nsIDOMBlob
> >& aBlobs
,
2007 IDBRequest
** _retval
)
2009 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2010 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2012 if (!mTransaction
->IsOpen()) {
2013 return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
;
2016 if (!IsWriteAllowed()) {
2017 return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR
;
2020 nsRefPtr
<IDBRequest
> request
= GenerateRequest(this);
2021 IDB_ENSURE_TRUE(request
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2023 StructuredCloneWriteInfo cloneWriteInfo
;
2024 if (!cloneWriteInfo
.SetFromSerialized(aCloneWriteInfo
)) {
2025 IDB_WARNING("Failed to copy structured clone buffer!");
2026 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
2029 if (!aBlobs
.IsEmpty()) {
2030 FileManager
* fileManager
= Transaction()->Database()->Manager();
2031 NS_ASSERTION(fileManager
, "Null file manager?!");
2033 uint32_t length
= aBlobs
.Length();
2034 cloneWriteInfo
.mFiles
.SetCapacity(length
);
2036 for (uint32_t index
= 0; index
< length
; index
++) {
2037 const nsCOMPtr
<nsIDOMBlob
>& blob
= aBlobs
[index
];
2039 nsCOMPtr
<nsIInputStream
> inputStream
;
2041 nsRefPtr
<FileInfo
> fileInfo
= Transaction()->GetFileInfo(blob
);
2043 fileInfo
= blob
->GetFileInfo(fileManager
);
2046 fileInfo
= fileManager
->GetNewFileInfo();
2048 IDB_WARNING("Failed to get new file info!");
2049 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
2052 if (NS_FAILED(blob
->GetInternalStream(getter_AddRefs(inputStream
)))) {
2053 IDB_WARNING("Failed to get internal steam!");
2054 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
2057 // XXXbent This is where we should send a message back to the child to
2058 // update the file id.
2060 Transaction()->AddFileInfo(blob
, fileInfo
);
2064 StructuredCloneFile
* file
= cloneWriteInfo
.mFiles
.AppendElement();
2066 file
->mFileInfo
.swap(fileInfo
);
2067 file
->mInputStream
.swap(inputStream
);
2073 nsTArray
<IndexUpdateInfo
> updateInfo(aUpdateInfoArray
);
2075 nsRefPtr
<AddHelper
> helper
=
2076 new AddHelper(mTransaction
, request
, this, Move(cloneWriteInfo
), key
,
2077 aOverwrite
, updateInfo
);
2079 nsresult rv
= helper
->DispatchToTransactionPool();
2080 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2082 #ifdef IDB_PROFILER_USE_MARKS
2084 IDB_PROFILER_MARK("IndexedDB Request %llu: "
2085 "database(%s).transaction(%s).objectStore(%s).%s(%s)",
2086 "IDBRequest[%llu] MT IDBObjectStore.put()",
2087 request
->GetSerialNumber(),
2088 IDB_PROFILER_STRING(Transaction()->Database()),
2089 IDB_PROFILER_STRING(Transaction()),
2090 IDB_PROFILER_STRING(this),
2091 key
.IsUnset() ? "" : IDB_PROFILER_STRING(key
));
2094 IDB_PROFILER_MARK("IndexedDB Request %llu: "
2095 "database(%s).transaction(%s).objectStore(%s).add(%s)",
2096 "IDBRequest[%llu] MT IDBObjectStore.add()",
2097 request
->GetSerialNumber(),
2098 IDB_PROFILER_STRING(Transaction()->Database()),
2099 IDB_PROFILER_STRING(Transaction()),
2100 IDB_PROFILER_STRING(this),
2101 key
.IsUnset() ? "" : IDB_PROFILER_STRING(key
));
2105 request
.forget(_retval
);
2109 already_AddRefed
<IDBRequest
>
2110 IDBObjectStore::GetInternal(IDBKeyRange
* aKeyRange
, ErrorResult
& aRv
)
2112 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2113 NS_ASSERTION(aKeyRange
, "Null pointer!");
2115 if (!mTransaction
->IsOpen()) {
2116 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2120 nsRefPtr
<IDBRequest
> request
= GenerateRequest(this);
2122 IDB_WARNING("Failed to generate request!");
2123 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2127 nsRefPtr
<GetHelper
> helper
=
2128 new GetHelper(mTransaction
, request
, this, aKeyRange
);
2130 nsresult rv
= helper
->DispatchToTransactionPool();
2131 if (NS_FAILED(rv
)) {
2132 IDB_WARNING("Failed to dispatch!");
2133 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2137 IDB_PROFILER_MARK("IndexedDB Request %llu: "
2138 "database(%s).transaction(%s).objectStore(%s).get(%s)",
2139 "IDBRequest[%llu] MT IDBObjectStore.get()",
2140 request
->GetSerialNumber(),
2141 IDB_PROFILER_STRING(Transaction()->Database()),
2142 IDB_PROFILER_STRING(Transaction()),
2143 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange
));
2145 return request
.forget();
2148 already_AddRefed
<IDBRequest
>
2149 IDBObjectStore::GetAllInternal(IDBKeyRange
* aKeyRange
,
2150 uint32_t aLimit
, ErrorResult
& aRv
)
2152 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2154 if (!mTransaction
->IsOpen()) {
2155 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2159 nsRefPtr
<IDBRequest
> request
= GenerateRequest(this);
2161 IDB_WARNING("Failed to generate request!");
2162 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2166 nsRefPtr
<GetAllHelper
> helper
=
2167 new GetAllHelper(mTransaction
, request
, this, aKeyRange
, aLimit
);
2169 nsresult rv
= helper
->DispatchToTransactionPool();
2170 if (NS_FAILED(rv
)) {
2171 IDB_WARNING("Failed to dispatch!");
2172 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2176 IDB_PROFILER_MARK("IndexedDB Request %llu: "
2177 "database(%s).transaction(%s).objectStore(%s)."
2179 "IDBRequest[%llu] MT IDBObjectStore.getAll()",
2180 request
->GetSerialNumber(),
2181 IDB_PROFILER_STRING(Transaction()->Database()),
2182 IDB_PROFILER_STRING(Transaction()),
2183 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange
),
2186 return request
.forget();
2189 already_AddRefed
<IDBRequest
>
2190 IDBObjectStore::GetAllKeysInternal(IDBKeyRange
* aKeyRange
, uint32_t aLimit
,
2193 MOZ_ASSERT(NS_IsMainThread());
2195 if (!mTransaction
->IsOpen()) {
2196 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2200 nsRefPtr
<IDBRequest
> request
= GenerateRequest(this);
2202 IDB_WARNING("Failed to generate request!");
2203 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2207 nsRefPtr
<GetAllKeysHelper
> helper
=
2208 new GetAllKeysHelper(mTransaction
, request
, this, aKeyRange
, aLimit
);
2210 nsresult rv
= helper
->DispatchToTransactionPool();
2211 if (NS_FAILED(rv
)) {
2212 IDB_WARNING("Failed to dispatch!");
2213 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2217 IDB_PROFILER_MARK("IndexedDB Request %llu: "
2218 "database(%s).transaction(%s).objectStore(%s)."
2219 "getAllKeys(%s, %lu)",
2220 "IDBRequest[%llu] MT IDBObjectStore.getAllKeys()",
2221 request
->GetSerialNumber(),
2222 IDB_PROFILER_STRING(Transaction()->Database()),
2223 IDB_PROFILER_STRING(Transaction()),
2224 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange
),
2227 return request
.forget();
2230 already_AddRefed
<IDBRequest
>
2231 IDBObjectStore::DeleteInternal(IDBKeyRange
* aKeyRange
,
2234 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2235 NS_ASSERTION(aKeyRange
, "Null key range!");
2237 if (!mTransaction
->IsOpen()) {
2238 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2242 if (!IsWriteAllowed()) {
2243 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR
);
2247 nsRefPtr
<IDBRequest
> request
= GenerateRequest(this);
2249 IDB_WARNING("Failed to generate request!");
2250 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2254 nsRefPtr
<DeleteHelper
> helper
=
2255 new DeleteHelper(mTransaction
, request
, this, aKeyRange
);
2257 nsresult rv
= helper
->DispatchToTransactionPool();
2258 if (NS_FAILED(rv
)) {
2259 IDB_WARNING("Failed to dispatch!");
2260 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2264 IDB_PROFILER_MARK("IndexedDB Request %llu: "
2265 "database(%s).transaction(%s).objectStore(%s).delete(%s)",
2266 "IDBRequest[%llu] MT IDBObjectStore.delete()",
2267 request
->GetSerialNumber(),
2268 IDB_PROFILER_STRING(Transaction()->Database()),
2269 IDB_PROFILER_STRING(Transaction()),
2270 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange
));
2272 return request
.forget();
2275 already_AddRefed
<IDBRequest
>
2276 IDBObjectStore::Clear(ErrorResult
& aRv
)
2278 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2280 if (!mTransaction
->IsOpen()) {
2281 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2285 if (!IsWriteAllowed()) {
2286 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR
);
2290 nsRefPtr
<IDBRequest
> request
= GenerateRequest(this);
2292 IDB_WARNING("Failed to generate request!");
2293 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2297 nsRefPtr
<ClearHelper
> helper(new ClearHelper(mTransaction
, request
, this));
2299 nsresult rv
= helper
->DispatchToTransactionPool();
2300 if (NS_FAILED(rv
)) {
2301 IDB_WARNING("Failed to dispatch!");
2302 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2306 IDB_PROFILER_MARK("IndexedDB Request %llu: "
2307 "database(%s).transaction(%s).objectStore(%s).clear()",
2308 "IDBRequest[%llu] MT IDBObjectStore.clear()",
2309 request
->GetSerialNumber(),
2310 IDB_PROFILER_STRING(Transaction()->Database()),
2311 IDB_PROFILER_STRING(Transaction()),
2312 IDB_PROFILER_STRING(this));
2314 return request
.forget();
2317 already_AddRefed
<IDBRequest
>
2318 IDBObjectStore::CountInternal(IDBKeyRange
* aKeyRange
, ErrorResult
& aRv
)
2320 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2322 if (!mTransaction
->IsOpen()) {
2323 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2327 nsRefPtr
<IDBRequest
> request
= GenerateRequest(this);
2329 IDB_WARNING("Failed to generate request!");
2330 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2334 nsRefPtr
<CountHelper
> helper
=
2335 new CountHelper(mTransaction
, request
, this, aKeyRange
);
2336 nsresult rv
= helper
->DispatchToTransactionPool();
2337 if (NS_FAILED(rv
)) {
2338 IDB_WARNING("Failed to dispatch!");
2339 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2343 IDB_PROFILER_MARK("IndexedDB Request %llu: "
2344 "database(%s).transaction(%s).objectStore(%s).count(%s)",
2345 "IDBRequest[%llu] MT IDBObjectStore.count()",
2346 request
->GetSerialNumber(),
2347 IDB_PROFILER_STRING(Transaction()->Database()),
2348 IDB_PROFILER_STRING(Transaction()),
2349 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange
));
2351 return request
.forget();
2354 already_AddRefed
<IDBRequest
>
2355 IDBObjectStore::OpenCursorInternal(IDBKeyRange
* aKeyRange
,
2356 size_t aDirection
, ErrorResult
& aRv
)
2358 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2360 if (!mTransaction
->IsOpen()) {
2361 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2365 IDBCursor::Direction direction
=
2366 static_cast<IDBCursor::Direction
>(aDirection
);
2368 nsRefPtr
<IDBRequest
> request
= GenerateRequest(this);
2370 IDB_WARNING("Failed to generate request!");
2371 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2375 nsRefPtr
<OpenCursorHelper
> helper
=
2376 new OpenCursorHelper(mTransaction
, request
, this, aKeyRange
, direction
);
2378 nsresult rv
= helper
->DispatchToTransactionPool();
2379 if (NS_FAILED(rv
)) {
2380 IDB_WARNING("Failed to dispatch!");
2381 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2385 IDB_PROFILER_MARK("IndexedDB Request %llu: "
2386 "database(%s).transaction(%s).objectStore(%s)."
2387 "openCursor(%s, %s)",
2388 "IDBRequest[%llu] MT IDBObjectStore.openCursor()",
2389 request
->GetSerialNumber(),
2390 IDB_PROFILER_STRING(Transaction()->Database()),
2391 IDB_PROFILER_STRING(Transaction()),
2392 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange
),
2393 IDB_PROFILER_STRING(direction
));
2395 return request
.forget();
2399 IDBObjectStore::OpenCursorFromChildProcess(
2400 IDBRequest
* aRequest
,
2403 const SerializedStructuredCloneReadInfo
& aCloneInfo
,
2404 nsTArray
<StructuredCloneFile
>& aBlobs
,
2405 IDBCursor
** _retval
)
2407 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2408 NS_ASSERTION((!aCloneInfo
.dataLength
&& !aCloneInfo
.data
) ||
2409 (aCloneInfo
.dataLength
&& aCloneInfo
.data
),
2410 "Inconsistent clone info!");
2412 IDBCursor::Direction direction
=
2413 static_cast<IDBCursor::Direction
>(aDirection
);
2415 StructuredCloneReadInfo cloneInfo
;
2417 if (!cloneInfo
.SetFromSerialized(aCloneInfo
)) {
2418 IDB_WARNING("Failed to copy clone buffer!");
2419 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
2422 cloneInfo
.mFiles
.SwapElements(aBlobs
);
2424 nsRefPtr
<IDBCursor
> cursor
=
2425 IDBCursor::Create(aRequest
, mTransaction
, this, direction
, Key(),
2426 EmptyCString(), EmptyCString(), aKey
, Move(cloneInfo
));
2427 IDB_ENSURE_TRUE(cursor
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2429 NS_ASSERTION(!cloneInfo
.mCloneBuffer
.data(), "Should have swapped!");
2431 cursor
.forget(_retval
);
2436 IDBObjectStore::OpenCursorFromChildProcess(IDBRequest
* aRequest
,
2439 IDBCursor
** _retval
)
2441 MOZ_ASSERT(NS_IsMainThread());
2442 MOZ_ASSERT(aRequest
);
2444 auto direction
= static_cast<IDBCursor::Direction
>(aDirection
);
2446 nsRefPtr
<IDBCursor
> cursor
=
2447 IDBCursor::Create(aRequest
, mTransaction
, this, direction
, Key(),
2448 EmptyCString(), EmptyCString(), aKey
);
2449 IDB_ENSURE_TRUE(cursor
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2451 cursor
.forget(_retval
);
2455 already_AddRefed
<IDBRequest
>
2456 IDBObjectStore::OpenKeyCursorInternal(IDBKeyRange
* aKeyRange
, size_t aDirection
,
2459 MOZ_ASSERT(NS_IsMainThread());
2461 if (!mTransaction
->IsOpen()) {
2462 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2466 nsRefPtr
<IDBRequest
> request
= GenerateRequest(this);
2468 IDB_WARNING("Failed to generate request!");
2469 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2473 auto direction
= static_cast<IDBCursor::Direction
>(aDirection
);
2475 nsRefPtr
<OpenKeyCursorHelper
> helper
=
2476 new OpenKeyCursorHelper(mTransaction
, request
, this, aKeyRange
, direction
);
2478 nsresult rv
= helper
->DispatchToTransactionPool();
2479 if (NS_FAILED(rv
)) {
2480 IDB_WARNING("Failed to dispatch!");
2481 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2485 IDB_PROFILER_MARK("IndexedDB Request %llu: "
2486 "database(%s).transaction(%s).objectStore(%s)."
2487 "openKeyCursor(%s, %s)",
2488 "IDBRequest[%llu] MT IDBObjectStore.openKeyCursor()",
2489 request
->GetSerialNumber(),
2490 IDB_PROFILER_STRING(Transaction()->Database()),
2491 IDB_PROFILER_STRING(Transaction()),
2492 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange
),
2493 IDB_PROFILER_STRING(direction
));
2495 return request
.forget();
2499 IDBObjectStore::SetInfo(ObjectStoreInfo
* aInfo
)
2501 NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
2502 NS_ASSERTION(aInfo
!= mInfo
, "This is nonsense");
2507 already_AddRefed
<IDBIndex
>
2508 IDBObjectStore::CreateIndexInternal(const IndexInfo
& aInfo
, ErrorResult
& aRv
)
2510 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2512 IndexInfo
* indexInfo
= mInfo
->indexes
.AppendElement();
2514 indexInfo
->name
= aInfo
.name
;
2515 indexInfo
->id
= aInfo
.id
;
2516 indexInfo
->keyPath
= aInfo
.keyPath
;
2517 indexInfo
->unique
= aInfo
.unique
;
2518 indexInfo
->multiEntry
= aInfo
.multiEntry
;
2520 // Don't leave this in the list if we fail below!
2521 AutoRemoveIndex
autoRemove(mInfo
, aInfo
.name
);
2523 nsRefPtr
<IDBIndex
> index
= IDBIndex::Create(this, indexInfo
, true);
2525 mCreatedIndexes
.AppendElement(index
);
2527 if (IndexedDatabaseManager::IsMainProcess()) {
2528 nsRefPtr
<CreateIndexHelper
> helper
=
2529 new CreateIndexHelper(mTransaction
, index
);
2531 nsresult rv
= helper
->DispatchToTransactionPool();
2532 if (NS_FAILED(rv
)) {
2533 IDB_WARNING("Failed to dispatch!");
2534 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2539 autoRemove
.forget();
2541 IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
2542 "database(%s).transaction(%s).objectStore(%s)."
2544 "MT IDBObjectStore.createIndex()",
2545 IDB_PROFILER_STRING(Transaction()->Database()),
2546 IDB_PROFILER_STRING(Transaction()),
2547 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(index
));
2549 return index
.forget();
2552 already_AddRefed
<IDBIndex
>
2553 IDBObjectStore::Index(const nsAString
& aName
, ErrorResult
&aRv
)
2555 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2557 if (mTransaction
->IsFinished()) {
2558 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2562 IndexInfo
* indexInfo
= nullptr;
2563 uint32_t indexCount
= mInfo
->indexes
.Length();
2564 for (uint32_t index
= 0; index
< indexCount
; index
++) {
2565 if (mInfo
->indexes
[index
].name
== aName
) {
2566 indexInfo
= &(mInfo
->indexes
[index
]);
2572 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR
);
2576 nsRefPtr
<IDBIndex
> retval
;
2577 for (uint32_t i
= 0; i
< mCreatedIndexes
.Length(); i
++) {
2578 nsRefPtr
<IDBIndex
>& index
= mCreatedIndexes
[i
];
2579 if (index
->Name() == aName
) {
2586 retval
= IDBIndex::Create(this, indexInfo
, false);
2588 IDB_WARNING("Failed to create index!");
2589 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2593 if (!mCreatedIndexes
.AppendElement(retval
)) {
2594 IDB_WARNING("Out of memory!");
2595 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2600 return retval
.forget();
2603 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore
)
2605 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore
)
2606 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
2607 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKeyPath
)
2608 NS_IMPL_CYCLE_COLLECTION_TRACE_END
2610 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore
)
2611 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
2612 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction
)
2614 for (uint32_t i
= 0; i
< tmp
->mCreatedIndexes
.Length(); i
++) {
2615 NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb
, "mCreatedIndexes[i]");
2616 cb
.NoteXPCOMChild(static_cast<nsISupports
*>(tmp
->mCreatedIndexes
[i
].get()));
2618 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
2620 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore
)
2621 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
2623 // Don't unlink mTransaction!
2625 tmp
->mCreatedIndexes
.Clear();
2627 tmp
->mCachedKeyPath
= JSVAL_VOID
;
2630 mozilla::DropJSObjects(tmp
);
2631 tmp
->mRooted
= false;
2633 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
2635 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBObjectStore
)
2636 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
2637 NS_INTERFACE_MAP_ENTRY(nsISupports
)
2638 NS_INTERFACE_MAP_END
2640 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBObjectStore
)
2641 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBObjectStore
)
2644 IDBObjectStore::WrapObject(JSContext
* aCx
)
2646 return IDBObjectStoreBinding::Wrap(aCx
, this);
2650 IDBObjectStore::GetKeyPath(JSContext
* aCx
, JS::MutableHandle
<JS::Value
> aResult
,
2653 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2655 if (!mCachedKeyPath
.isUndefined()) {
2656 JS::ExposeValueToActiveJS(mCachedKeyPath
);
2657 aResult
.set(mCachedKeyPath
);
2661 aRv
= GetKeyPath().ToJSVal(aCx
, mCachedKeyPath
);
2662 if (NS_WARN_IF(aRv
.Failed())) {
2666 if (mCachedKeyPath
.isGCThing()) {
2667 mozilla::HoldJSObjects(this);
2671 JS::ExposeValueToActiveJS(mCachedKeyPath
);
2672 aResult
.set(mCachedKeyPath
);
2675 already_AddRefed
<DOMStringList
>
2676 IDBObjectStore::GetIndexNames(ErrorResult
& aRv
)
2678 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2680 nsRefPtr
<DOMStringList
> list(new DOMStringList());
2682 nsTArray
<nsString
>& names
= list
->StringArray();
2683 uint32_t count
= mInfo
->indexes
.Length();
2684 names
.SetCapacity(count
);
2686 for (uint32_t index
= 0; index
< count
; index
++) {
2687 names
.InsertElementSorted(mInfo
->indexes
[index
].name
);
2690 return list
.forget();
2693 already_AddRefed
<IDBRequest
>
2694 IDBObjectStore::Get(JSContext
* aCx
, JS::Handle
<JS::Value
> aKey
,
2697 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2699 if (!mTransaction
->IsOpen()) {
2700 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2704 nsRefPtr
<IDBKeyRange
> keyRange
;
2705 aRv
= IDBKeyRange::FromJSVal(aCx
, aKey
, getter_AddRefs(keyRange
));
2706 ENSURE_SUCCESS(aRv
, nullptr);
2709 // Must specify a key or keyRange for get().
2710 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
2714 return GetInternal(keyRange
, aRv
);
2717 already_AddRefed
<IDBRequest
>
2718 IDBObjectStore::GetAll(JSContext
* aCx
,
2719 JS::Handle
<JS::Value
> aKey
,
2720 const Optional
<uint32_t>& aLimit
, ErrorResult
& aRv
)
2722 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2724 if (!mTransaction
->IsOpen()) {
2725 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2729 nsRefPtr
<IDBKeyRange
> keyRange
;
2730 aRv
= IDBKeyRange::FromJSVal(aCx
, aKey
, getter_AddRefs(keyRange
));
2731 ENSURE_SUCCESS(aRv
, nullptr);
2733 uint32_t limit
= UINT32_MAX
;
2734 if (aLimit
.WasPassed() && aLimit
.Value() != 0) {
2735 limit
= aLimit
.Value();
2738 return GetAllInternal(keyRange
, limit
, aRv
);
2741 already_AddRefed
<IDBRequest
>
2742 IDBObjectStore::Delete(JSContext
* aCx
, JS::Handle
<JS::Value
> aKey
,
2745 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2747 if (!mTransaction
->IsOpen()) {
2748 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2752 if (!IsWriteAllowed()) {
2753 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR
);
2757 nsRefPtr
<IDBKeyRange
> keyRange
;
2758 aRv
= IDBKeyRange::FromJSVal(aCx
, aKey
, getter_AddRefs(keyRange
));
2759 ENSURE_SUCCESS(aRv
, nullptr);
2762 // Must specify a key or keyRange for delete().
2763 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR
);
2767 return DeleteInternal(keyRange
, aRv
);
2770 already_AddRefed
<IDBRequest
>
2771 IDBObjectStore::OpenCursor(JSContext
* aCx
,
2772 JS::Handle
<JS::Value
> aRange
,
2773 IDBCursorDirection aDirection
, ErrorResult
& aRv
)
2775 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2777 if (!mTransaction
->IsOpen()) {
2778 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2782 nsRefPtr
<IDBKeyRange
> keyRange
;
2783 aRv
= IDBKeyRange::FromJSVal(aCx
, aRange
, getter_AddRefs(keyRange
));
2784 ENSURE_SUCCESS(aRv
, nullptr);
2786 IDBCursor::Direction direction
= IDBCursor::ConvertDirection(aDirection
);
2787 size_t argDirection
= static_cast<size_t>(direction
);
2789 return OpenCursorInternal(keyRange
, argDirection
, aRv
);
2792 already_AddRefed
<IDBIndex
>
2793 IDBObjectStore::CreateIndex(JSContext
* aCx
, const nsAString
& aName
,
2794 const nsAString
& aKeyPath
,
2795 const IDBIndexParameters
& aOptionalParameters
,
2798 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2801 if (NS_FAILED(KeyPath::Parse(aCx
, aKeyPath
, &keyPath
)) ||
2802 !keyPath
.IsValid()) {
2803 aRv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
2807 return CreateIndex(aCx
, aName
, keyPath
, aOptionalParameters
, aRv
);
2810 already_AddRefed
<IDBIndex
>
2811 IDBObjectStore::CreateIndex(JSContext
* aCx
, const nsAString
& aName
,
2812 const Sequence
<nsString
>& aKeyPath
,
2813 const IDBIndexParameters
& aOptionalParameters
,
2816 NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
2818 if (!aKeyPath
.Length()) {
2819 aRv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
2824 if (NS_FAILED(KeyPath::Parse(aCx
, aKeyPath
, &keyPath
))) {
2825 aRv
.Throw(NS_ERROR_DOM_SYNTAX_ERR
);
2829 return CreateIndex(aCx
, aName
, keyPath
, aOptionalParameters
, aRv
);
2832 already_AddRefed
<IDBIndex
>
2833 IDBObjectStore::CreateIndex(JSContext
* aCx
, const nsAString
& aName
,
2835 const IDBIndexParameters
& aOptionalParameters
,
2838 // Check name and current mode
2839 IDBTransaction
* transaction
= AsyncConnectionHelper::GetCurrentTransaction();
2842 transaction
!= mTransaction
||
2843 mTransaction
->GetMode() != IDBTransaction::VERSION_CHANGE
) {
2844 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
2849 uint32_t indexCount
= mInfo
->indexes
.Length();
2850 for (uint32_t index
= 0; index
< indexCount
; index
++) {
2851 if (mInfo
->indexes
[index
].name
== aName
) {
2858 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR
);
2862 NS_ASSERTION(mTransaction
->IsOpen(), "Impossible!");
2865 for (uint32_t index
= 0; index
< mCreatedIndexes
.Length(); index
++) {
2866 if (mCreatedIndexes
[index
]->Name() == aName
) {
2867 NS_ERROR("Already created this one!");
2872 if (aOptionalParameters
.mMultiEntry
&& aKeyPath
.IsArray()) {
2873 aRv
.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR
);
2877 DatabaseInfo
* databaseInfo
= mTransaction
->DBInfo();
2882 info
.id
= databaseInfo
->nextIndexId
++;
2883 info
.keyPath
= aKeyPath
;
2884 info
.unique
= aOptionalParameters
.mUnique
;
2885 info
.multiEntry
= aOptionalParameters
.mMultiEntry
;
2887 return CreateIndexInternal(info
, aRv
);
2891 IDBObjectStore::DeleteIndex(const nsAString
& aName
, ErrorResult
& aRv
)
2893 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2895 IDBTransaction
* transaction
= AsyncConnectionHelper::GetCurrentTransaction();
2898 transaction
!= mTransaction
||
2899 mTransaction
->GetMode() != IDBTransaction::VERSION_CHANGE
) {
2900 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR
);
2904 NS_ASSERTION(mTransaction
->IsOpen(), "Impossible!");
2907 for (; index
< mInfo
->indexes
.Length(); index
++) {
2908 if (mInfo
->indexes
[index
].name
== aName
) {
2913 if (index
== mInfo
->indexes
.Length()) {
2914 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR
);
2918 if (IndexedDatabaseManager::IsMainProcess()) {
2919 nsRefPtr
<DeleteIndexHelper
> helper
=
2920 new DeleteIndexHelper(mTransaction
, this, aName
);
2922 nsresult rv
= helper
->DispatchToTransactionPool();
2923 if (NS_FAILED(rv
)) {
2924 IDB_WARNING("Failed to dispatch!");
2925 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
2930 NS_ASSERTION(mActorChild
, "Must have an actor here!");
2932 mActorChild
->SendDeleteIndex(nsString(aName
));
2935 mInfo
->indexes
.RemoveElementAt(index
);
2937 for (uint32_t i
= 0; i
< mCreatedIndexes
.Length(); i
++) {
2938 if (mCreatedIndexes
[i
]->Name() == aName
) {
2939 mCreatedIndexes
.RemoveElementAt(i
);
2944 IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
2945 "database(%s).transaction(%s).objectStore(%s)."
2946 "deleteIndex(\"%s\")",
2947 "MT IDBObjectStore.deleteIndex()",
2948 IDB_PROFILER_STRING(Transaction()->Database()),
2949 IDB_PROFILER_STRING(Transaction()),
2950 IDB_PROFILER_STRING(this),
2951 NS_ConvertUTF16toUTF8(aName
).get());
2954 already_AddRefed
<IDBRequest
>
2955 IDBObjectStore::Count(JSContext
* aCx
,
2956 JS::Handle
<JS::Value
> aKey
,
2959 if (!mTransaction
->IsOpen()) {
2960 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2964 nsRefPtr
<IDBKeyRange
> keyRange
;
2965 aRv
= IDBKeyRange::FromJSVal(aCx
, aKey
, getter_AddRefs(keyRange
));
2966 ENSURE_SUCCESS(aRv
, nullptr);
2968 return CountInternal(keyRange
, aRv
);
2971 already_AddRefed
<IDBRequest
>
2972 IDBObjectStore::GetAllKeys(JSContext
* aCx
,
2973 JS::Handle
<JS::Value
> aKey
,
2974 const Optional
<uint32_t>& aLimit
, ErrorResult
& aRv
)
2976 MOZ_ASSERT(NS_IsMainThread());
2978 if (!mTransaction
->IsOpen()) {
2979 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
2983 nsRefPtr
<IDBKeyRange
> keyRange
;
2984 aRv
= IDBKeyRange::FromJSVal(aCx
, aKey
, getter_AddRefs(keyRange
));
2985 ENSURE_SUCCESS(aRv
, nullptr);
2987 uint32_t limit
= UINT32_MAX
;
2988 if (aLimit
.WasPassed() && aLimit
.Value() != 0) {
2989 limit
= aLimit
.Value();
2992 return GetAllKeysInternal(keyRange
, limit
, aRv
);
2995 already_AddRefed
<IDBRequest
>
2996 IDBObjectStore::OpenKeyCursor(JSContext
* aCx
,
2997 JS::Handle
<JS::Value
> aRange
,
2998 IDBCursorDirection aDirection
, ErrorResult
& aRv
)
3000 MOZ_ASSERT(NS_IsMainThread());
3002 if (!mTransaction
->IsOpen()) {
3003 aRv
.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR
);
3007 nsRefPtr
<IDBKeyRange
> keyRange
;
3008 aRv
= IDBKeyRange::FromJSVal(aCx
, aRange
, getter_AddRefs(keyRange
));
3009 ENSURE_SUCCESS(aRv
, nullptr);
3011 IDBCursor::Direction direction
= IDBCursor::ConvertDirection(aDirection
);
3013 return OpenKeyCursorInternal(keyRange
, static_cast<size_t>(direction
), aRv
);
3017 CopyData(nsIInputStream
* aInputStream
, nsIOutputStream
* aOutputStream
)
3019 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
3020 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3022 PROFILER_LABEL("IDBObjectStore", "CopyData",
3023 js::ProfileEntry::Category::STORAGE
);
3028 char copyBuffer
[FILE_COPY_BUFFER_SIZE
];
3031 rv
= aInputStream
->Read(copyBuffer
, sizeof(copyBuffer
), &numRead
);
3032 NS_ENSURE_SUCCESS(rv
, rv
);
3039 rv
= aOutputStream
->Write(copyBuffer
, numRead
, &numWrite
);
3040 if (rv
== NS_ERROR_FILE_NO_DEVICE_SPACE
) {
3041 rv
= NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR
;
3043 NS_ENSURE_SUCCESS(rv
, rv
);
3045 NS_ENSURE_TRUE(numWrite
== numRead
, NS_ERROR_FAILURE
);
3048 rv
= aOutputStream
->Flush();
3049 NS_ENSURE_SUCCESS(rv
, rv
);
3055 ObjectStoreHelper::ReleaseMainThreadObjects()
3057 mObjectStore
= nullptr;
3058 AsyncConnectionHelper::ReleaseMainThreadObjects();
3062 ObjectStoreHelper::Dispatch(nsIEventTarget
* aDatabaseThread
)
3064 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
3066 PROFILER_MAIN_THREAD_LABEL("ObjectStoreHelper", "Dispatch",
3067 js::ProfileEntry::Category::STORAGE
);
3069 if (IndexedDatabaseManager::IsMainProcess()) {
3070 return AsyncConnectionHelper::Dispatch(aDatabaseThread
);
3073 // If we've been invalidated then there's no point sending anything to the
3075 if (mObjectStore
->Transaction()->Database()->IsInvalidated()) {
3076 IDB_REPORT_INTERNAL_ERR();
3077 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
3080 IndexedDBObjectStoreChild
* objectStoreActor
= mObjectStore
->GetActorChild();
3081 NS_ASSERTION(objectStoreActor
, "Must have an actor here!");
3083 ObjectStoreRequestParams params
;
3085 // Our "parent" process may be either the root process or another content
3086 // process if this indexedDB is managed by a PBrowser that is managed by a
3087 // PContentBridge. We need to find which one it is so that we can create
3088 // PBlobs that are managed by the right nsIContentChild.
3089 IndexedDBChild
* rootActor
=
3090 static_cast<IndexedDBChild
*>(objectStoreActor
->Manager()->
3091 Manager()->Manager());
3092 nsIContentChild
* blobCreator
;
3093 if (rootActor
->GetManagerContent()) {
3094 blobCreator
= rootActor
->GetManagerContent();
3096 blobCreator
= rootActor
->GetManagerTab()->Manager();
3099 nsresult rv
= PackArgumentsForParentProcess(params
, blobCreator
);
3100 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3102 NoDispatchEventTarget target
;
3103 rv
= AsyncConnectionHelper::Dispatch(&target
);
3104 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3107 new IndexedDBObjectStoreRequestChild(this, mObjectStore
, params
.type());
3108 objectStoreActor
->SendPIndexedDBRequestConstructor(mActor
, params
);
3114 NoRequestObjectStoreHelper::ReleaseMainThreadObjects()
3116 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3117 mObjectStore
= nullptr;
3118 AsyncConnectionHelper::ReleaseMainThreadObjects();
3122 NoRequestObjectStoreHelper::UnpackResponseFromParentProcess(
3123 const ResponseValue
& aResponseValue
)
3128 AsyncConnectionHelper::ChildProcessSendResult
3129 NoRequestObjectStoreHelper::SendResponseToChildProcess(nsresult aResultCode
)
3131 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3132 return Success_NotSent
;
3136 NoRequestObjectStoreHelper::OnSuccess()
3138 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3143 NoRequestObjectStoreHelper::OnError()
3145 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3146 mTransaction
->Abort(GetResultCode());
3149 // This is a duplicate of the js engine's byte munging in StructuredClone.cpp
3151 ReinterpretDoubleAsUInt64(double d
)
3162 AddHelper::DoDatabaseWork(mozIStorageConnection
* aConnection
)
3164 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
3165 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3166 NS_ASSERTION(aConnection
, "Passed a null connection!");
3168 PROFILER_LABEL("AddHelper", "DoDatabaseWork",
3169 js::ProfileEntry::Category::STORAGE
);
3171 if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
3172 NS_WARNING("Refusing to add more data because disk space is low!");
3173 return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR
;
3177 bool keyUnset
= mKey
.IsUnset();
3178 int64_t osid
= mObjectStore
->Id();
3179 const KeyPath
& keyPath
= mObjectStore
->GetKeyPath();
3181 // The "|| keyUnset" here is mostly a debugging tool. If a key isn't
3182 // specified we should never have a collision and so it shouldn't matter
3183 // if we allow overwrite or not. By not allowing overwrite we raise
3184 // detectable errors rather than corrupting data
3185 nsCOMPtr
<mozIStorageStatement
> stmt
= !mOverwrite
|| keyUnset
?
3186 mTransaction
->GetCachedStatement(
3187 "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
3188 "VALUES (:osid, :key_value, :data, :file_ids)") :
3189 mTransaction
->GetCachedStatement(
3190 "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data, "
3192 "VALUES (:osid, :key_value, :data, :file_ids)");
3193 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3195 mozStorageStatementScoper
scoper(stmt
);
3197 rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid
);
3198 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3200 NS_ASSERTION(!keyUnset
|| mObjectStore
->IsAutoIncrement(),
3201 "Should have key unless autoincrement");
3203 int64_t autoIncrementNum
= 0;
3205 if (mObjectStore
->IsAutoIncrement()) {
3207 autoIncrementNum
= mObjectStore
->Info()->nextAutoIncrementId
;
3209 MOZ_ASSERT(autoIncrementNum
> 0,
3210 "Generated key must always be a positive integer");
3212 if (autoIncrementNum
> (1LL << 53)) {
3213 IDB_REPORT_INTERNAL_ERR();
3214 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
3217 mKey
.SetFromInteger(autoIncrementNum
);
3219 else if (mKey
.IsFloat() &&
3220 mKey
.ToFloat() >= mObjectStore
->Info()->nextAutoIncrementId
) {
3221 autoIncrementNum
= floor(mKey
.ToFloat());
3224 if (keyUnset
&& keyPath
.IsValid()) {
3225 // Special case where someone put an object into an autoIncrement'ing
3226 // objectStore with no key in its keyPath set. We needed to figure out
3227 // which row id we would get above before we could set that properly.
3229 LittleEndian::writeUint64((char*)mCloneWriteInfo
.mCloneBuffer
.data() +
3230 mCloneWriteInfo
.mOffsetToKeyProp
,
3231 ReinterpretDoubleAsUInt64(static_cast<double>(
3232 autoIncrementNum
)));
3236 mKey
.BindToStatement(stmt
, NS_LITERAL_CSTRING("key_value"));
3239 // Compress the bytes before adding into the database.
3240 const char* uncompressed
=
3241 reinterpret_cast<const char*>(mCloneWriteInfo
.mCloneBuffer
.data());
3242 size_t uncompressedLength
= mCloneWriteInfo
.mCloneBuffer
.nbytes();
3244 // We don't have a smart pointer class that calls moz_free, so we need to
3245 // manage | compressed | manually.
3247 size_t compressedLength
= snappy::MaxCompressedLength(uncompressedLength
);
3248 // moz_malloc is equivalent to NS_Alloc, which we use because mozStorage
3249 // expects to be able to free the adopted pointer with NS_Free.
3250 char* compressed
= (char*)moz_malloc(compressedLength
);
3251 NS_ENSURE_TRUE(compressed
, NS_ERROR_OUT_OF_MEMORY
);
3253 snappy::RawCompress(uncompressed
, uncompressedLength
, compressed
,
3256 uint8_t* dataBuffer
= reinterpret_cast<uint8_t*>(compressed
);
3257 size_t dataBufferLength
= compressedLength
;
3259 // If this call succeeds, | compressed | is now owned by the statement, and
3260 // we are no longer responsible for it.
3261 rv
= stmt
->BindAdoptedBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer
,
3263 if (NS_FAILED(rv
)) {
3264 moz_free(compressed
);
3266 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3270 uint32_t length
= mCloneWriteInfo
.mFiles
.Length();
3272 nsRefPtr
<FileManager
> fileManager
= mDatabase
->Manager();
3274 nsCOMPtr
<nsIFile
> directory
= fileManager
->GetDirectory();
3275 IDB_ENSURE_TRUE(directory
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3277 nsCOMPtr
<nsIFile
> journalDirectory
= fileManager
->EnsureJournalDirectory();
3278 IDB_ENSURE_TRUE(journalDirectory
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3280 nsAutoString fileIds
;
3282 for (uint32_t index
= 0; index
< length
; index
++) {
3283 StructuredCloneFile
& cloneFile
= mCloneWriteInfo
.mFiles
[index
];
3285 FileInfo
* fileInfo
= cloneFile
.mFileInfo
;
3286 nsIInputStream
* inputStream
= cloneFile
.mInputStream
;
3288 int64_t id
= fileInfo
->Id();
3290 // Create a journal file first
3291 nsCOMPtr
<nsIFile
> nativeFile
=
3292 fileManager
->GetFileForId(journalDirectory
, id
);
3293 IDB_ENSURE_TRUE(nativeFile
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3295 rv
= nativeFile
->Create(nsIFile::NORMAL_FILE_TYPE
, 0644);
3296 IDB_ENSURE_TRUE(nativeFile
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3298 // Now we can copy the blob
3299 nativeFile
= fileManager
->GetFileForId(directory
, id
);
3300 IDB_ENSURE_TRUE(nativeFile
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3302 IDBDatabase
* database
= mObjectStore
->Transaction()->Database();
3303 nsRefPtr
<FileOutputStream
> outputStream
=
3304 FileOutputStream::Create(database
->Type(), database
->Group(),
3305 database
->Origin(), nativeFile
);
3306 IDB_ENSURE_TRUE(outputStream
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3308 rv
= CopyData(inputStream
, outputStream
);
3309 if (NS_FAILED(rv
) &&
3310 NS_ERROR_GET_MODULE(rv
) != NS_ERROR_MODULE_DOM_INDEXEDDB
) {
3311 IDB_REPORT_INTERNAL_ERR();
3312 rv
= NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
3314 NS_ENSURE_SUCCESS(rv
, rv
);
3316 cloneFile
.mFile
->AddFileInfo(fileInfo
);
3320 fileIds
.Append(' ');
3322 fileIds
.AppendInt(id
);
3325 rv
= stmt
->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds
);
3328 rv
= stmt
->BindNullByName(NS_LITERAL_CSTRING("file_ids"));
3330 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3332 rv
= stmt
->Execute();
3333 if (rv
== NS_ERROR_STORAGE_CONSTRAINT
) {
3334 NS_ASSERTION(!keyUnset
, "Generated key had a collision!?");
3335 return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR
;
3337 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3339 int64_t objectDataId
;
3340 rv
= aConnection
->GetLastInsertRowID(&objectDataId
);
3341 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3343 // Update our indexes if needed.
3344 if (mOverwrite
|| !mIndexUpdateInfo
.IsEmpty()) {
3345 rv
= IDBObjectStore::UpdateIndexes(mTransaction
, osid
, mKey
, mOverwrite
,
3346 objectDataId
, mIndexUpdateInfo
);
3347 if (rv
== NS_ERROR_STORAGE_CONSTRAINT
) {
3348 return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR
;
3350 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3353 if (autoIncrementNum
) {
3354 mObjectStore
->Info()->nextAutoIncrementId
= autoIncrementNum
+ 1;
3361 AddHelper::GetSuccessResult(JSContext
* aCx
,
3362 JS::MutableHandle
<JS::Value
> aVal
)
3364 NS_ASSERTION(!mKey
.IsUnset(), "Badness!");
3366 mCloneWriteInfo
.mCloneBuffer
.clear();
3368 return mKey
.ToJSVal(aCx
, aVal
);
3372 AddHelper::ReleaseMainThreadObjects()
3374 IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo
);
3375 ObjectStoreHelper::ReleaseMainThreadObjects();
3379 AddHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
3380 nsIContentChild
* aBlobCreator
)
3382 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
3383 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3384 NS_ASSERTION(aBlobCreator
, "Must have a valid creator!");
3386 PROFILER_MAIN_THREAD_LABEL("AddHelper", "PackArgumentsForParentProcess",
3387 js::ProfileEntry::Category::STORAGE
);
3389 AddPutParams commonParams
;
3390 commonParams
.cloneInfo() = mCloneWriteInfo
;
3391 commonParams
.key() = mKey
;
3392 commonParams
.indexUpdateInfos().AppendElements(mIndexUpdateInfo
);
3394 const nsTArray
<StructuredCloneFile
>& files
= mCloneWriteInfo
.mFiles
;
3396 if (!files
.IsEmpty()) {
3397 uint32_t fileCount
= files
.Length();
3399 InfallibleTArray
<PBlobChild
*>& blobsChild
= commonParams
.blobsChild();
3400 blobsChild
.SetCapacity(fileCount
);
3402 NS_ASSERTION(aBlobCreator
, "This should never be null!");
3404 for (uint32_t index
= 0; index
< fileCount
; index
++) {
3405 const StructuredCloneFile
& file
= files
[index
];
3407 NS_ASSERTION(file
.mFile
, "This should never be null!");
3408 NS_ASSERTION(!file
.mFileInfo
, "This is not yet supported!");
3411 aBlobCreator
->GetOrCreateActorForBlob(file
.mFile
);
3413 IDB_REPORT_INTERNAL_ERR();
3414 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
3416 blobsChild
.AppendElement(actor
);
3421 PutParams putParams
;
3422 putParams
.commonParams() = commonParams
;
3423 aParams
= putParams
;
3426 AddParams addParams
;
3427 addParams
.commonParams() = commonParams
;
3428 aParams
= addParams
;
3434 AsyncConnectionHelper::ChildProcessSendResult
3435 AddHelper::SendResponseToChildProcess(nsresult aResultCode
)
3437 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
3438 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3440 PROFILER_MAIN_THREAD_LABEL("AddHelper", "SendResponseToChildProcess",
3441 js::ProfileEntry::Category::STORAGE
);
3443 IndexedDBRequestParentBase
* actor
= mRequest
->GetActorParent();
3444 NS_ASSERTION(actor
, "How did we get this far without an actor?");
3446 ResponseValue response
;
3447 if (NS_FAILED(aResultCode
)) {
3448 response
= aResultCode
;
3450 else if (mOverwrite
) {
3451 PutResponse putResponse
;
3452 putResponse
.key() = mKey
;
3453 response
= putResponse
;
3456 AddResponse addResponse
;
3457 addResponse
.key() = mKey
;
3458 response
= addResponse
;
3461 if (!actor
->SendResponse(response
)) {
3465 return Success_Sent
;
3469 AddHelper::UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
3471 NS_ASSERTION(aResponseValue
.type() == ResponseValue::TAddResponse
||
3472 aResponseValue
.type() == ResponseValue::TPutResponse
,
3473 "Bad response type!");
3476 aResponseValue
.get_PutResponse().key() :
3477 aResponseValue
.get_AddResponse().key();
3483 GetHelper::DoDatabaseWork(mozIStorageConnection
* /* aConnection */)
3485 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
3486 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3487 NS_ASSERTION(mKeyRange
, "Must have a key range here!");
3489 PROFILER_LABEL("GetHelper", "DoDatabaseWork [IDBObjectStore.cpp]",
3490 js::ProfileEntry::Category::STORAGE
);
3492 nsCString keyRangeClause
;
3493 mKeyRange
->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause
);
3495 NS_ASSERTION(!keyRangeClause
.IsEmpty(), "Huh?!");
3497 nsCString query
= NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
3498 "WHERE object_store_id = :osid") +
3499 keyRangeClause
+ NS_LITERAL_CSTRING(" LIMIT 1");
3501 nsCOMPtr
<mozIStorageStatement
> stmt
= mTransaction
->GetCachedStatement(query
);
3502 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3504 mozStorageStatementScoper
scoper(stmt
);
3507 stmt
->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore
->Id());
3508 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3510 rv
= mKeyRange
->BindToStatement(stmt
);
3511 NS_ENSURE_SUCCESS(rv
, rv
);
3514 rv
= stmt
->ExecuteStep(&hasResult
);
3515 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3518 rv
= IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt
, 0, 1,
3519 mDatabase
, mCloneReadInfo
);
3520 NS_ENSURE_SUCCESS(rv
, rv
);
3527 GetHelper::GetSuccessResult(JSContext
* aCx
,
3528 JS::MutableHandle
<JS::Value
> aVal
)
3530 bool result
= IDBObjectStore::DeserializeValue(aCx
, mCloneReadInfo
, aVal
);
3532 mCloneReadInfo
.mCloneBuffer
.clear();
3534 NS_ENSURE_TRUE(result
, NS_ERROR_DOM_DATA_CLONE_ERR
);
3539 GetHelper::ReleaseMainThreadObjects()
3541 mKeyRange
= nullptr;
3542 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo
);
3543 ObjectStoreHelper::ReleaseMainThreadObjects();
3547 GetHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
3548 nsIContentChild
* aBlobCreator
)
3550 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
3551 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3552 NS_ASSERTION(mKeyRange
, "This should never be null!");
3553 NS_ASSERTION(aBlobCreator
, "Must have a valid creator!");
3555 PROFILER_MAIN_THREAD_LABEL("GetHelper", "PackArgumentsForParentProcess [IDBObjectStore.cpp]",
3556 js::ProfileEntry::Category::STORAGE
);
3560 mKeyRange
->ToSerializedKeyRange(params
.keyRange());
3566 AsyncConnectionHelper::ChildProcessSendResult
3567 GetHelper::SendResponseToChildProcess(nsresult aResultCode
)
3569 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
3570 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3572 PROFILER_MAIN_THREAD_LABEL("GetHelper", "SendResponseToChildProcess [IDBObjectStore.cpp]",
3573 js::ProfileEntry::Category::STORAGE
);
3575 IndexedDBRequestParentBase
* actor
= mRequest
->GetActorParent();
3576 NS_ASSERTION(actor
, "How did we get this far without an actor?");
3578 InfallibleTArray
<PBlobParent
*> blobsParent
;
3580 if (NS_SUCCEEDED(aResultCode
)) {
3581 IDBDatabase
* database
= mObjectStore
->Transaction()->Database();
3582 NS_ASSERTION(database
, "This should never be null!");
3584 nsIContentParent
* contentParent
= database
->GetContentParent();
3585 NS_ASSERTION(contentParent
, "This should never be null!");
3587 FileManager
* fileManager
= database
->Manager();
3588 NS_ASSERTION(fileManager
, "This should never be null!");
3590 const nsTArray
<StructuredCloneFile
>& files
= mCloneReadInfo
.mFiles
;
3593 IDBObjectStore::ConvertBlobsToActors(contentParent
, fileManager
, files
,
3595 if (NS_FAILED(aResultCode
)) {
3596 NS_WARNING("ConvertBlobsToActors failed!");
3600 ResponseValue response
;
3601 if (NS_FAILED(aResultCode
)) {
3602 response
= aResultCode
;
3605 GetResponse getResponse
;
3606 getResponse
.cloneInfo() = mCloneReadInfo
;
3607 getResponse
.blobsParent().SwapElements(blobsParent
);
3608 response
= getResponse
;
3611 if (!actor
->SendResponse(response
)) {
3615 return Success_Sent
;
3619 GetHelper::UnpackResponseFromParentProcess(const ResponseValue
& aResponseValue
)
3621 NS_ASSERTION(aResponseValue
.type() == ResponseValue::TGetResponse
,
3622 "Bad response type!");
3624 const GetResponse
& getResponse
= aResponseValue
.get_GetResponse();
3625 const SerializedStructuredCloneReadInfo
& cloneInfo
= getResponse
.cloneInfo();
3627 NS_ASSERTION((!cloneInfo
.dataLength
&& !cloneInfo
.data
) ||
3628 (cloneInfo
.dataLength
&& cloneInfo
.data
),
3629 "Inconsistent clone info!");
3631 if (!mCloneReadInfo
.SetFromSerialized(cloneInfo
)) {
3632 IDB_WARNING("Failed to copy clone buffer!");
3633 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
3636 IDBObjectStore::ConvertActorsToBlobs(getResponse
.blobsChild(),
3637 mCloneReadInfo
.mFiles
);
3642 DeleteHelper::DoDatabaseWork(mozIStorageConnection
* /*aConnection */)
3644 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
3645 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3646 NS_ASSERTION(mKeyRange
, "Must have a key range here!");
3648 PROFILER_LABEL("DeleteHelper", "DoDatabaseWork",
3649 js::ProfileEntry::Category::STORAGE
);
3651 nsCString keyRangeClause
;
3652 mKeyRange
->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause
);
3654 NS_ASSERTION(!keyRangeClause
.IsEmpty(), "Huh?!");
3656 nsCString query
= NS_LITERAL_CSTRING("DELETE FROM object_data "
3657 "WHERE object_store_id = :osid") +
3660 nsCOMPtr
<mozIStorageStatement
> stmt
= mTransaction
->GetCachedStatement(query
);
3661 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3663 mozStorageStatementScoper
scoper(stmt
);
3665 nsresult rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
3666 mObjectStore
->Id());
3667 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3669 rv
= mKeyRange
->BindToStatement(stmt
);
3670 NS_ENSURE_SUCCESS(rv
, rv
);
3672 rv
= stmt
->Execute();
3673 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3679 DeleteHelper::GetSuccessResult(JSContext
* aCx
,
3680 JS::MutableHandle
<JS::Value
> aVal
)
3682 aVal
.setUndefined();
3687 DeleteHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
3688 nsIContentChild
* aBlobCreator
)
3690 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
3691 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3692 NS_ASSERTION(mKeyRange
, "This should never be null!");
3693 NS_ASSERTION(aBlobCreator
, "Must have a valid creator!");
3695 PROFILER_MAIN_THREAD_LABEL("DeleteHelper", "PackArgumentsForParentProcess",
3696 js::ProfileEntry::Category::STORAGE
);
3698 DeleteParams params
;
3700 mKeyRange
->ToSerializedKeyRange(params
.keyRange());
3706 AsyncConnectionHelper::ChildProcessSendResult
3707 DeleteHelper::SendResponseToChildProcess(nsresult aResultCode
)
3709 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
3710 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3712 PROFILER_MAIN_THREAD_LABEL("DeleteHelper", "SendResponseToChildProcess",
3713 js::ProfileEntry::Category::STORAGE
);
3715 IndexedDBRequestParentBase
* actor
= mRequest
->GetActorParent();
3716 NS_ASSERTION(actor
, "How did we get this far without an actor?");
3718 ResponseValue response
;
3719 if (NS_FAILED(aResultCode
)) {
3720 response
= aResultCode
;
3723 response
= DeleteResponse();
3726 if (!actor
->SendResponse(response
)) {
3730 return Success_Sent
;
3734 DeleteHelper::UnpackResponseFromParentProcess(
3735 const ResponseValue
& aResponseValue
)
3737 NS_ASSERTION(aResponseValue
.type() == ResponseValue::TDeleteResponse
,
3738 "Bad response type!");
3744 ClearHelper::DoDatabaseWork(mozIStorageConnection
* aConnection
)
3746 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
3747 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3748 NS_ASSERTION(aConnection
, "Passed a null connection!");
3750 PROFILER_LABEL("ClearHelper", "DoDatabaseWork",
3751 js::ProfileEntry::Category::STORAGE
);
3753 nsCOMPtr
<mozIStorageStatement
> stmt
=
3754 mTransaction
->GetCachedStatement(
3755 NS_LITERAL_CSTRING("DELETE FROM object_data "
3756 "WHERE object_store_id = :osid"));
3757 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3759 mozStorageStatementScoper
scoper(stmt
);
3761 nsresult rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
3762 mObjectStore
->Id());
3763 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3765 rv
= stmt
->Execute();
3766 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3772 ClearHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
3773 nsIContentChild
* aBlobCreator
)
3775 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
3776 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3777 NS_ASSERTION(aBlobCreator
, "Must have a valid creator!");
3779 PROFILER_MAIN_THREAD_LABEL("ClearHelper", "PackArgumentsForParentProcess",
3780 js::ProfileEntry::Category::STORAGE
);
3782 aParams
= ClearParams();
3786 AsyncConnectionHelper::ChildProcessSendResult
3787 ClearHelper::SendResponseToChildProcess(nsresult aResultCode
)
3789 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
3790 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3792 PROFILER_MAIN_THREAD_LABEL("ClearHelper", "SendResponseToChildProcess",
3793 js::ProfileEntry::Category::STORAGE
);
3795 IndexedDBRequestParentBase
* actor
= mRequest
->GetActorParent();
3796 NS_ASSERTION(actor
, "How did we get this far without an actor?");
3798 ResponseValue response
;
3799 if (NS_FAILED(aResultCode
)) {
3800 response
= aResultCode
;
3803 response
= ClearResponse();
3806 if (!actor
->SendResponse(response
)) {
3810 return Success_Sent
;
3814 ClearHelper::UnpackResponseFromParentProcess(
3815 const ResponseValue
& aResponseValue
)
3817 NS_ASSERTION(aResponseValue
.type() == ResponseValue::TClearResponse
,
3818 "Bad response type!");
3824 OpenCursorHelper::DoDatabaseWork(mozIStorageConnection
* aConnection
)
3826 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
3827 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
3829 PROFILER_LABEL("OpenCursorHelper", "DoDatabaseWork [IDBObjectStore.cpp]",
3830 js::ProfileEntry::Category::STORAGE
);
3832 NS_NAMED_LITERAL_CSTRING(keyValue
, "key_value");
3834 nsCString keyRangeClause
;
3836 mKeyRange
->GetBindingClause(keyValue
, keyRangeClause
);
3839 nsAutoCString directionClause
;
3840 switch (mDirection
) {
3841 case IDBCursor::NEXT
:
3842 case IDBCursor::NEXT_UNIQUE
:
3843 directionClause
.AssignLiteral(" ORDER BY key_value ASC");
3846 case IDBCursor::PREV
:
3847 case IDBCursor::PREV_UNIQUE
:
3848 directionClause
.AssignLiteral(" ORDER BY key_value DESC");
3852 NS_NOTREACHED("Unknown direction type!");
3855 nsCString firstQuery
= NS_LITERAL_CSTRING("SELECT key_value, data, file_ids "
3857 "WHERE object_store_id = :id") +
3858 keyRangeClause
+ directionClause
+
3859 NS_LITERAL_CSTRING(" LIMIT 1");
3861 nsCOMPtr
<mozIStorageStatement
> stmt
=
3862 mTransaction
->GetCachedStatement(firstQuery
);
3863 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3865 mozStorageStatementScoper
scoper(stmt
);
3867 nsresult rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("id"),
3868 mObjectStore
->Id());
3869 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3872 rv
= mKeyRange
->BindToStatement(stmt
);
3873 NS_ENSURE_SUCCESS(rv
, rv
);
3877 rv
= stmt
->ExecuteStep(&hasResult
);
3878 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3885 rv
= mKey
.SetFromStatement(stmt
, 0);
3886 NS_ENSURE_SUCCESS(rv
, rv
);
3888 rv
= IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt
, 1, 2,
3889 mDatabase
, mCloneReadInfo
);
3890 NS_ENSURE_SUCCESS(rv
, rv
);
3892 // Now we need to make the query to get the next match.
3893 keyRangeClause
.Truncate();
3894 nsAutoCString continueToKeyRangeClause
;
3896 NS_NAMED_LITERAL_CSTRING(currentKey
, "current_key");
3897 NS_NAMED_LITERAL_CSTRING(rangeKey
, "range_key");
3899 switch (mDirection
) {
3900 case IDBCursor::NEXT
:
3901 case IDBCursor::NEXT_UNIQUE
:
3902 AppendConditionClause(keyValue
, currentKey
, false, false,
3904 AppendConditionClause(keyValue
, currentKey
, false, true,
3905 continueToKeyRangeClause
);
3906 if (mKeyRange
&& !mKeyRange
->Upper().IsUnset()) {
3907 AppendConditionClause(keyValue
, rangeKey
, true,
3908 !mKeyRange
->IsUpperOpen(), keyRangeClause
);
3909 AppendConditionClause(keyValue
, rangeKey
, true,
3910 !mKeyRange
->IsUpperOpen(),
3911 continueToKeyRangeClause
);
3912 mRangeKey
= mKeyRange
->Upper();
3916 case IDBCursor::PREV
:
3917 case IDBCursor::PREV_UNIQUE
:
3918 AppendConditionClause(keyValue
, currentKey
, true, false, keyRangeClause
);
3919 AppendConditionClause(keyValue
, currentKey
, true, true,
3920 continueToKeyRangeClause
);
3921 if (mKeyRange
&& !mKeyRange
->Lower().IsUnset()) {
3922 AppendConditionClause(keyValue
, rangeKey
, false,
3923 !mKeyRange
->IsLowerOpen(), keyRangeClause
);
3924 AppendConditionClause(keyValue
, rangeKey
, false,
3925 !mKeyRange
->IsLowerOpen(),
3926 continueToKeyRangeClause
);
3927 mRangeKey
= mKeyRange
->Lower();
3932 NS_NOTREACHED("Unknown direction type!");
3935 NS_NAMED_LITERAL_CSTRING(queryStart
, "SELECT key_value, data, file_ids "
3937 "WHERE object_store_id = :id");
3939 mContinueQuery
= queryStart
+ keyRangeClause
+ directionClause
+
3940 NS_LITERAL_CSTRING(" LIMIT ");
3942 mContinueToQuery
= queryStart
+ continueToKeyRangeClause
+ directionClause
+
3943 NS_LITERAL_CSTRING(" LIMIT ");
3949 OpenCursorHelper::EnsureCursor()
3951 if (mCursor
|| mKey
.IsUnset()) {
3955 mSerializedCloneReadInfo
= mCloneReadInfo
;
3957 NS_ASSERTION(mSerializedCloneReadInfo
.data
&&
3958 mSerializedCloneReadInfo
.dataLength
,
3959 "Shouldn't be possible!");
3961 nsRefPtr
<IDBCursor
> cursor
=
3962 IDBCursor::Create(mRequest
, mTransaction
, mObjectStore
, mDirection
,
3963 mRangeKey
, mContinueQuery
, mContinueToQuery
, mKey
,
3964 Move(mCloneReadInfo
));
3965 IDB_ENSURE_TRUE(cursor
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3967 NS_ASSERTION(!mCloneReadInfo
.mCloneBuffer
.data(), "Should have swapped!");
3969 mCursor
.swap(cursor
);
3974 OpenCursorHelper::GetSuccessResult(JSContext
* aCx
,
3975 JS::MutableHandle
<JS::Value
> aVal
)
3977 nsresult rv
= EnsureCursor();
3978 NS_ENSURE_SUCCESS(rv
, rv
);
3981 rv
= WrapNative(aCx
, mCursor
, aVal
);
3982 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
3985 aVal
.setUndefined();
3992 OpenCursorHelper::ReleaseMainThreadObjects()
3994 mKeyRange
= nullptr;
3995 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo
);
3999 // These don't need to be released on the main thread but they're only valid
4000 // as long as mCursor is set.
4001 mSerializedCloneReadInfo
.data
= nullptr;
4002 mSerializedCloneReadInfo
.dataLength
= 0;
4004 ObjectStoreHelper::ReleaseMainThreadObjects();
4008 OpenCursorHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
4009 nsIContentChild
* aBlobCreator
)
4011 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
4012 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
4013 NS_ASSERTION(aBlobCreator
, "Must have a valid creator!");
4015 PROFILER_MAIN_THREAD_LABEL("OpenCursorHelper", "PackArgumentsForParentProcess [IDBObjectStore.cpp]",
4016 js::ProfileEntry::Category::STORAGE
);
4018 OpenCursorParams params
;
4022 mKeyRange
->ToSerializedKeyRange(keyRange
);
4023 params
.optionalKeyRange() = keyRange
;
4026 params
.optionalKeyRange() = mozilla::void_t();
4029 params
.direction() = mDirection
;
4035 AsyncConnectionHelper::ChildProcessSendResult
4036 OpenCursorHelper::SendResponseToChildProcess(nsresult aResultCode
)
4038 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
4039 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
4040 NS_ASSERTION(!mCursor
, "Shouldn't have this yet!");
4042 PROFILER_MAIN_THREAD_LABEL("OpenCursorHelper", "SendResponseToChildProcess [IDBObjectStore.cpp]",
4043 js::ProfileEntry::Category::STORAGE
);
4045 IndexedDBRequestParentBase
* actor
= mRequest
->GetActorParent();
4046 NS_ASSERTION(actor
, "How did we get this far without an actor?");
4048 InfallibleTArray
<PBlobParent
*> blobsParent
;
4050 if (NS_SUCCEEDED(aResultCode
)) {
4051 IDBDatabase
* database
= mObjectStore
->Transaction()->Database();
4052 NS_ASSERTION(database
, "This should never be null!");
4054 nsIContentParent
* contentParent
= database
->GetContentParent();
4055 NS_ASSERTION(contentParent
, "This should never be null!");
4057 FileManager
* fileManager
= database
->Manager();
4058 NS_ASSERTION(fileManager
, "This should never be null!");
4060 const nsTArray
<StructuredCloneFile
>& files
= mCloneReadInfo
.mFiles
;
4063 IDBObjectStore::ConvertBlobsToActors(contentParent
, fileManager
, files
,
4065 if (NS_FAILED(aResultCode
)) {
4066 NS_WARNING("ConvertBlobsToActors failed!");
4070 if (NS_SUCCEEDED(aResultCode
)) {
4071 nsresult rv
= EnsureCursor();
4072 if (NS_FAILED(rv
)) {
4073 NS_WARNING("EnsureCursor failed!");
4078 ResponseValue response
;
4079 if (NS_FAILED(aResultCode
)) {
4080 response
= aResultCode
;
4083 OpenCursorResponse openCursorResponse
;
4086 openCursorResponse
= mozilla::void_t();
4089 IndexedDBObjectStoreParent
* objectStoreActor
=
4090 mObjectStore
->GetActorParent();
4091 NS_ASSERTION(objectStoreActor
, "Must have an actor here!");
4093 IndexedDBRequestParentBase
* requestActor
= mRequest
->GetActorParent();
4094 NS_ASSERTION(requestActor
, "Must have an actor here!");
4096 NS_ASSERTION(mSerializedCloneReadInfo
.data
&&
4097 mSerializedCloneReadInfo
.dataLength
,
4098 "Shouldn't be possible!");
4100 ObjectStoreCursorConstructorParams params
;
4101 params
.requestParent() = requestActor
;
4102 params
.direction() = mDirection
;
4103 params
.key() = mKey
;
4104 params
.optionalCloneInfo() = mSerializedCloneReadInfo
;
4105 params
.blobsParent().SwapElements(blobsParent
);
4107 if (!objectStoreActor
->OpenCursor(mCursor
, params
, openCursorResponse
)) {
4112 response
= openCursorResponse
;
4115 if (!actor
->SendResponse(response
)) {
4119 return Success_Sent
;
4123 OpenCursorHelper::UnpackResponseFromParentProcess(
4124 const ResponseValue
& aResponseValue
)
4126 NS_ASSERTION(aResponseValue
.type() == ResponseValue::TOpenCursorResponse
,
4127 "Bad response type!");
4128 NS_ASSERTION(aResponseValue
.get_OpenCursorResponse().type() ==
4129 OpenCursorResponse::Tvoid_t
||
4130 aResponseValue
.get_OpenCursorResponse().type() ==
4131 OpenCursorResponse::TPIndexedDBCursorChild
,
4132 "Bad response union type!");
4133 NS_ASSERTION(!mCursor
, "Shouldn't have this yet!");
4135 const OpenCursorResponse
& response
=
4136 aResponseValue
.get_OpenCursorResponse();
4138 switch (response
.type()) {
4139 case OpenCursorResponse::Tvoid_t
:
4142 case OpenCursorResponse::TPIndexedDBCursorChild
: {
4143 IndexedDBCursorChild
* actor
=
4144 static_cast<IndexedDBCursorChild
*>(
4145 response
.get_PIndexedDBCursorChild());
4147 mCursor
= actor
->ForgetStrongCursor();
4148 NS_ASSERTION(mCursor
, "This should never be null!");
4160 OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection
* /* aConnection */)
4162 MOZ_ASSERT(!NS_IsMainThread());
4163 MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
4165 PROFILER_LABEL("OpenKeyCursorHelper", "DoDatabaseWork [IDBObjectStore.cpp]",
4166 js::ProfileEntry::Category::STORAGE
);
4168 NS_NAMED_LITERAL_CSTRING(keyValue
, "key_value");
4169 NS_NAMED_LITERAL_CSTRING(id
, "id");
4170 NS_NAMED_LITERAL_CSTRING(openLimit
, " LIMIT ");
4172 nsAutoCString queryStart
= NS_LITERAL_CSTRING("SELECT ") + keyValue
+
4173 NS_LITERAL_CSTRING(" FROM object_data WHERE "
4174 "object_store_id = :") +
4177 nsAutoCString keyRangeClause
;
4179 mKeyRange
->GetBindingClause(keyValue
, keyRangeClause
);
4182 nsAutoCString directionClause
= NS_LITERAL_CSTRING(" ORDER BY ") + keyValue
;
4183 switch (mDirection
) {
4184 case IDBCursor::NEXT
:
4185 case IDBCursor::NEXT_UNIQUE
:
4186 directionClause
.AppendLiteral(" ASC");
4189 case IDBCursor::PREV
:
4190 case IDBCursor::PREV_UNIQUE
:
4191 directionClause
.AppendLiteral(" DESC");
4195 MOZ_CRASH("Unknown direction type!");
4198 nsCString firstQuery
= queryStart
+ keyRangeClause
+ directionClause
+
4199 openLimit
+ NS_LITERAL_CSTRING("1");
4201 nsCOMPtr
<mozIStorageStatement
> stmt
=
4202 mTransaction
->GetCachedStatement(firstQuery
);
4203 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4205 mozStorageStatementScoper
scoper(stmt
);
4207 nsresult rv
= stmt
->BindInt64ByName(id
, mObjectStore
->Id());
4208 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4211 rv
= mKeyRange
->BindToStatement(stmt
);
4212 NS_ENSURE_SUCCESS(rv
, rv
);
4216 rv
= stmt
->ExecuteStep(&hasResult
);
4217 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4224 rv
= mKey
.SetFromStatement(stmt
, 0);
4225 NS_ENSURE_SUCCESS(rv
, rv
);
4227 // Now we need to make the query to get the next match.
4228 keyRangeClause
.Truncate();
4229 nsAutoCString continueToKeyRangeClause
;
4231 NS_NAMED_LITERAL_CSTRING(currentKey
, "current_key");
4232 NS_NAMED_LITERAL_CSTRING(rangeKey
, "range_key");
4234 switch (mDirection
) {
4235 case IDBCursor::NEXT
:
4236 case IDBCursor::NEXT_UNIQUE
:
4237 AppendConditionClause(keyValue
, currentKey
, false, false,
4239 AppendConditionClause(keyValue
, currentKey
, false, true,
4240 continueToKeyRangeClause
);
4241 if (mKeyRange
&& !mKeyRange
->Upper().IsUnset()) {
4242 AppendConditionClause(keyValue
, rangeKey
, true,
4243 !mKeyRange
->IsUpperOpen(), keyRangeClause
);
4244 AppendConditionClause(keyValue
, rangeKey
, true,
4245 !mKeyRange
->IsUpperOpen(),
4246 continueToKeyRangeClause
);
4247 mRangeKey
= mKeyRange
->Upper();
4251 case IDBCursor::PREV
:
4252 case IDBCursor::PREV_UNIQUE
:
4253 AppendConditionClause(keyValue
, currentKey
, true, false, keyRangeClause
);
4254 AppendConditionClause(keyValue
, currentKey
, true, true,
4255 continueToKeyRangeClause
);
4256 if (mKeyRange
&& !mKeyRange
->Lower().IsUnset()) {
4257 AppendConditionClause(keyValue
, rangeKey
, false,
4258 !mKeyRange
->IsLowerOpen(), keyRangeClause
);
4259 AppendConditionClause(keyValue
, rangeKey
, false,
4260 !mKeyRange
->IsLowerOpen(),
4261 continueToKeyRangeClause
);
4262 mRangeKey
= mKeyRange
->Lower();
4267 MOZ_CRASH("Unknown direction type!");
4270 mContinueQuery
= queryStart
+ keyRangeClause
+ directionClause
+ openLimit
;
4271 mContinueToQuery
= queryStart
+ continueToKeyRangeClause
+ directionClause
+
4278 OpenKeyCursorHelper::EnsureCursor()
4280 MOZ_ASSERT(NS_IsMainThread());
4282 PROFILER_MAIN_THREAD_LABEL("OpenKeyCursorHelper", "EnsureCursor [IDBObjectStore.cpp]",
4283 js::ProfileEntry::Category::STORAGE
);
4285 if (mCursor
|| mKey
.IsUnset()) {
4289 mCursor
= IDBCursor::Create(mRequest
, mTransaction
, mObjectStore
, mDirection
,
4290 mRangeKey
, mContinueQuery
, mContinueToQuery
,
4292 IDB_ENSURE_TRUE(mCursor
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4298 OpenKeyCursorHelper::GetSuccessResult(JSContext
* aCx
,
4299 JS::MutableHandle
<JS::Value
> aVal
)
4301 MOZ_ASSERT(NS_IsMainThread());
4303 PROFILER_MAIN_THREAD_LABEL("OpenKeyCursorHelper", "GetSuccessResult [IDBObjectStore.cpp]",
4304 js::ProfileEntry::Category::STORAGE
);
4306 nsresult rv
= EnsureCursor();
4307 NS_ENSURE_SUCCESS(rv
, rv
);
4310 rv
= WrapNative(aCx
, mCursor
, aVal
);
4311 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4314 aVal
.setUndefined();
4321 OpenKeyCursorHelper::ReleaseMainThreadObjects()
4323 MOZ_ASSERT(NS_IsMainThread());
4325 mKeyRange
= nullptr;
4328 ObjectStoreHelper::ReleaseMainThreadObjects();
4332 OpenKeyCursorHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
4333 nsIContentChild
* aBlobCreator
)
4335 MOZ_ASSERT(NS_IsMainThread());
4336 MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
4337 NS_ASSERTION(aBlobCreator
, "Must have a valid creator!");
4339 PROFILER_MAIN_THREAD_LABEL("OpenKeyCursorHelper", "PackArgumentsForParentProcess [IDBObjectStore.cpp]",
4340 js::ProfileEntry::Category::STORAGE
);
4342 OpenKeyCursorParams params
;
4346 mKeyRange
->ToSerializedKeyRange(keyRange
);
4347 params
.optionalKeyRange() = keyRange
;
4350 params
.optionalKeyRange() = mozilla::void_t();
4353 params
.direction() = mDirection
;
4359 AsyncConnectionHelper::ChildProcessSendResult
4360 OpenKeyCursorHelper::SendResponseToChildProcess(nsresult aResultCode
)
4362 MOZ_ASSERT(NS_IsMainThread());
4363 MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
4364 MOZ_ASSERT(!mCursor
);
4366 PROFILER_MAIN_THREAD_LABEL("OpenKeyCursorHelper", "SendResponseToChildProcess [IDBObjectStore.cpp]",
4367 js::ProfileEntry::Category::STORAGE
);
4369 IndexedDBRequestParentBase
* actor
= mRequest
->GetActorParent();
4372 if (NS_SUCCEEDED(aResultCode
)) {
4373 nsresult rv
= EnsureCursor();
4374 if (NS_FAILED(rv
)) {
4375 NS_WARNING("EnsureCursor failed!");
4380 ResponseValue response
;
4381 if (NS_FAILED(aResultCode
)) {
4382 response
= aResultCode
;
4384 OpenCursorResponse openCursorResponse
;
4387 openCursorResponse
= mozilla::void_t();
4390 IndexedDBObjectStoreParent
* objectStoreActor
=
4391 mObjectStore
->GetActorParent();
4392 MOZ_ASSERT(objectStoreActor
);
4394 IndexedDBRequestParentBase
* requestActor
= mRequest
->GetActorParent();
4395 MOZ_ASSERT(requestActor
);
4397 ObjectStoreCursorConstructorParams params
;
4398 params
.requestParent() = requestActor
;
4399 params
.direction() = mDirection
;
4400 params
.key() = mKey
;
4401 params
.optionalCloneInfo() = mozilla::void_t();
4403 if (!objectStoreActor
->OpenCursor(mCursor
, params
, openCursorResponse
)) {
4408 response
= openCursorResponse
;
4411 if (!actor
->SendResponse(response
)) {
4415 return Success_Sent
;
4419 OpenKeyCursorHelper::UnpackResponseFromParentProcess(
4420 const ResponseValue
& aResponseValue
)
4422 MOZ_ASSERT(NS_IsMainThread());
4423 MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
4424 MOZ_ASSERT(aResponseValue
.type() == ResponseValue::TOpenCursorResponse
);
4425 MOZ_ASSERT(aResponseValue
.get_OpenCursorResponse().type() ==
4426 OpenCursorResponse::Tvoid_t
||
4427 aResponseValue
.get_OpenCursorResponse().type() ==
4428 OpenCursorResponse::TPIndexedDBCursorChild
);
4429 MOZ_ASSERT(!mCursor
);
4431 PROFILER_MAIN_THREAD_LABEL("OpenKeyCursorHelper", "UnpackResponseFromParentProcess [IDBObjectStore.cpp]",
4432 js::ProfileEntry::Category::STORAGE
);
4434 const OpenCursorResponse
& response
=
4435 aResponseValue
.get_OpenCursorResponse();
4437 switch (response
.type()) {
4438 case OpenCursorResponse::Tvoid_t
:
4441 case OpenCursorResponse::TPIndexedDBCursorChild
: {
4442 IndexedDBCursorChild
* actor
=
4443 static_cast<IndexedDBCursorChild
*>(
4444 response
.get_PIndexedDBCursorChild());
4446 mCursor
= actor
->ForgetStrongCursor();
4447 NS_ASSERTION(mCursor
, "This should never be null!");
4452 MOZ_CRASH("Unknown response union type!");
4459 CreateIndexHelper::DoDatabaseWork(mozIStorageConnection
* aConnection
)
4461 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
4462 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
4464 PROFILER_LABEL("CreateIndexHelper", "DoDatabaseWork",
4465 js::ProfileEntry::Category::STORAGE
);
4467 if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
4468 NS_WARNING("Refusing to create index because disk space is low!");
4469 return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR
;
4472 // Insert the data into the database.
4473 nsCOMPtr
<mozIStorageStatement
> stmt
=
4474 mTransaction
->GetCachedStatement(
4475 "INSERT INTO object_store_index (id, name, key_path, unique_index, "
4476 "multientry, object_store_id) "
4477 "VALUES (:id, :name, :key_path, :unique, :multientry, :osid)"
4479 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4481 mozStorageStatementScoper
scoper(stmt
);
4483 nsresult rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("id"),
4485 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4487 rv
= stmt
->BindStringByName(NS_LITERAL_CSTRING("name"), mIndex
->Name());
4488 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4490 nsAutoString keyPathSerialization
;
4491 mIndex
->GetKeyPath().SerializeToString(keyPathSerialization
);
4492 rv
= stmt
->BindStringByName(NS_LITERAL_CSTRING("key_path"),
4493 keyPathSerialization
);
4494 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4496 rv
= stmt
->BindInt32ByName(NS_LITERAL_CSTRING("unique"),
4497 mIndex
->IsUnique() ? 1 : 0);
4498 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4500 rv
= stmt
->BindInt32ByName(NS_LITERAL_CSTRING("multientry"),
4501 mIndex
->IsMultiEntry() ? 1 : 0);
4502 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4504 rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
4505 mIndex
->ObjectStore()->Id());
4506 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4508 if (NS_FAILED(stmt
->Execute())) {
4509 return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR
;
4515 aConnection
->GetLastInsertRowID(&id
);
4516 NS_ASSERTION(mIndex
->Id() == id
, "Bad index id!");
4520 // Now we need to populate the index with data from the object store.
4521 rv
= InsertDataFromObjectStore(aConnection
);
4522 if (NS_FAILED(rv
)) {
4530 CreateIndexHelper::ReleaseMainThreadObjects()
4533 NoRequestObjectStoreHelper::ReleaseMainThreadObjects();
4537 CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection
* aConnection
)
4539 nsCOMPtr
<mozIStorageStatement
> stmt
=
4540 mTransaction
->GetCachedStatement(
4541 NS_LITERAL_CSTRING("SELECT id, data, file_ids, key_value FROM "
4542 "object_data WHERE object_store_id = :osid"));
4543 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4545 mozStorageStatementScoper
scoper(stmt
);
4547 nsresult rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
4548 mIndex
->ObjectStore()->Id());
4549 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4551 IDB_ENSURE_TRUE(sTLSIndex
!= BAD_TLS_INDEX
,
4552 NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4555 rv
= stmt
->ExecuteStep(&hasResult
);
4556 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4558 // Bail early if we have no data to avoid creating the below runtime
4562 ThreadLocalJSRuntime
* tlsEntry
=
4563 reinterpret_cast<ThreadLocalJSRuntime
*>(PR_GetThreadPrivate(sTLSIndex
));
4566 tlsEntry
= ThreadLocalJSRuntime::Create();
4567 IDB_ENSURE_TRUE(tlsEntry
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4569 PR_SetThreadPrivate(sTLSIndex
, tlsEntry
);
4572 JSContext
* cx
= tlsEntry
->Context();
4573 JSAutoRequest
ar(cx
);
4574 JSAutoCompartment
ac(cx
, tlsEntry
->Global());
4577 StructuredCloneReadInfo cloneReadInfo
;
4578 rv
= IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt
, 1, 2,
4579 mDatabase
, cloneReadInfo
);
4580 NS_ENSURE_SUCCESS(rv
, rv
);
4582 JSAutoStructuredCloneBuffer
& buffer
= cloneReadInfo
.mCloneBuffer
;
4584 JSStructuredCloneCallbacks callbacks
= {
4585 IDBObjectStore::StructuredCloneReadCallback
<CreateIndexDeserializationTraits
>,
4593 JS::Rooted
<JS::Value
> clone(cx
);
4594 if (!buffer
.read(cx
, &clone
, &callbacks
, &cloneReadInfo
)) {
4595 NS_WARNING("Failed to deserialize structured clone data!");
4596 return NS_ERROR_DOM_DATA_CLONE_ERR
;
4599 nsTArray
<IndexUpdateInfo
> updateInfo
;
4600 rv
= IDBObjectStore::AppendIndexUpdateInfo(mIndex
->Id(),
4601 mIndex
->GetKeyPath(),
4603 mIndex
->IsMultiEntry(),
4604 tlsEntry
->Context(),
4606 NS_ENSURE_SUCCESS(rv
, rv
);
4608 int64_t objectDataID
= stmt
->AsInt64(0);
4611 rv
= key
.SetFromStatement(stmt
, 3);
4612 NS_ENSURE_SUCCESS(rv
, rv
);
4614 rv
= IDBObjectStore::UpdateIndexes(mTransaction
, mIndex
->Id(),
4615 key
, false, objectDataID
, updateInfo
);
4616 NS_ENSURE_SUCCESS(rv
, rv
);
4618 } while (NS_SUCCEEDED(rv
= stmt
->ExecuteStep(&hasResult
)) && hasResult
);
4619 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4625 CreateIndexHelper::DestroyTLSEntry(void* aPtr
)
4627 delete reinterpret_cast<ThreadLocalJSRuntime
*>(aPtr
);
4631 DeleteIndexHelper::DoDatabaseWork(mozIStorageConnection
* aConnection
)
4633 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
4634 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
4636 PROFILER_LABEL("DeleteIndexHelper", "DoDatabaseWork",
4637 js::ProfileEntry::Category::STORAGE
);
4639 nsCOMPtr
<mozIStorageStatement
> stmt
=
4640 mTransaction
->GetCachedStatement(
4641 "DELETE FROM object_store_index "
4642 "WHERE name = :name "
4644 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4646 mozStorageStatementScoper
scoper(stmt
);
4648 nsresult rv
= stmt
->BindStringByName(NS_LITERAL_CSTRING("name"), mName
);
4649 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4651 if (NS_FAILED(stmt
->Execute())) {
4652 return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR
;
4659 GetAllHelper::DoDatabaseWork(mozIStorageConnection
* aConnection
)
4661 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
4662 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
4664 PROFILER_LABEL("GetAllHelper", "DoDatabaseWork [IDBObjectStore.cpp]",
4665 js::ProfileEntry::Category::STORAGE
);
4667 NS_NAMED_LITERAL_CSTRING(lowerKeyName
, "lower_key");
4668 NS_NAMED_LITERAL_CSTRING(upperKeyName
, "upper_key");
4670 nsAutoCString keyRangeClause
;
4672 if (!mKeyRange
->Lower().IsUnset()) {
4673 keyRangeClause
= NS_LITERAL_CSTRING(" AND key_value");
4674 if (mKeyRange
->IsLowerOpen()) {
4675 keyRangeClause
.AppendLiteral(" > :");
4678 keyRangeClause
.AppendLiteral(" >= :");
4680 keyRangeClause
.Append(lowerKeyName
);
4683 if (!mKeyRange
->Upper().IsUnset()) {
4684 keyRangeClause
+= NS_LITERAL_CSTRING(" AND key_value");
4685 if (mKeyRange
->IsUpperOpen()) {
4686 keyRangeClause
.AppendLiteral(" < :");
4689 keyRangeClause
.AppendLiteral(" <= :");
4691 keyRangeClause
.Append(upperKeyName
);
4695 nsAutoCString limitClause
;
4696 if (mLimit
!= UINT32_MAX
) {
4697 limitClause
.AssignLiteral(" LIMIT ");
4698 limitClause
.AppendInt(mLimit
);
4701 nsCString query
= NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
4702 "WHERE object_store_id = :osid") +
4704 NS_LITERAL_CSTRING(" ORDER BY key_value ASC") +
4707 mCloneReadInfos
.SetCapacity(50);
4709 nsCOMPtr
<mozIStorageStatement
> stmt
= mTransaction
->GetCachedStatement(query
);
4710 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4712 mozStorageStatementScoper
scoper(stmt
);
4714 nsresult rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
4715 mObjectStore
->Id());
4716 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4719 if (!mKeyRange
->Lower().IsUnset()) {
4720 rv
= mKeyRange
->Lower().BindToStatement(stmt
, lowerKeyName
);
4721 NS_ENSURE_SUCCESS(rv
, rv
);
4723 if (!mKeyRange
->Upper().IsUnset()) {
4724 rv
= mKeyRange
->Upper().BindToStatement(stmt
, upperKeyName
);
4725 NS_ENSURE_SUCCESS(rv
, rv
);
4730 while (NS_SUCCEEDED((rv
= stmt
->ExecuteStep(&hasResult
))) && hasResult
) {
4731 if (mCloneReadInfos
.Capacity() == mCloneReadInfos
.Length()) {
4732 mCloneReadInfos
.SetCapacity(mCloneReadInfos
.Capacity() * 2);
4735 StructuredCloneReadInfo
* readInfo
= mCloneReadInfos
.AppendElement();
4736 NS_ASSERTION(readInfo
, "Shouldn't fail since SetCapacity succeeded!");
4738 rv
= IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt
, 0, 1,
4739 mDatabase
, *readInfo
);
4740 NS_ENSURE_SUCCESS(rv
, rv
);
4742 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4748 GetAllHelper::GetSuccessResult(JSContext
* aCx
,
4749 JS::MutableHandle
<JS::Value
> aVal
)
4751 NS_ASSERTION(mCloneReadInfos
.Length() <= mLimit
, "Too many results!");
4753 nsresult rv
= ConvertToArrayAndCleanup(aCx
, mCloneReadInfos
, aVal
);
4755 NS_ASSERTION(mCloneReadInfos
.IsEmpty(),
4756 "Should have cleared in ConvertToArrayAndCleanup");
4757 NS_ENSURE_SUCCESS(rv
, rv
);
4763 GetAllHelper::ReleaseMainThreadObjects()
4765 mKeyRange
= nullptr;
4766 for (uint32_t index
= 0; index
< mCloneReadInfos
.Length(); index
++) {
4767 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos
[index
]);
4769 ObjectStoreHelper::ReleaseMainThreadObjects();
4773 GetAllHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
4774 nsIContentChild
* aBlobCreator
)
4776 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
4777 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
4778 NS_ASSERTION(aBlobCreator
, "Must have a valid creator!");
4780 PROFILER_MAIN_THREAD_LABEL("GetAllHelper", "PackArgumentsForParentProcess [IDBObjectStore.cpp]",
4781 js::ProfileEntry::Category::STORAGE
);
4783 GetAllParams params
;
4787 mKeyRange
->ToSerializedKeyRange(keyRange
);
4788 params
.optionalKeyRange() = keyRange
;
4791 params
.optionalKeyRange() = mozilla::void_t();
4794 params
.limit() = mLimit
;
4800 AsyncConnectionHelper::ChildProcessSendResult
4801 GetAllHelper::SendResponseToChildProcess(nsresult aResultCode
)
4803 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
4804 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
4806 PROFILER_MAIN_THREAD_LABEL("GetAllHelper", "SendResponseToChildProcess [IDBObjectStore.cpp]",
4807 js::ProfileEntry::Category::STORAGE
);
4809 IndexedDBRequestParentBase
* actor
= mRequest
->GetActorParent();
4810 NS_ASSERTION(actor
, "How did we get this far without an actor?");
4812 GetAllResponse getAllResponse
;
4813 if (NS_SUCCEEDED(aResultCode
) && !mCloneReadInfos
.IsEmpty()) {
4814 IDBDatabase
* database
= mObjectStore
->Transaction()->Database();
4815 NS_ASSERTION(database
, "This should never be null!");
4817 nsIContentParent
* contentParent
= database
->GetContentParent();
4818 NS_ASSERTION(contentParent
, "This should never be null!");
4820 FileManager
* fileManager
= database
->Manager();
4821 NS_ASSERTION(fileManager
, "This should never be null!");
4823 uint32_t length
= mCloneReadInfos
.Length();
4825 InfallibleTArray
<SerializedStructuredCloneReadInfo
>& infos
=
4826 getAllResponse
.cloneInfos();
4827 infos
.SetCapacity(length
);
4829 InfallibleTArray
<BlobArray
>& blobArrays
= getAllResponse
.blobs();
4830 blobArrays
.SetCapacity(length
);
4832 for (uint32_t index
= 0;
4833 NS_SUCCEEDED(aResultCode
) && index
< length
;
4835 // Append the structured clone data.
4836 const StructuredCloneReadInfo
& clone
= mCloneReadInfos
[index
];
4837 SerializedStructuredCloneReadInfo
* info
= infos
.AppendElement();
4840 // Now take care of the files.
4841 const nsTArray
<StructuredCloneFile
>& files
= clone
.mFiles
;
4842 BlobArray
* blobArray
= blobArrays
.AppendElement();
4843 InfallibleTArray
<PBlobParent
*>& blobs
= blobArray
->blobsParent();
4846 IDBObjectStore::ConvertBlobsToActors(contentParent
, fileManager
, files
,
4848 if (NS_FAILED(aResultCode
)) {
4849 NS_WARNING("ConvertBlobsToActors failed!");
4855 ResponseValue response
;
4856 if (NS_FAILED(aResultCode
)) {
4857 response
= aResultCode
;
4860 response
= getAllResponse
;
4863 if (!actor
->SendResponse(response
)) {
4867 return Success_Sent
;
4871 GetAllHelper::UnpackResponseFromParentProcess(
4872 const ResponseValue
& aResponseValue
)
4874 NS_ASSERTION(aResponseValue
.type() == ResponseValue::TGetAllResponse
,
4875 "Bad response type!");
4877 const GetAllResponse
& getAllResponse
= aResponseValue
.get_GetAllResponse();
4878 const InfallibleTArray
<SerializedStructuredCloneReadInfo
>& cloneInfos
=
4879 getAllResponse
.cloneInfos();
4880 const InfallibleTArray
<BlobArray
>& blobArrays
= getAllResponse
.blobs();
4882 mCloneReadInfos
.SetCapacity(cloneInfos
.Length());
4884 for (uint32_t index
= 0; index
< cloneInfos
.Length(); index
++) {
4885 const SerializedStructuredCloneReadInfo srcInfo
= cloneInfos
[index
];
4886 const InfallibleTArray
<PBlobChild
*>& blobs
= blobArrays
[index
].blobsChild();
4888 StructuredCloneReadInfo
* destInfo
= mCloneReadInfos
.AppendElement();
4889 if (!destInfo
->SetFromSerialized(srcInfo
)) {
4890 IDB_WARNING("Failed to copy clone buffer!");
4891 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
4894 IDBObjectStore::ConvertActorsToBlobs(blobs
, destInfo
->mFiles
);
4901 GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection
* /* aConnection */)
4903 MOZ_ASSERT(!NS_IsMainThread());
4904 MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
4906 PROFILER_LABEL("GetAllKeysHelper", "DoDatabaseWork [IDObjectStore.cpp]",
4907 js::ProfileEntry::Category::STORAGE
);
4909 NS_NAMED_LITERAL_CSTRING(keyValue
, "key_value");
4911 nsAutoCString keyRangeClause
;
4913 mKeyRange
->GetBindingClause(keyValue
, keyRangeClause
);
4916 nsAutoCString limitClause
;
4917 if (mLimit
!= UINT32_MAX
) {
4918 limitClause
= NS_LITERAL_CSTRING(" LIMIT ");
4919 limitClause
.AppendInt(mLimit
);
4922 NS_NAMED_LITERAL_CSTRING(osid
, "osid");
4924 nsCString query
= NS_LITERAL_CSTRING("SELECT ") + keyValue
+
4925 NS_LITERAL_CSTRING(" FROM object_data WHERE "
4926 "object_store_id = :") +
4927 osid
+ keyRangeClause
+
4928 NS_LITERAL_CSTRING(" ORDER BY key_value ASC") +
4931 nsCOMPtr
<mozIStorageStatement
> stmt
= mTransaction
->GetCachedStatement(query
);
4932 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4934 mozStorageStatementScoper
scoper(stmt
);
4936 nsresult rv
= stmt
->BindInt64ByName(osid
, mObjectStore
->Id());
4937 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4940 rv
= mKeyRange
->BindToStatement(stmt
);
4941 NS_ENSURE_SUCCESS(rv
, rv
);
4944 mKeys
.SetCapacity(std::min
<uint32_t>(50, mLimit
));
4947 while(NS_SUCCEEDED((rv
= stmt
->ExecuteStep(&hasResult
))) && hasResult
) {
4948 if (mKeys
.Capacity() == mKeys
.Length()) {
4949 mKeys
.SetCapacity(mKeys
.Capacity() * 2);
4952 Key
* key
= mKeys
.AppendElement();
4953 NS_ASSERTION(key
, "This shouldn't fail!");
4955 rv
= key
->SetFromStatement(stmt
, 0);
4956 NS_ENSURE_SUCCESS(rv
, rv
);
4958 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
4964 GetAllKeysHelper::GetSuccessResult(JSContext
* aCx
,
4965 JS::MutableHandle
<JS::Value
> aVal
)
4967 MOZ_ASSERT(NS_IsMainThread());
4968 MOZ_ASSERT(mKeys
.Length() <= mLimit
);
4970 PROFILER_MAIN_THREAD_LABEL("GetAllKeysHelper", "GetSuccessResult [IDBObjectStore.cpp]",
4971 js::ProfileEntry::Category::STORAGE
);
4974 mKeys
.SwapElements(keys
);
4976 JS::Rooted
<JSObject
*> array(aCx
, JS_NewArrayObject(aCx
, 0));
4978 IDB_WARNING("Failed to make array!");
4979 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
4982 if (!keys
.IsEmpty()) {
4983 if (!JS_SetArrayLength(aCx
, array
, keys
.Length())) {
4984 IDB_WARNING("Failed to set array length!");
4985 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
4988 for (uint32_t index
= 0, count
= keys
.Length(); index
< count
; index
++) {
4989 const Key
& key
= keys
[index
];
4990 MOZ_ASSERT(!key
.IsUnset());
4992 JS::Rooted
<JS::Value
> value(aCx
);
4993 nsresult rv
= key
.ToJSVal(aCx
, &value
);
4994 if (NS_FAILED(rv
)) {
4995 NS_WARNING("Failed to get jsval for key!");
4999 if (!JS_SetElement(aCx
, array
, index
, value
)) {
5000 IDB_WARNING("Failed to set array element!");
5001 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
;
5006 aVal
.setObject(*array
);
5011 GetAllKeysHelper::ReleaseMainThreadObjects()
5013 MOZ_ASSERT(NS_IsMainThread());
5015 mKeyRange
= nullptr;
5017 ObjectStoreHelper::ReleaseMainThreadObjects();
5021 GetAllKeysHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
5022 nsIContentChild
* aBlobCreator
)
5024 MOZ_ASSERT(NS_IsMainThread());
5025 MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
5026 NS_ASSERTION(aBlobCreator
, "Must have a valid creator!");
5028 PROFILER_MAIN_THREAD_LABEL("GetAllKeysHelper", "PackArgumentsForParentProcess [IDBObjectStore.cpp]",
5029 js::ProfileEntry::Category::STORAGE
);
5031 GetAllKeysParams params
;
5035 mKeyRange
->ToSerializedKeyRange(keyRange
);
5036 params
.optionalKeyRange() = keyRange
;
5038 params
.optionalKeyRange() = mozilla::void_t();
5041 params
.limit() = mLimit
;
5047 AsyncConnectionHelper::ChildProcessSendResult
5048 GetAllKeysHelper::SendResponseToChildProcess(nsresult aResultCode
)
5050 MOZ_ASSERT(NS_IsMainThread());
5051 MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
5053 PROFILER_MAIN_THREAD_LABEL("GetAllKeysHelper", "SendResponseToChildProcess [IDBObjectStore.cpp]",
5054 js::ProfileEntry::Category::STORAGE
);
5056 IndexedDBRequestParentBase
* actor
= mRequest
->GetActorParent();
5059 ResponseValue response
;
5060 if (NS_FAILED(aResultCode
)) {
5061 response
= aResultCode
;
5064 GetAllKeysResponse getAllKeysResponse
;
5065 getAllKeysResponse
.keys().AppendElements(mKeys
);
5066 response
= getAllKeysResponse
;
5069 if (!actor
->SendResponse(response
)) {
5073 return Success_Sent
;
5077 GetAllKeysHelper::UnpackResponseFromParentProcess(
5078 const ResponseValue
& aResponseValue
)
5080 MOZ_ASSERT(NS_IsMainThread());
5081 MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
5082 MOZ_ASSERT(aResponseValue
.type() == ResponseValue::TGetAllKeysResponse
);
5084 mKeys
.AppendElements(aResponseValue
.get_GetAllKeysResponse().keys());
5089 CountHelper::DoDatabaseWork(mozIStorageConnection
* aConnection
)
5091 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
5092 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
5094 PROFILER_LABEL("CountHelper", "DoDatabaseWork [IDBObjectStore.cpp]",
5095 js::ProfileEntry::Category::STORAGE
);
5097 NS_NAMED_LITERAL_CSTRING(lowerKeyName
, "lower_key");
5098 NS_NAMED_LITERAL_CSTRING(upperKeyName
, "upper_key");
5100 nsAutoCString keyRangeClause
;
5102 if (!mKeyRange
->Lower().IsUnset()) {
5103 keyRangeClause
= NS_LITERAL_CSTRING(" AND key_value");
5104 if (mKeyRange
->IsLowerOpen()) {
5105 keyRangeClause
.AppendLiteral(" > :");
5108 keyRangeClause
.AppendLiteral(" >= :");
5110 keyRangeClause
.Append(lowerKeyName
);
5113 if (!mKeyRange
->Upper().IsUnset()) {
5114 keyRangeClause
+= NS_LITERAL_CSTRING(" AND key_value");
5115 if (mKeyRange
->IsUpperOpen()) {
5116 keyRangeClause
.AppendLiteral(" < :");
5119 keyRangeClause
.AppendLiteral(" <= :");
5121 keyRangeClause
.Append(upperKeyName
);
5125 nsCString query
= NS_LITERAL_CSTRING("SELECT count(*) FROM object_data "
5126 "WHERE object_store_id = :osid") +
5129 nsCOMPtr
<mozIStorageStatement
> stmt
= mTransaction
->GetCachedStatement(query
);
5130 IDB_ENSURE_TRUE(stmt
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
5132 mozStorageStatementScoper
scoper(stmt
);
5134 nsresult rv
= stmt
->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
5135 mObjectStore
->Id());
5136 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
5139 if (!mKeyRange
->Lower().IsUnset()) {
5140 rv
= mKeyRange
->Lower().BindToStatement(stmt
, lowerKeyName
);
5141 NS_ENSURE_SUCCESS(rv
, rv
);
5143 if (!mKeyRange
->Upper().IsUnset()) {
5144 rv
= mKeyRange
->Upper().BindToStatement(stmt
, upperKeyName
);
5145 NS_ENSURE_SUCCESS(rv
, rv
);
5150 rv
= stmt
->ExecuteStep(&hasResult
);
5151 IDB_ENSURE_SUCCESS(rv
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
5152 IDB_ENSURE_TRUE(hasResult
, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR
);
5154 mCount
= stmt
->AsInt64(0);
5159 CountHelper::GetSuccessResult(JSContext
* aCx
,
5160 JS::MutableHandle
<JS::Value
> aVal
)
5162 aVal
.setNumber(static_cast<double>(mCount
));
5167 CountHelper::ReleaseMainThreadObjects()
5169 mKeyRange
= nullptr;
5170 ObjectStoreHelper::ReleaseMainThreadObjects();
5174 CountHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams
& aParams
,
5175 nsIContentChild
* aBlobCreator
)
5177 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
5178 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
5179 NS_ASSERTION(aBlobCreator
, "Must have a valid creator!");
5181 PROFILER_MAIN_THREAD_LABEL("CountHelper", "PackArgumentsForParentProcess [IDBObjectStore.cpp]",
5182 js::ProfileEntry::Category::STORAGE
);
5188 mKeyRange
->ToSerializedKeyRange(keyRange
);
5189 params
.optionalKeyRange() = keyRange
;
5192 params
.optionalKeyRange() = mozilla::void_t();
5199 AsyncConnectionHelper::ChildProcessSendResult
5200 CountHelper::SendResponseToChildProcess(nsresult aResultCode
)
5202 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
5203 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
5205 PROFILER_MAIN_THREAD_LABEL("CountHelper", "SendResponseToChildProcess [IDBObjectStore.cpp]",
5206 js::ProfileEntry::Category::STORAGE
);
5208 IndexedDBRequestParentBase
* actor
= mRequest
->GetActorParent();
5209 NS_ASSERTION(actor
, "How did we get this far without an actor?");
5211 ResponseValue response
;
5212 if (NS_FAILED(aResultCode
)) {
5213 response
= aResultCode
;
5216 CountResponse countResponse
= mCount
;
5217 response
= countResponse
;
5220 if (!actor
->SendResponse(response
)) {
5224 return Success_Sent
;
5228 CountHelper::UnpackResponseFromParentProcess(
5229 const ResponseValue
& aResponseValue
)
5231 NS_ASSERTION(aResponseValue
.type() == ResponseValue::TCountResponse
,
5232 "Bad response type!");
5234 mCount
= aResponseValue
.get_CountResponse().count();