dom/indexedDB/IDBObjectStore.cpp

Wed, 31 Dec 2014 06:55:50 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:55:50 +0100
changeset 2
7e26c7da4463
permissions
-rw-r--r--

Added tag UPSTREAM_283F7C6 for changeset ca08bd8f51b2

     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"
    14 #include <algorithm>
    15 #include "jsfriendapi.h"
    16 #include "mozilla/dom/ContentChild.h"
    17 #include "mozilla/dom/ContentParent.h"
    18 #include "mozilla/dom/FileHandleBinding.h"
    19 #include "mozilla/dom/StructuredCloneTags.h"
    20 #include "mozilla/dom/ipc/Blob.h"
    21 #include "mozilla/dom/quota/FileStreams.h"
    22 #include "mozilla/Endian.h"
    23 #include "mozilla/storage.h"
    24 #include "nsContentUtils.h"
    25 #include "nsDOMClassInfo.h"
    26 #include "nsDOMFile.h"
    27 #include "mozilla/dom/DOMStringList.h"
    28 #include "nsJSUtils.h"
    29 #include "nsServiceManagerUtils.h"
    30 #include "nsThreadUtils.h"
    31 #include "snappy/snappy.h"
    33 #include "AsyncConnectionHelper.h"
    34 #include "IDBCursor.h"
    35 #include "IDBEvents.h"
    36 #include "IDBFileHandle.h"
    37 #include "IDBIndex.h"
    38 #include "IDBKeyRange.h"
    39 #include "IDBTransaction.h"
    40 #include "DatabaseInfo.h"
    41 #include "KeyPath.h"
    42 #include "ProfilerHelpers.h"
    43 #include "ReportInternalError.h"
    45 #include "ipc/IndexedDBChild.h"
    46 #include "ipc/IndexedDBParent.h"
    48 #include "IndexedDatabaseInlines.h"
    49 #include "nsCharSeparatedTokenizer.h"
    51 #define FILE_COPY_BUFFER_SIZE 32768
    53 USING_INDEXEDDB_NAMESPACE
    54 using namespace mozilla::dom;
    55 using namespace mozilla::dom::indexedDB::ipc;
    56 using mozilla::dom::quota::FileOutputStream;
    57 using mozilla::ErrorResult;
    58 using mozilla::fallible_t;
    59 using mozilla::LittleEndian;
    60 using mozilla::Move;
    61 using mozilla::NativeEndian;
    63 BEGIN_INDEXEDDB_NAMESPACE
    65 struct FileHandleData
    66 {
    67   nsString type;
    68   nsString name;
    69 };
    71 struct BlobOrFileData
    72 {
    73   BlobOrFileData()
    74   : tag(0), size(0), lastModifiedDate(UINT64_MAX)
    75   { }
    77   uint32_t tag;
    78   uint64_t size;
    79   nsString type;
    80   nsString name;
    81   uint64_t lastModifiedDate;
    82 };
    84 END_INDEXEDDB_NAMESPACE
    86 namespace {
    88 inline
    89 bool
    90 IgnoreNothing(char16_t c)
    91 {
    92   return false;
    93 }
    95 class ObjectStoreHelper : public AsyncConnectionHelper
    96 {
    97 public:
    98   ObjectStoreHelper(IDBTransaction* aTransaction,
    99                     IDBRequest* aRequest,
   100                     IDBObjectStore* aObjectStore)
   101   : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore),
   102     mActor(nullptr)
   103   {
   104     NS_ASSERTION(aTransaction, "Null transaction!");
   105     NS_ASSERTION(aRequest, "Null request!");
   106     NS_ASSERTION(aObjectStore, "Null object store!");
   107   }
   109   virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
   111   virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread) MOZ_OVERRIDE;
   113   virtual nsresult
   114   PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) = 0;
   116   virtual nsresult
   117   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0;
   119 protected:
   120   nsRefPtr<IDBObjectStore> mObjectStore;
   122 private:
   123   IndexedDBObjectStoreRequestChild* mActor;
   124 };
   126 class NoRequestObjectStoreHelper : public AsyncConnectionHelper
   127 {
   128 public:
   129   NoRequestObjectStoreHelper(IDBTransaction* aTransaction,
   130                              IDBObjectStore* aObjectStore)
   131   : AsyncConnectionHelper(aTransaction, nullptr), mObjectStore(aObjectStore)
   132   {
   133     NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   134     NS_ASSERTION(aTransaction, "Null transaction!");
   135     NS_ASSERTION(aObjectStore, "Null object store!");
   136   }
   138   virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
   140   virtual nsresult UnpackResponseFromParentProcess(
   141                                             const ResponseValue& aResponseValue)
   142                                             MOZ_OVERRIDE;
   144   virtual ChildProcessSendResult
   145   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   147   virtual nsresult OnSuccess() MOZ_OVERRIDE;
   149   virtual void OnError() MOZ_OVERRIDE;
   151 protected:
   152   nsRefPtr<IDBObjectStore> mObjectStore;
   153 };
   155 class AddHelper : public ObjectStoreHelper
   156 {
   157 public:
   158   AddHelper(IDBTransaction* aTransaction,
   159             IDBRequest* aRequest,
   160             IDBObjectStore* aObjectStore,
   161             StructuredCloneWriteInfo&& aCloneWriteInfo,
   162             const Key& aKey,
   163             bool aOverwrite,
   164             nsTArray<IndexUpdateInfo>& aIndexUpdateInfo)
   165   : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
   166     mCloneWriteInfo(Move(aCloneWriteInfo)),
   167     mKey(aKey),
   168     mOverwrite(aOverwrite)
   169   {
   170     mIndexUpdateInfo.SwapElements(aIndexUpdateInfo);
   171   }
   173   ~AddHelper()
   174   {
   175     IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo);
   176   }
   178   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
   179                                   MOZ_OVERRIDE;
   181   virtual nsresult GetSuccessResult(JSContext* aCx,
   182                                     JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
   184   virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
   186   virtual nsresult
   187   PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
   189   virtual ChildProcessSendResult
   190   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   192   virtual nsresult
   193   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
   194                                   MOZ_OVERRIDE;
   196 private:
   197   // These may change in the autoincrement case.
   198   StructuredCloneWriteInfo mCloneWriteInfo;
   199   Key mKey;
   200   nsTArray<IndexUpdateInfo> mIndexUpdateInfo;
   201   const bool mOverwrite;
   202 };
   204 class GetHelper : public ObjectStoreHelper
   205 {
   206 public:
   207   GetHelper(IDBTransaction* aTransaction,
   208             IDBRequest* aRequest,
   209             IDBObjectStore* aObjectStore,
   210             IDBKeyRange* aKeyRange)
   211   : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
   212     mKeyRange(aKeyRange)
   213   {
   214     NS_ASSERTION(aKeyRange, "Null key range!");
   215   }
   217   ~GetHelper()
   218   {
   219     IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
   220   }
   222   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
   223                                   MOZ_OVERRIDE;
   225   virtual nsresult GetSuccessResult(JSContext* aCx,
   226                                     JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
   228   virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
   230   virtual nsresult
   231   PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
   233   virtual ChildProcessSendResult
   234   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   236   virtual nsresult
   237   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
   238                                   MOZ_OVERRIDE;
   240 protected:
   241   // In-params.
   242   nsRefPtr<IDBKeyRange> mKeyRange;
   244 private:
   245   // Out-params.
   246   StructuredCloneReadInfo mCloneReadInfo;
   247 };
   249 class DeleteHelper : public GetHelper
   250 {
   251 public:
   252   DeleteHelper(IDBTransaction* aTransaction,
   253                IDBRequest* aRequest,
   254                IDBObjectStore* aObjectStore,
   255                IDBKeyRange* aKeyRange)
   256   : GetHelper(aTransaction, aRequest, aObjectStore, aKeyRange)
   257   { }
   259   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
   260                                   MOZ_OVERRIDE;
   262   virtual nsresult GetSuccessResult(JSContext* aCx,
   263                                     JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
   265   virtual nsresult
   266   PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
   268   virtual ChildProcessSendResult
   269   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   271   virtual nsresult
   272   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
   273                                   MOZ_OVERRIDE;
   274 };
   276 class ClearHelper : public ObjectStoreHelper
   277 {
   278 public:
   279   ClearHelper(IDBTransaction* aTransaction,
   280               IDBRequest* aRequest,
   281               IDBObjectStore* aObjectStore)
   282   : ObjectStoreHelper(aTransaction, aRequest, aObjectStore)
   283   { }
   285   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
   286                                   MOZ_OVERRIDE;
   288   virtual nsresult
   289   PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
   291   virtual ChildProcessSendResult
   292   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   294   virtual nsresult
   295   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
   296                                   MOZ_OVERRIDE;
   297 };
   299 class OpenCursorHelper : public ObjectStoreHelper
   300 {
   301 public:
   302   OpenCursorHelper(IDBTransaction* aTransaction,
   303                    IDBRequest* aRequest,
   304                    IDBObjectStore* aObjectStore,
   305                    IDBKeyRange* aKeyRange,
   306                    IDBCursor::Direction aDirection)
   307   : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
   308     mKeyRange(aKeyRange), mDirection(aDirection)
   309   { }
   311   ~OpenCursorHelper()
   312   {
   313     IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
   314   }
   316   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
   317                                   MOZ_OVERRIDE;
   319   virtual nsresult GetSuccessResult(JSContext* aCx,
   320                                     JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
   322   virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
   324   virtual nsresult
   325   PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
   327   virtual ChildProcessSendResult
   328   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   330   virtual nsresult
   331   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
   332                                   MOZ_OVERRIDE;
   334 private:
   335   nsresult EnsureCursor();
   337   // In-params.
   338   nsRefPtr<IDBKeyRange> mKeyRange;
   339   const IDBCursor::Direction mDirection;
   341   // Out-params.
   342   Key mKey;
   343   StructuredCloneReadInfo mCloneReadInfo;
   344   nsCString mContinueQuery;
   345   nsCString mContinueToQuery;
   346   Key mRangeKey;
   348   // Only used in the parent process.
   349   nsRefPtr<IDBCursor> mCursor;
   350   SerializedStructuredCloneReadInfo mSerializedCloneReadInfo;
   351 };
   353 class OpenKeyCursorHelper MOZ_FINAL : public ObjectStoreHelper
   354 {
   355 public:
   356   OpenKeyCursorHelper(IDBTransaction* aTransaction,
   357                       IDBRequest* aRequest,
   358                       IDBObjectStore* aObjectStore,
   359                       IDBKeyRange* aKeyRange,
   360                       IDBCursor::Direction aDirection)
   361   : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
   362     mKeyRange(aKeyRange), mDirection(aDirection)
   363   { }
   365   virtual nsresult
   366   DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE;
   368   virtual nsresult
   369   GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
   370                    MOZ_OVERRIDE;
   372   virtual void
   373   ReleaseMainThreadObjects() MOZ_OVERRIDE;
   375   virtual nsresult
   376   PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
   378   virtual ChildProcessSendResult
   379   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   381   virtual nsresult
   382   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
   383                                   MOZ_OVERRIDE;
   385 private:
   386   ~OpenKeyCursorHelper()
   387   { }
   389   nsresult EnsureCursor();
   391   // In-params.
   392   nsRefPtr<IDBKeyRange> mKeyRange;
   393   const IDBCursor::Direction mDirection;
   395   // Out-params.
   396   Key mKey;
   397   nsCString mContinueQuery;
   398   nsCString mContinueToQuery;
   399   Key mRangeKey;
   401   // Only used in the parent process.
   402   nsRefPtr<IDBCursor> mCursor;
   403 };
   405 class CreateIndexHelper : public NoRequestObjectStoreHelper
   406 {
   407 public:
   408   CreateIndexHelper(IDBTransaction* aTransaction, IDBIndex* aIndex)
   409   : NoRequestObjectStoreHelper(aTransaction, aIndex->ObjectStore()),
   410     mIndex(aIndex)
   411   {
   412     if (sTLSIndex == BAD_TLS_INDEX) {
   413       PR_NewThreadPrivateIndex(&sTLSIndex, DestroyTLSEntry);
   414     }
   416     NS_ASSERTION(sTLSIndex != BAD_TLS_INDEX,
   417                  "PR_NewThreadPrivateIndex failed!");
   418   }
   420   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
   421                                   MOZ_OVERRIDE;
   423   virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
   425 private:
   426   nsresult InsertDataFromObjectStore(mozIStorageConnection* aConnection);
   428   static void DestroyTLSEntry(void* aPtr);
   430   static unsigned sTLSIndex;
   432   // In-params.
   433   nsRefPtr<IDBIndex> mIndex;
   434 };
   436 unsigned CreateIndexHelper::sTLSIndex = unsigned(BAD_TLS_INDEX);
   438 class DeleteIndexHelper : public NoRequestObjectStoreHelper
   439 {
   440 public:
   441   DeleteIndexHelper(IDBTransaction* aTransaction,
   442                     IDBObjectStore* aObjectStore,
   443                     const nsAString& aName)
   444   : NoRequestObjectStoreHelper(aTransaction, aObjectStore), mName(aName)
   445   { }
   447   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
   448                                   MOZ_OVERRIDE;
   450 private:
   451   // In-params
   452   nsString mName;
   453 };
   455 class GetAllHelper : public ObjectStoreHelper
   456 {
   457 public:
   458   GetAllHelper(IDBTransaction* aTransaction,
   459                IDBRequest* aRequest,
   460                IDBObjectStore* aObjectStore,
   461                IDBKeyRange* aKeyRange,
   462                const uint32_t aLimit)
   463   : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
   464     mKeyRange(aKeyRange), mLimit(aLimit)
   465   { }
   467   ~GetAllHelper()
   468   {
   469     for (uint32_t index = 0; index < mCloneReadInfos.Length(); index++) {
   470       IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos[index]);
   471     }
   472   }
   474   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
   475                                   MOZ_OVERRIDE;
   477   virtual nsresult GetSuccessResult(JSContext* aCx,
   478                                     JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
   480   virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
   482   virtual nsresult
   483   PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
   485   virtual ChildProcessSendResult
   486   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   488   virtual nsresult
   489   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
   490                                   MOZ_OVERRIDE;
   492 protected:
   493   // In-params.
   494   nsRefPtr<IDBKeyRange> mKeyRange;
   495   const uint32_t mLimit;
   497 private:
   498   // Out-params.
   499   nsTArray<StructuredCloneReadInfo> mCloneReadInfos;
   500 };
   502 class GetAllKeysHelper MOZ_FINAL : public ObjectStoreHelper
   503 {
   504 public:
   505   GetAllKeysHelper(IDBTransaction* aTransaction,
   506                    IDBRequest* aRequest,
   507                    IDBObjectStore* aObjectStore,
   508                    IDBKeyRange* aKeyRange,
   509                    const uint32_t aLimit)
   510   : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
   511     mKeyRange(aKeyRange), mLimit(aLimit)
   512   { }
   514   virtual nsresult
   515   DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE;
   517   virtual nsresult
   518   GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal)
   519                    MOZ_OVERRIDE;
   521   virtual void
   522   ReleaseMainThreadObjects() MOZ_OVERRIDE;
   524   virtual nsresult
   525   PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
   527   virtual ChildProcessSendResult
   528   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   530   virtual nsresult
   531   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
   532                                   MOZ_OVERRIDE;
   534 private:
   535   ~GetAllKeysHelper()
   536   { }
   538   nsRefPtr<IDBKeyRange> mKeyRange;
   539   const uint32_t mLimit;
   540   nsTArray<Key> mKeys;
   541 };
   543 class CountHelper : public ObjectStoreHelper
   544 {
   545 public:
   546   CountHelper(IDBTransaction* aTransaction,
   547               IDBRequest* aRequest,
   548               IDBObjectStore* aObjectStore,
   549               IDBKeyRange* aKeyRange)
   550   : ObjectStoreHelper(aTransaction, aRequest, aObjectStore),
   551     mKeyRange(aKeyRange), mCount(0)
   552   { }
   554   virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
   555                                   MOZ_OVERRIDE;
   557   virtual nsresult GetSuccessResult(JSContext* aCx,
   558                                     JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
   560   virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
   562   virtual nsresult
   563   PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE;
   565   virtual ChildProcessSendResult
   566   SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   568   virtual nsresult
   569   UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
   570                                   MOZ_OVERRIDE;
   572 private:
   573   nsRefPtr<IDBKeyRange> mKeyRange;
   574   uint64_t mCount;
   575 };
   577 class MOZ_STACK_CLASS AutoRemoveIndex
   578 {
   579 public:
   580   AutoRemoveIndex(ObjectStoreInfo* aObjectStoreInfo,
   581                   const nsAString& aIndexName)
   582   : mObjectStoreInfo(aObjectStoreInfo), mIndexName(aIndexName)
   583   { }
   585   ~AutoRemoveIndex()
   586   {
   587     if (mObjectStoreInfo) {
   588       for (uint32_t i = 0; i < mObjectStoreInfo->indexes.Length(); i++) {
   589         if (mObjectStoreInfo->indexes[i].name == mIndexName) {
   590           mObjectStoreInfo->indexes.RemoveElementAt(i);
   591           break;
   592         }
   593       }
   594     }
   595   }
   597   void forget()
   598   {
   599     mObjectStoreInfo = nullptr;
   600   }
   602 private:
   603   ObjectStoreInfo* mObjectStoreInfo;
   604   nsString mIndexName;
   605 };
   607 class ThreadLocalJSRuntime
   608 {
   609   JSRuntime* mRuntime;
   610   JSContext* mContext;
   611   JSObject* mGlobal;
   613   static const JSClass sGlobalClass;
   614   static const unsigned sRuntimeHeapSize = 768 * 1024;
   616   ThreadLocalJSRuntime()
   617   : mRuntime(nullptr), mContext(nullptr), mGlobal(nullptr)
   618   {
   619       MOZ_COUNT_CTOR(ThreadLocalJSRuntime);
   620   }
   622   nsresult Init()
   623   {
   624     mRuntime = JS_NewRuntime(sRuntimeHeapSize, JS_NO_HELPER_THREADS);
   625     NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY);
   627     /*
   628      * Not setting this will cause JS_CHECK_RECURSION to report false
   629      * positives
   630      */
   631     JS_SetNativeStackQuota(mRuntime, 128 * sizeof(size_t) * 1024); 
   633     mContext = JS_NewContext(mRuntime, 0);
   634     NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY);
   636     JSAutoRequest ar(mContext);
   638     mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr,
   639                                  JS::FireOnNewGlobalHook);
   640     NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY);
   642     js::SetDefaultObjectForContext(mContext, mGlobal);
   643     return NS_OK;
   644   }
   646  public:
   647   static ThreadLocalJSRuntime *Create()
   648   {
   649     ThreadLocalJSRuntime *entry = new ThreadLocalJSRuntime();
   650     NS_ENSURE_TRUE(entry, nullptr);
   652     if (NS_FAILED(entry->Init())) {
   653       delete entry;
   654       return nullptr;
   655     }
   657     return entry;
   658   }
   660   JSContext *Context() const
   661   {
   662     return mContext;
   663   }
   665   JSObject *Global() const
   666   {
   667     return mGlobal;
   668   }
   670   ~ThreadLocalJSRuntime()
   671   {
   672     MOZ_COUNT_DTOR(ThreadLocalJSRuntime);
   674     if (mContext) {
   675       JS_DestroyContext(mContext);
   676     }
   678     if (mRuntime) {
   679       JS_DestroyRuntime(mRuntime);
   680     }
   681   }
   682 };
   684 const JSClass ThreadLocalJSRuntime::sGlobalClass = {
   685   "IndexedDBTransactionThreadGlobal",
   686   JSCLASS_GLOBAL_FLAGS,
   687   JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub,
   688   JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub,
   689   nullptr, nullptr, nullptr, nullptr,
   690   JS_GlobalObjectTraceHook
   691 };
   693 inline
   694 already_AddRefed<IDBRequest>
   695 GenerateRequest(IDBObjectStore* aObjectStore)
   696 {
   697   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   698   IDBDatabase* database = aObjectStore->Transaction()->Database();
   699   return IDBRequest::Create(aObjectStore, database,
   700                             aObjectStore->Transaction());
   701 }
   703 struct MOZ_STACK_CLASS GetAddInfoClosure
   704 {
   705   IDBObjectStore* mThis;
   706   StructuredCloneWriteInfo& mCloneWriteInfo;
   707   JS::Handle<JS::Value> mValue;
   708 };
   710 nsresult
   711 GetAddInfoCallback(JSContext* aCx, void* aClosure)
   712 {
   713   GetAddInfoClosure* data = static_cast<GetAddInfoClosure*>(aClosure);
   715   data->mCloneWriteInfo.mOffsetToKeyProp = 0;
   716   data->mCloneWriteInfo.mTransaction = data->mThis->Transaction();
   718   if (!IDBObjectStore::SerializeValue(aCx, data->mCloneWriteInfo, data->mValue)) {
   719     return NS_ERROR_DOM_DATA_CLONE_ERR;
   720   }
   722   return NS_OK;
   723 }
   725 inline
   726 BlobChild*
   727 ActorFromRemoteBlob(nsIDOMBlob* aBlob)
   728 {
   729   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   730   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   732   nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob);
   733   if (remoteBlob) {
   734     BlobChild* actor =
   735       static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob()));
   736     NS_ASSERTION(actor, "Null actor?!");
   737     return actor;
   738   }
   739   return nullptr;
   740 }
   742 inline
   743 bool
   744 ResolveMysteryFile(nsIDOMBlob* aBlob, const nsString& aName,
   745                    const nsString& aContentType, uint64_t aSize,
   746                    uint64_t aLastModifiedDate)
   747 {
   748   BlobChild* actor = ActorFromRemoteBlob(aBlob);
   749   if (actor) {
   750     return actor->SetMysteryBlobInfo(aName, aContentType,
   751                                      aSize, aLastModifiedDate);
   752   }
   753   return true;
   754 }
   756 inline
   757 bool
   758 ResolveMysteryBlob(nsIDOMBlob* aBlob, const nsString& aContentType,
   759                    uint64_t aSize)
   760 {
   761   BlobChild* actor = ActorFromRemoteBlob(aBlob);
   762   if (actor) {
   763     return actor->SetMysteryBlobInfo(aContentType, aSize);
   764   }
   765   return true;
   766 }
   768 class MainThreadDeserializationTraits
   769 {
   770 public:
   771   static JSObject* CreateAndWrapFileHandle(JSContext* aCx,
   772                                            IDBDatabase* aDatabase,
   773                                            StructuredCloneFile& aFile,
   774                                            const FileHandleData& aData)
   775   {
   776     MOZ_ASSERT(NS_IsMainThread());
   778     nsRefPtr<FileInfo>& fileInfo = aFile.mFileInfo;
   780     nsRefPtr<IDBFileHandle> fileHandle = IDBFileHandle::Create(aDatabase,
   781       aData.name, aData.type, fileInfo.forget());
   783     return fileHandle->WrapObject(aCx);
   784   }
   786   static JSObject* CreateAndWrapBlobOrFile(JSContext* aCx,
   787                                            IDBDatabase* aDatabase,
   788                                            StructuredCloneFile& aFile,
   789                                            const BlobOrFileData& aData)
   790   {
   791     MOZ_ASSERT(NS_IsMainThread());
   793     MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
   794                aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
   795                aData.tag == SCTAG_DOM_BLOB);
   797     nsresult rv = NS_OK;
   799     nsRefPtr<FileInfo>& fileInfo = aFile.mFileInfo;
   801     nsCOMPtr<nsIFile> nativeFile;
   802     if (!aFile.mFile) {
   803       FileManager* fileManager = aDatabase->Manager();
   804         NS_ASSERTION(fileManager, "This should never be null!");
   806       nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
   807       if (!directory) {
   808         NS_WARNING("Failed to get directory!");
   809         return nullptr;
   810       }
   812       nativeFile = fileManager->GetFileForId(directory, fileInfo->Id());
   813       if (!nativeFile) {
   814         NS_WARNING("Failed to get file!");
   815         return nullptr;
   816       }
   817     }
   819     if (aData.tag == SCTAG_DOM_BLOB) {
   820       nsCOMPtr<nsIDOMBlob> domBlob;
   821       if (aFile.mFile) {
   822         if (!ResolveMysteryBlob(aFile.mFile, aData.type, aData.size)) {
   823           return nullptr;
   824         }
   825         domBlob = aFile.mFile;
   826       }
   827       else {
   828         domBlob = new nsDOMFileFile(aData.type, aData.size, nativeFile,
   829                                     fileInfo);
   830       }
   832       JS::Rooted<JS::Value> wrappedBlob(aCx);
   833       rv = nsContentUtils::WrapNative(aCx, domBlob, &NS_GET_IID(nsIDOMBlob),
   834                                       &wrappedBlob);
   835       if (NS_FAILED(rv)) {
   836         NS_WARNING("Failed to wrap native!");
   837         return nullptr;
   838       }
   840       return JSVAL_TO_OBJECT(wrappedBlob);
   841     }
   843     nsCOMPtr<nsIDOMFile> domFile;
   844     if (aFile.mFile) {
   845       if (!ResolveMysteryFile(aFile.mFile, aData.name, aData.type, aData.size,
   846                               aData.lastModifiedDate)) {
   847         return nullptr;
   848       }
   849       domFile = do_QueryInterface(aFile.mFile);
   850       NS_ASSERTION(domFile, "This should never fail!");
   851     }
   852     else {
   853       domFile = new nsDOMFileFile(aData.name, aData.type, aData.size,
   854                                   nativeFile, fileInfo);
   855     }
   857     JS::Rooted<JS::Value> wrappedFile(aCx);
   858     rv = nsContentUtils::WrapNative(aCx, domFile, &NS_GET_IID(nsIDOMFile),
   859                                     &wrappedFile);
   860     if (NS_FAILED(rv)) {
   861       NS_WARNING("Failed to wrap native!");
   862       return nullptr;
   863     }
   865     return JSVAL_TO_OBJECT(wrappedFile);
   866   }
   867 };
   870 class CreateIndexDeserializationTraits
   871 {
   872 public:
   873   static JSObject* CreateAndWrapFileHandle(JSContext* aCx,
   874                                            IDBDatabase* aDatabase,
   875                                            StructuredCloneFile& aFile,
   876                                            const FileHandleData& aData)
   877   {
   878     // FileHandle can't be used in index creation, so just make a dummy object.
   879     return JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr());
   880   }
   882   static JSObject* CreateAndWrapBlobOrFile(JSContext* aCx,
   883                                            IDBDatabase* aDatabase,
   884                                            StructuredCloneFile& aFile,
   885                                            const BlobOrFileData& aData)
   886   {
   887     MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE ||
   888                aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
   889                aData.tag == SCTAG_DOM_BLOB);
   891     // The following properties are available for use in index creation
   892     //   Blob.size
   893     //   Blob.type
   894     //   File.name
   895     //   File.lastModifiedDate
   897     JS::Rooted<JSObject*> obj(aCx,
   898       JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()));
   899     if (!obj) {
   900       NS_WARNING("Failed to create object!");
   901       return nullptr;
   902     }
   904     // Technically these props go on the proto, but this detail won't change
   905     // the results of index creation.
   907     JS::Rooted<JSString*> type(aCx,
   908       JS_NewUCStringCopyN(aCx, aData.type.get(), aData.type.Length()));
   909     if (!type ||
   910         !JS_DefineProperty(aCx, obj, "size", double(aData.size), 0) ||
   911         !JS_DefineProperty(aCx, obj, "type", type, 0)) {
   912       return nullptr;
   913     }
   915     if (aData.tag == SCTAG_DOM_BLOB) {
   916       return obj;
   917     }
   919     JS::Rooted<JSString*> name(aCx,
   920       JS_NewUCStringCopyN(aCx, aData.name.get(), aData.name.Length()));
   921     JS::Rooted<JSObject*> date(aCx,
   922       JS_NewDateObjectMsec(aCx, aData.lastModifiedDate));
   923     if (!name || !date ||
   924         !JS_DefineProperty(aCx, obj, "name", name, 0) ||
   925         !JS_DefineProperty(aCx, obj, "lastModifiedDate", date, 0)) {
   926       return nullptr;
   927     }
   929     return obj;
   930   }
   931 };
   933 } // anonymous namespace
   935 const JSClass IDBObjectStore::sDummyPropJSClass = {
   936   "dummy", 0,
   937   JS_PropertyStub,  JS_DeletePropertyStub,
   938   JS_PropertyStub,  JS_StrictPropertyStub,
   939   JS_EnumerateStub, JS_ResolveStub,
   940   JS_ConvertStub
   941 };
   943 // static
   944 already_AddRefed<IDBObjectStore>
   945 IDBObjectStore::Create(IDBTransaction* aTransaction,
   946                        ObjectStoreInfo* aStoreInfo,
   947                        const nsACString& aDatabaseId,
   948                        bool aCreating)
   949 {
   950   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   952   nsRefPtr<IDBObjectStore> objectStore = new IDBObjectStore();
   954   objectStore->mTransaction = aTransaction;
   955   objectStore->mName = aStoreInfo->name;
   956   objectStore->mId = aStoreInfo->id;
   957   objectStore->mKeyPath = aStoreInfo->keyPath;
   958   objectStore->mAutoIncrement = aStoreInfo->autoIncrement;
   959   objectStore->mDatabaseId = aDatabaseId;
   960   objectStore->mInfo = aStoreInfo;
   962   if (!IndexedDatabaseManager::IsMainProcess()) {
   963     IndexedDBTransactionChild* transactionActor = aTransaction->GetActorChild();
   964     NS_ASSERTION(transactionActor, "Must have an actor here!");
   966     ObjectStoreConstructorParams params;
   968     if (aCreating) {
   969       CreateObjectStoreParams createParams;
   970       createParams.info() = *aStoreInfo;
   971       params = createParams;
   972     }
   973     else {
   974       GetObjectStoreParams getParams;
   975       getParams.name() = aStoreInfo->name;
   976       params = getParams;
   977     }
   979     IndexedDBObjectStoreChild* actor =
   980       new IndexedDBObjectStoreChild(objectStore);
   982     transactionActor->SendPIndexedDBObjectStoreConstructor(actor, params);
   983   }
   985   return objectStore.forget();
   986 }
   988 // static
   989 nsresult
   990 IDBObjectStore::AppendIndexUpdateInfo(
   991                                     int64_t aIndexID,
   992                                     const KeyPath& aKeyPath,
   993                                     bool aUnique,
   994                                     bool aMultiEntry,
   995                                     JSContext* aCx,
   996                                     JS::Handle<JS::Value> aVal,
   997                                     nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
   998 {
   999   nsresult rv;
  1001   if (!aMultiEntry) {
  1002     Key key;
  1003     rv = aKeyPath.ExtractKey(aCx, aVal, key);
  1005     // If an index's keypath doesn't match an object, we ignore that object.
  1006     if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) {
  1007       return NS_OK;
  1010     if (NS_FAILED(rv)) {
  1011       return rv;
  1014     IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
  1015     updateInfo->indexId = aIndexID;
  1016     updateInfo->indexUnique = aUnique;
  1017     updateInfo->value = key;
  1019     return NS_OK;
  1022   JS::Rooted<JS::Value> val(aCx);
  1023   if (NS_FAILED(aKeyPath.ExtractKeyAsJSVal(aCx, aVal, val.address()))) {
  1024     return NS_OK;
  1027   if (JS_IsArrayObject(aCx, val)) {
  1028     JS::Rooted<JSObject*> array(aCx, &val.toObject());
  1029     uint32_t arrayLength;
  1030     if (!JS_GetArrayLength(aCx, array, &arrayLength)) {
  1031       IDB_REPORT_INTERNAL_ERR();
  1032       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1035     for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) {
  1036       JS::Rooted<JS::Value> arrayItem(aCx);
  1037       if (!JS_GetElement(aCx, array, arrayIndex, &arrayItem)) {
  1038         IDB_REPORT_INTERNAL_ERR();
  1039         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1042       Key value;
  1043       if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) ||
  1044           value.IsUnset()) {
  1045         // Not a value we can do anything with, ignore it.
  1046         continue;
  1049       IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
  1050       updateInfo->indexId = aIndexID;
  1051       updateInfo->indexUnique = aUnique;
  1052       updateInfo->value = value;
  1055   else {
  1056     Key value;
  1057     if (NS_FAILED(value.SetFromJSVal(aCx, val)) ||
  1058         value.IsUnset()) {
  1059       // Not a value we can do anything with, ignore it.
  1060       return NS_OK;
  1063     IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement();
  1064     updateInfo->indexId = aIndexID;
  1065     updateInfo->indexUnique = aUnique;
  1066     updateInfo->value = value;
  1069   return NS_OK;
  1072 // static
  1073 nsresult
  1074 IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction,
  1075                               int64_t aObjectStoreId,
  1076                               const Key& aObjectStoreKey,
  1077                               bool aOverwrite,
  1078                               int64_t aObjectDataId,
  1079                               const nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
  1081   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  1082   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1084   PROFILER_LABEL("IndexedDB", "IDBObjectStore::UpdateIndexes");
  1086   nsresult rv;
  1088   NS_ASSERTION(aObjectDataId != INT64_MIN, "Bad objectData id!");
  1090   NS_NAMED_LITERAL_CSTRING(objectDataId, "object_data_id");
  1092   if (aOverwrite) {
  1093     nsCOMPtr<mozIStorageStatement> deleteStmt =
  1094       aTransaction->GetCachedStatement(
  1095         "DELETE FROM unique_index_data "
  1096         "WHERE object_data_id = :object_data_id; "
  1097         "DELETE FROM index_data "
  1098         "WHERE object_data_id = :object_data_id");
  1099     NS_ENSURE_TRUE(deleteStmt, NS_ERROR_FAILURE);
  1101     mozStorageStatementScoper scoper(deleteStmt);
  1103     rv = deleteStmt->BindInt64ByName(objectDataId, aObjectDataId);
  1104     NS_ENSURE_SUCCESS(rv, rv);
  1106     rv = deleteStmt->Execute();
  1107     NS_ENSURE_SUCCESS(rv, rv);
  1110   // Avoid lots of hash lookups for objectStores with lots of indexes by lazily
  1111   // holding the necessary statements on the stack outside the loop.
  1112   nsCOMPtr<mozIStorageStatement> insertUniqueStmt;
  1113   nsCOMPtr<mozIStorageStatement> insertStmt;
  1115   uint32_t infoCount = aUpdateInfoArray.Length();
  1116   for (uint32_t i = 0; i < infoCount; i++) {
  1117     const IndexUpdateInfo& updateInfo = aUpdateInfoArray[i];
  1119     nsCOMPtr<mozIStorageStatement>& stmt =
  1120       updateInfo.indexUnique ? insertUniqueStmt : insertStmt;
  1122     if (!stmt) {
  1123       stmt = updateInfo.indexUnique ?
  1124         aTransaction->GetCachedStatement(
  1125           "INSERT INTO unique_index_data "
  1126             "(index_id, object_data_id, object_data_key, value) "
  1127           "VALUES (:index_id, :object_data_id, :object_data_key, :value)") :
  1128         aTransaction->GetCachedStatement(
  1129           "INSERT OR IGNORE INTO index_data ("
  1130             "index_id, object_data_id, object_data_key, value) "
  1131           "VALUES (:index_id, :object_data_id, :object_data_key, :value)");
  1133     NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE);
  1135     mozStorageStatementScoper scoper(stmt);
  1137     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
  1138                                updateInfo.indexId);
  1139     NS_ENSURE_SUCCESS(rv, rv);
  1141     rv = stmt->BindInt64ByName(objectDataId, aObjectDataId);
  1142     NS_ENSURE_SUCCESS(rv, rv);
  1144     rv = aObjectStoreKey.BindToStatement(stmt,
  1145                                          NS_LITERAL_CSTRING("object_data_key"));
  1146     NS_ENSURE_SUCCESS(rv, rv);
  1148     rv = updateInfo.value.BindToStatement(stmt, NS_LITERAL_CSTRING("value"));
  1149     NS_ENSURE_SUCCESS(rv, rv);
  1151     rv = stmt->Execute();
  1152     if (rv == NS_ERROR_STORAGE_CONSTRAINT && updateInfo.indexUnique) {
  1153       // If we're inserting multiple entries for the same unique index, then
  1154       // we might have failed to insert due to colliding with another entry for
  1155       // the same index in which case we should ignore it.
  1157       for (int32_t j = (int32_t)i - 1;
  1158            j >= 0 && aUpdateInfoArray[j].indexId == updateInfo.indexId;
  1159            --j) {
  1160         if (updateInfo.value == aUpdateInfoArray[j].value) {
  1161           // We found a key with the same value for the same index. So we
  1162           // must have had a collision with a value we just inserted.
  1163           rv = NS_OK;
  1164           break;
  1169     if (NS_FAILED(rv)) {
  1170       return rv;
  1174   return NS_OK;
  1177 // static
  1178 nsresult
  1179 IDBObjectStore::GetStructuredCloneReadInfoFromStatement(
  1180                                            mozIStorageStatement* aStatement,
  1181                                            uint32_t aDataIndex,
  1182                                            uint32_t aFileIdsIndex,
  1183                                            IDBDatabase* aDatabase,
  1184                                            StructuredCloneReadInfo& aInfo)
  1186   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  1187   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1189   PROFILER_LABEL("IndexedDB",
  1190                  "IDBObjectStore::GetStructuredCloneReadInfoFromStatement");
  1192 #ifdef DEBUG
  1194     int32_t type;
  1195     NS_ASSERTION(NS_SUCCEEDED(aStatement->GetTypeOfIndex(aDataIndex, &type)) &&
  1196                  type == mozIStorageStatement::VALUE_TYPE_BLOB,
  1197                  "Bad value type!");
  1199 #endif
  1201   const uint8_t* blobData;
  1202   uint32_t blobDataLength;
  1203   nsresult rv = aStatement->GetSharedBlob(aDataIndex, &blobDataLength,
  1204                                           &blobData);
  1205   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1207   const char* compressed = reinterpret_cast<const char*>(blobData);
  1208   size_t compressedLength = size_t(blobDataLength);
  1210   static const fallible_t fallible = fallible_t();
  1212   size_t uncompressedLength;
  1213   if (!snappy::GetUncompressedLength(compressed, compressedLength,
  1214                                      &uncompressedLength)) {
  1215     IDB_WARNING("Snappy can't determine uncompressed length!");
  1216     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1219   nsAutoArrayPtr<char> uncompressed(new (fallible) char[uncompressedLength]);
  1220   NS_ENSURE_TRUE(uncompressed, NS_ERROR_OUT_OF_MEMORY);
  1222   if (!snappy::RawUncompress(compressed, compressedLength,
  1223                              uncompressed.get())) {
  1224     IDB_WARNING("Snappy can't determine uncompressed length!");
  1225     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1228   JSAutoStructuredCloneBuffer& buffer = aInfo.mCloneBuffer;
  1229   if (!buffer.copy(reinterpret_cast<const uint64_t *>(uncompressed.get()),
  1230                    uncompressedLength)) {
  1231     IDB_REPORT_INTERNAL_ERR();
  1232     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1235   bool isNull;
  1236   rv = aStatement->GetIsNull(aFileIdsIndex, &isNull);
  1237   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1239   if (!isNull) {
  1240     nsString ids;
  1241     rv = aStatement->GetString(aFileIdsIndex, ids);
  1242     IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1244     nsAutoTArray<int64_t, 10> array;
  1245     rv = ConvertFileIdsToArray(ids, array);
  1246     IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1248     FileManager* fileManager = aDatabase->Manager();
  1250     for (uint32_t i = 0; i < array.Length(); i++) {
  1251       const int64_t& id = array[i];
  1253       nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(id);
  1254       NS_ASSERTION(fileInfo, "Null file info!");
  1256       StructuredCloneFile* file = aInfo.mFiles.AppendElement();
  1257       file->mFileInfo.swap(fileInfo);
  1261   aInfo.mDatabase = aDatabase;
  1263   return NS_OK;
  1266 // static
  1267 void
  1268 IDBObjectStore::ClearCloneWriteInfo(StructuredCloneWriteInfo& aWriteInfo)
  1270   // This is kind of tricky, we only want to release stuff on the main thread,
  1271   // but we can end up being called on other threads if we have already been
  1272   // cleared on the main thread.
  1273   if (!aWriteInfo.mCloneBuffer.data() && !aWriteInfo.mFiles.Length()) {
  1274     return;
  1277   // If there's something to clear, we should be on the main thread.
  1278   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1280   ClearStructuredCloneBuffer(aWriteInfo.mCloneBuffer);
  1281   aWriteInfo.mFiles.Clear();
  1284 // static
  1285 void
  1286 IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo)
  1288   // This is kind of tricky, we only want to release stuff on the main thread,
  1289   // but we can end up being called on other threads if we have already been
  1290   // cleared on the main thread.
  1291   if (!aReadInfo.mCloneBuffer.data() && !aReadInfo.mFiles.Length()) {
  1292     return;
  1295   // If there's something to clear, we should be on the main thread.
  1296   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1298   ClearStructuredCloneBuffer(aReadInfo.mCloneBuffer);
  1299   aReadInfo.mFiles.Clear();
  1302 // static
  1303 void
  1304 IDBObjectStore::ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer)
  1306   if (aBuffer.data()) {
  1307     aBuffer.clear();
  1311 // static
  1312 bool
  1313 IDBObjectStore::DeserializeValue(JSContext* aCx,
  1314                                  StructuredCloneReadInfo& aCloneReadInfo,
  1315                                  JS::MutableHandle<JS::Value> aValue)
  1317   NS_ASSERTION(NS_IsMainThread(),
  1318                "Should only be deserializing on the main thread!");
  1319   NS_ASSERTION(aCx, "A JSContext is required!");
  1321   JSAutoStructuredCloneBuffer& buffer = aCloneReadInfo.mCloneBuffer;
  1323   if (!buffer.data()) {
  1324     aValue.setUndefined();
  1325     return true;
  1328   JSAutoRequest ar(aCx);
  1330   JSStructuredCloneCallbacks callbacks = {
  1331     IDBObjectStore::StructuredCloneReadCallback<MainThreadDeserializationTraits>,
  1332     nullptr,
  1333     nullptr,
  1334     nullptr,
  1335     nullptr,
  1336     nullptr
  1337   };
  1339   return buffer.read(aCx, aValue, &callbacks, &aCloneReadInfo);
  1342 // static
  1343 bool
  1344 IDBObjectStore::SerializeValue(JSContext* aCx,
  1345                                StructuredCloneWriteInfo& aCloneWriteInfo,
  1346                                JS::Handle<JS::Value> aValue)
  1348   NS_ASSERTION(NS_IsMainThread(),
  1349                "Should only be serializing on the main thread!");
  1350   NS_ASSERTION(aCx, "A JSContext is required!");
  1352   JSAutoRequest ar(aCx);
  1354   JSStructuredCloneCallbacks callbacks = {
  1355     nullptr,
  1356     StructuredCloneWriteCallback,
  1357     nullptr,
  1358     nullptr,
  1359     nullptr,
  1360     nullptr
  1361   };
  1363   JSAutoStructuredCloneBuffer& buffer = aCloneWriteInfo.mCloneBuffer;
  1365   return buffer.write(aCx, aValue, &callbacks, &aCloneWriteInfo);
  1368 static inline bool
  1369 StructuredCloneReadString(JSStructuredCloneReader* aReader,
  1370                           nsCString& aString)
  1372   uint32_t length;
  1373   if (!JS_ReadBytes(aReader, &length, sizeof(uint32_t))) {
  1374     NS_WARNING("Failed to read length!");
  1375     return false;
  1377   length = NativeEndian::swapFromLittleEndian(length);
  1379   if (!aString.SetLength(length, fallible_t())) {
  1380     NS_WARNING("Out of memory?");
  1381     return false;
  1383   char* buffer = aString.BeginWriting();
  1385   if (!JS_ReadBytes(aReader, buffer, length)) {
  1386     NS_WARNING("Failed to read type!");
  1387     return false;
  1390   return true;
  1393 // static
  1394 bool
  1395 IDBObjectStore::ReadFileHandle(JSStructuredCloneReader* aReader,
  1396                                FileHandleData* aRetval)
  1398   static_assert(SCTAG_DOM_FILEHANDLE == 0xFFFF8004,
  1399                 "Update me!");
  1400   MOZ_ASSERT(aReader && aRetval);
  1402   nsCString type;
  1403   if (!StructuredCloneReadString(aReader, type)) {
  1404     return false;
  1406   CopyUTF8toUTF16(type, aRetval->type);
  1408   nsCString name;
  1409   if (!StructuredCloneReadString(aReader, name)) {
  1410     return false;
  1412   CopyUTF8toUTF16(name, aRetval->name);
  1414   return true;
  1417 // static
  1418 bool
  1419 IDBObjectStore::ReadBlobOrFile(JSStructuredCloneReader* aReader,
  1420                                uint32_t aTag,
  1421                                BlobOrFileData* aRetval)
  1423   static_assert(SCTAG_DOM_BLOB == 0xFFFF8001 &&
  1424                 SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xFFFF8002 &&
  1425                 SCTAG_DOM_FILE == 0xFFFF8005,
  1426                 "Update me!");
  1427   MOZ_ASSERT(aReader && aRetval);
  1428   MOZ_ASSERT(aTag == SCTAG_DOM_FILE ||
  1429              aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
  1430              aTag == SCTAG_DOM_BLOB);
  1432   aRetval->tag = aTag;
  1434   // If it's not a FileHandle, it's a Blob or a File.
  1435   uint64_t size;
  1436   if (!JS_ReadBytes(aReader, &size, sizeof(uint64_t))) {
  1437     NS_WARNING("Failed to read size!");
  1438     return false;
  1440   aRetval->size = NativeEndian::swapFromLittleEndian(size);
  1442   nsCString type;
  1443   if (!StructuredCloneReadString(aReader, type)) {
  1444     return false;
  1446   CopyUTF8toUTF16(type, aRetval->type);
  1448   // Blobs are done.
  1449   if (aTag == SCTAG_DOM_BLOB) {
  1450     return true;
  1453   NS_ASSERTION(aTag == SCTAG_DOM_FILE ||
  1454                aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE, "Huh?!");
  1456   uint64_t lastModifiedDate;
  1457   if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE) {
  1458     lastModifiedDate = UINT64_MAX;
  1460   else {
  1461     if(!JS_ReadBytes(aReader, &lastModifiedDate, sizeof(lastModifiedDate))) {
  1462       NS_WARNING("Failed to read lastModifiedDate");
  1463       return false;
  1465     lastModifiedDate = NativeEndian::swapFromLittleEndian(lastModifiedDate);
  1467   aRetval->lastModifiedDate = lastModifiedDate;
  1469   nsCString name;
  1470   if (!StructuredCloneReadString(aReader, name)) {
  1471     return false;
  1473   CopyUTF8toUTF16(name, aRetval->name);
  1475   return true;
  1478 // static
  1479 template <class DeserializationTraits>
  1480 JSObject*
  1481 IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx,
  1482                                             JSStructuredCloneReader* aReader,
  1483                                             uint32_t aTag,
  1484                                             uint32_t aData,
  1485                                             void* aClosure)
  1487   // We need to statically assert that our tag values are what we expect
  1488   // so that if people accidentally change them they notice.
  1489   static_assert(SCTAG_DOM_BLOB == 0xFFFF8001 &&
  1490                 SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xFFFF8002 &&
  1491                 SCTAG_DOM_FILEHANDLE == 0xFFFF8004 &&
  1492                 SCTAG_DOM_FILE == 0xFFFF8005,
  1493                 "You changed our structured clone tag values and just ate "
  1494                 "everyone's IndexedDB data.  I hope you are happy.");
  1496   if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE ||
  1497       aTag == SCTAG_DOM_FILEHANDLE ||
  1498       aTag == SCTAG_DOM_BLOB ||
  1499       aTag == SCTAG_DOM_FILE) {
  1500     StructuredCloneReadInfo* cloneReadInfo =
  1501       reinterpret_cast<StructuredCloneReadInfo*>(aClosure);
  1503     if (aData >= cloneReadInfo->mFiles.Length()) {
  1504       NS_ERROR("Bad blob index!");
  1505       return nullptr;
  1508     StructuredCloneFile& file = cloneReadInfo->mFiles[aData];
  1509     IDBDatabase* database = cloneReadInfo->mDatabase;
  1511     if (aTag == SCTAG_DOM_FILEHANDLE) {
  1512       FileHandleData data;
  1513       if (!ReadFileHandle(aReader, &data)) {
  1514         return nullptr;
  1517       return DeserializationTraits::CreateAndWrapFileHandle(aCx, database,
  1518                                                             file, data);
  1521     BlobOrFileData data;
  1522     if (!ReadBlobOrFile(aReader, aTag, &data)) {
  1523       return nullptr;
  1526     return DeserializationTraits::CreateAndWrapBlobOrFile(aCx, database,
  1527                                                           file, data);
  1530   const JSStructuredCloneCallbacks* runtimeCallbacks =
  1531     js::GetContextStructuredCloneCallbacks(aCx);
  1533   if (runtimeCallbacks) {
  1534     return runtimeCallbacks->read(aCx, aReader, aTag, aData, nullptr);
  1537   return nullptr;
  1540 // static
  1541 bool
  1542 IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx,
  1543                                              JSStructuredCloneWriter* aWriter,
  1544                                              JS::Handle<JSObject*> aObj,
  1545                                              void* aClosure)
  1547   StructuredCloneWriteInfo* cloneWriteInfo =
  1548     reinterpret_cast<StructuredCloneWriteInfo*>(aClosure);
  1550   if (JS_GetClass(aObj) == &sDummyPropJSClass) {
  1551     NS_ASSERTION(cloneWriteInfo->mOffsetToKeyProp == 0,
  1552                  "We should not have been here before!");
  1553     cloneWriteInfo->mOffsetToKeyProp = js_GetSCOffset(aWriter);
  1555     uint64_t value = 0;
  1556     // Omit endian swap
  1557     return JS_WriteBytes(aWriter, &value, sizeof(value));
  1560   IDBTransaction* transaction = cloneWriteInfo->mTransaction;
  1561   FileManager* fileManager = transaction->Database()->Manager();
  1563   file::FileHandle* fileHandle = nullptr;
  1564   if (NS_SUCCEEDED(UNWRAP_OBJECT(FileHandle, aObj, fileHandle))) {
  1565     nsRefPtr<FileInfo> fileInfo = fileHandle->GetFileInfo();
  1567     // Throw when trying to store non IDB file handles or IDB file handles
  1568     // across databases.
  1569     if (!fileInfo || fileInfo->Manager() != fileManager) {
  1570       return false;
  1573     NS_ConvertUTF16toUTF8 convType(fileHandle->Type());
  1574     uint32_t convTypeLength =
  1575       NativeEndian::swapToLittleEndian(convType.Length());
  1577     NS_ConvertUTF16toUTF8 convName(fileHandle->Name());
  1578     uint32_t convNameLength =
  1579       NativeEndian::swapToLittleEndian(convName.Length());
  1581     if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILEHANDLE,
  1582                             cloneWriteInfo->mFiles.Length()) ||
  1583         !JS_WriteBytes(aWriter, &convTypeLength, sizeof(uint32_t)) ||
  1584         !JS_WriteBytes(aWriter, convType.get(), convType.Length()) ||
  1585         !JS_WriteBytes(aWriter, &convNameLength, sizeof(uint32_t)) ||
  1586         !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
  1587       return false;
  1590     StructuredCloneFile* file = cloneWriteInfo->mFiles.AppendElement();
  1591     file->mFileInfo = fileInfo.forget();
  1593     return true;
  1596   nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative;
  1597   nsContentUtils::XPConnect()->
  1598     GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative));
  1600   if (wrappedNative) {
  1601     nsISupports* supports = wrappedNative->Native();
  1603     nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports);
  1604     if (blob) {
  1605       nsCOMPtr<nsIInputStream> inputStream;
  1607       // Check if it is a blob created from this db or the blob was already
  1608       // stored in this db
  1609       nsRefPtr<FileInfo> fileInfo = transaction->GetFileInfo(blob);
  1610       if (!fileInfo && fileManager) {
  1611         fileInfo = blob->GetFileInfo(fileManager);
  1613         if (!fileInfo) {
  1614           fileInfo = fileManager->GetNewFileInfo();
  1615           if (!fileInfo) {
  1616             NS_WARNING("Failed to get new file info!");
  1617             return false;
  1620           if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
  1621             NS_WARNING("Failed to get internal steam!");
  1622             return false;
  1625           transaction->AddFileInfo(blob, fileInfo);
  1629       uint64_t size;
  1630       if (NS_FAILED(blob->GetSize(&size))) {
  1631         NS_WARNING("Failed to get size!");
  1632         return false;
  1634       size = NativeEndian::swapToLittleEndian(size);
  1636       nsString type;
  1637       if (NS_FAILED(blob->GetType(type))) {
  1638         NS_WARNING("Failed to get type!");
  1639         return false;
  1641       NS_ConvertUTF16toUTF8 convType(type);
  1642       uint32_t convTypeLength =
  1643         NativeEndian::swapToLittleEndian(convType.Length());
  1645       nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob);
  1647       if (!JS_WriteUint32Pair(aWriter, file ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB,
  1648                               cloneWriteInfo->mFiles.Length()) ||
  1649           !JS_WriteBytes(aWriter, &size, sizeof(size)) ||
  1650           !JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) ||
  1651           !JS_WriteBytes(aWriter, convType.get(), convType.Length())) {
  1652         return false;
  1655       if (file) {
  1656         uint64_t lastModifiedDate = 0;
  1657         if (NS_FAILED(file->GetMozLastModifiedDate(&lastModifiedDate))) {
  1658           NS_WARNING("Failed to get last modified date!");
  1659           return false;
  1662         lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate);
  1664         nsString name;
  1665         if (NS_FAILED(file->GetName(name))) {
  1666           NS_WARNING("Failed to get name!");
  1667           return false;
  1669         NS_ConvertUTF16toUTF8 convName(name);
  1670         uint32_t convNameLength =
  1671           NativeEndian::swapToLittleEndian(convName.Length());
  1673         if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) || 
  1674             !JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) ||
  1675             !JS_WriteBytes(aWriter, convName.get(), convName.Length())) {
  1676           return false;
  1680       StructuredCloneFile* cloneFile = cloneWriteInfo->mFiles.AppendElement();
  1681       cloneFile->mFile = blob.forget();
  1682       cloneFile->mFileInfo = fileInfo.forget();
  1683       cloneFile->mInputStream = inputStream.forget();
  1685       return true;
  1689   // try using the runtime callbacks
  1690   const JSStructuredCloneCallbacks* runtimeCallbacks =
  1691     js::GetContextStructuredCloneCallbacks(aCx);
  1692   if (runtimeCallbacks) {
  1693     return runtimeCallbacks->write(aCx, aWriter, aObj, nullptr);
  1696   return false;
  1699 // static
  1700 nsresult
  1701 IDBObjectStore::ConvertFileIdsToArray(const nsAString& aFileIds,
  1702                                       nsTArray<int64_t>& aResult)
  1704   nsCharSeparatedTokenizerTemplate<IgnoreNothing> tokenizer(aFileIds, ' ');
  1706   while (tokenizer.hasMoreTokens()) {
  1707     nsString token(tokenizer.nextToken());
  1709     NS_ASSERTION(!token.IsEmpty(), "Should be a valid id!");
  1711     nsresult rv;
  1712     int32_t id = token.ToInteger(&rv);
  1713     NS_ENSURE_SUCCESS(rv, rv);
  1715     int64_t* element = aResult.AppendElement();
  1716     *element = id;
  1719   return NS_OK;
  1722 // static
  1723 void
  1724 IDBObjectStore::ConvertActorsToBlobs(
  1725                                    const InfallibleTArray<PBlobChild*>& aActors,
  1726                                    nsTArray<StructuredCloneFile>& aFiles)
  1728   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1729   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1730   NS_ASSERTION(aFiles.IsEmpty(), "Should be empty!");
  1732   if (!aActors.IsEmpty()) {
  1733     NS_ASSERTION(ContentChild::GetSingleton(), "This should never be null!");
  1735     uint32_t length = aActors.Length();
  1736     aFiles.SetCapacity(length);
  1738     for (uint32_t index = 0; index < length; index++) {
  1739       BlobChild* actor = static_cast<BlobChild*>(aActors[index]);
  1741       StructuredCloneFile* file = aFiles.AppendElement();
  1742       file->mFile = actor->GetBlob();
  1747 // static
  1748 nsresult
  1749 IDBObjectStore::ConvertBlobsToActors(
  1750                                     ContentParent* aContentParent,
  1751                                     FileManager* aFileManager,
  1752                                     const nsTArray<StructuredCloneFile>& aFiles,
  1753                                     InfallibleTArray<PBlobParent*>& aActors)
  1755   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1756   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1757   NS_ASSERTION(aContentParent, "Null contentParent!");
  1758   NS_ASSERTION(aFileManager, "Null file manager!");
  1760   if (!aFiles.IsEmpty()) {
  1761     nsCOMPtr<nsIFile> directory = aFileManager->GetDirectory();
  1762     if (!directory) {
  1763       IDB_WARNING("Failed to get directory!");
  1764       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1767     uint32_t fileCount = aFiles.Length();
  1768     aActors.SetCapacity(fileCount);
  1770     for (uint32_t index = 0; index < fileCount; index++) {
  1771       const StructuredCloneFile& file = aFiles[index];
  1772       NS_ASSERTION(file.mFileInfo, "This should never be null!");
  1774       nsCOMPtr<nsIFile> nativeFile =
  1775         aFileManager->GetFileForId(directory, file.mFileInfo->Id());
  1776       if (!nativeFile) {
  1777         IDB_WARNING("Failed to get file!");
  1778         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1781       nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(nativeFile, file.mFileInfo);
  1783       BlobParent* actor =
  1784         aContentParent->GetOrCreateActorForBlob(blob);
  1785       if (!actor) {
  1786         // This can only fail if the child has crashed.
  1787         IDB_REPORT_INTERNAL_ERR();
  1788         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1791       aActors.AppendElement(actor);
  1795   return NS_OK;
  1798 IDBObjectStore::IDBObjectStore()
  1799 : mId(INT64_MIN),
  1800   mKeyPath(0),
  1801   mCachedKeyPath(JSVAL_VOID),
  1802   mRooted(false),
  1803   mAutoIncrement(false),
  1804   mActorChild(nullptr),
  1805   mActorParent(nullptr)
  1807   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1809   SetIsDOMBinding();
  1812 IDBObjectStore::~IDBObjectStore()
  1814   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1815   NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
  1816   if (mActorChild) {
  1817     NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1818     mActorChild->Send__delete__(mActorChild);
  1819     NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
  1822   if (mRooted) {
  1823     mCachedKeyPath = JSVAL_VOID;
  1824     mozilla::DropJSObjects(this);
  1828 nsresult
  1829 IDBObjectStore::GetAddInfo(JSContext* aCx,
  1830                            JS::Handle<JS::Value> aValue,
  1831                            JS::Handle<JS::Value> aKeyVal,
  1832                            StructuredCloneWriteInfo& aCloneWriteInfo,
  1833                            Key& aKey,
  1834                            nsTArray<IndexUpdateInfo>& aUpdateInfoArray)
  1836   nsresult rv;
  1838   // Return DATA_ERR if a key was passed in and this objectStore uses inline
  1839   // keys.
  1840   if (!JSVAL_IS_VOID(aKeyVal) && HasValidKeyPath()) {
  1841     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
  1844   JSAutoRequest ar(aCx);
  1846   if (!HasValidKeyPath()) {
  1847     // Out-of-line keys must be passed in.
  1848     rv = aKey.SetFromJSVal(aCx, aKeyVal);
  1849     if (NS_FAILED(rv)) {
  1850       return rv;
  1853   else if (!mAutoIncrement) {
  1854     rv = GetKeyPath().ExtractKey(aCx, aValue, aKey);
  1855     if (NS_FAILED(rv)) {
  1856       return rv;
  1860   // Return DATA_ERR if no key was specified this isn't an autoIncrement
  1861   // objectStore.
  1862   if (aKey.IsUnset() && !mAutoIncrement) {
  1863     return NS_ERROR_DOM_INDEXEDDB_DATA_ERR;
  1866   // Figure out indexes and the index values to update here.
  1867   uint32_t count = mInfo->indexes.Length();
  1868   aUpdateInfoArray.SetCapacity(count); // Pretty good estimate
  1869   for (uint32_t indexesIndex = 0; indexesIndex < count; indexesIndex++) {
  1870     const IndexInfo& indexInfo = mInfo->indexes[indexesIndex];
  1872     rv = AppendIndexUpdateInfo(indexInfo.id, indexInfo.keyPath,
  1873                                indexInfo.unique, indexInfo.multiEntry, aCx,
  1874                                aValue, aUpdateInfoArray);
  1875     NS_ENSURE_SUCCESS(rv, rv);
  1878   GetAddInfoClosure data = {this, aCloneWriteInfo, aValue};
  1880   if (mAutoIncrement && HasValidKeyPath()) {
  1881     NS_ASSERTION(aKey.IsUnset(), "Shouldn't have gotten the key yet!");
  1883     rv = GetKeyPath().ExtractOrCreateKey(aCx, aValue, aKey,
  1884                                          &GetAddInfoCallback, &data);
  1886   else {
  1887     rv = GetAddInfoCallback(aCx, &data);
  1890   return rv;
  1893 already_AddRefed<IDBRequest>
  1894 IDBObjectStore::AddOrPut(JSContext* aCx, JS::Handle<JS::Value> aValue,
  1895                          JS::Handle<JS::Value> aKey,
  1896                          bool aOverwrite, ErrorResult& aRv)
  1898   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1900   if (!mTransaction->IsOpen()) {
  1901     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  1902     return nullptr;
  1905   if (!IsWriteAllowed()) {
  1906     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
  1907     return nullptr;
  1910   StructuredCloneWriteInfo cloneWriteInfo;
  1911   Key key;
  1912   nsTArray<IndexUpdateInfo> updateInfo;
  1914   JS::Rooted<JS::Value> value(aCx, aValue);
  1915   aRv = GetAddInfo(aCx, value, aKey, cloneWriteInfo, key, updateInfo);
  1916   if (aRv.Failed()) {
  1917     return nullptr;
  1920   nsRefPtr<IDBRequest> request = GenerateRequest(this);
  1921   if (!request) {
  1922     IDB_WARNING("Failed to generate request!");
  1923     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1924     return nullptr;
  1927   nsRefPtr<AddHelper> helper =
  1928     new AddHelper(mTransaction, request, this, Move(cloneWriteInfo), key,
  1929                   aOverwrite, updateInfo);
  1931   nsresult rv = helper->DispatchToTransactionPool();
  1932   if (NS_FAILED(rv)) {
  1933     IDB_WARNING("Failed to dispatch!");
  1934     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1935     return nullptr;
  1938 #ifdef IDB_PROFILER_USE_MARKS
  1939   if (aOverwrite) {
  1940     IDB_PROFILER_MARK("IndexedDB Request %llu: "
  1941                       "database(%s).transaction(%s).objectStore(%s).%s(%s)",
  1942                       "IDBRequest[%llu] MT IDBObjectStore.put()",
  1943                       request->GetSerialNumber(),
  1944                       IDB_PROFILER_STRING(Transaction()->Database()),
  1945                       IDB_PROFILER_STRING(Transaction()),
  1946                       IDB_PROFILER_STRING(this),
  1947                       key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
  1949   else {
  1950     IDB_PROFILER_MARK("IndexedDB Request %llu: "
  1951                       "database(%s).transaction(%s).objectStore(%s).add(%s)",
  1952                       "IDBRequest[%llu] MT IDBObjectStore.add()",
  1953                       request->GetSerialNumber(),
  1954                       IDB_PROFILER_STRING(Transaction()->Database()),
  1955                       IDB_PROFILER_STRING(Transaction()),
  1956                       IDB_PROFILER_STRING(this),
  1957                       key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
  1959 #endif
  1961   return request.forget();
  1964 nsresult
  1965 IDBObjectStore::AddOrPutInternal(
  1966                       const SerializedStructuredCloneWriteInfo& aCloneWriteInfo,
  1967                       const Key& aKey,
  1968                       const InfallibleTArray<IndexUpdateInfo>& aUpdateInfoArray,
  1969                       const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs,
  1970                       bool aOverwrite,
  1971                       IDBRequest** _retval)
  1973   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1974   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1976   if (!mTransaction->IsOpen()) {
  1977     return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
  1980   if (!IsWriteAllowed()) {
  1981     return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR;
  1984   nsRefPtr<IDBRequest> request = GenerateRequest(this);
  1985   IDB_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1987   StructuredCloneWriteInfo cloneWriteInfo;
  1988   if (!cloneWriteInfo.SetFromSerialized(aCloneWriteInfo)) {
  1989     IDB_WARNING("Failed to copy structured clone buffer!");
  1990     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1993   if (!aBlobs.IsEmpty()) {
  1994     FileManager* fileManager = Transaction()->Database()->Manager();
  1995     NS_ASSERTION(fileManager, "Null file manager?!");
  1997     uint32_t length = aBlobs.Length();
  1998     cloneWriteInfo.mFiles.SetCapacity(length);
  2000     for (uint32_t index = 0; index < length; index++) {
  2001       const nsCOMPtr<nsIDOMBlob>& blob = aBlobs[index];
  2003       nsCOMPtr<nsIInputStream> inputStream;
  2005       nsRefPtr<FileInfo> fileInfo = Transaction()->GetFileInfo(blob);
  2006       if (!fileInfo) {
  2007         fileInfo = blob->GetFileInfo(fileManager);
  2009         if (!fileInfo) {
  2010           fileInfo = fileManager->GetNewFileInfo();
  2011           if (!fileInfo) {
  2012             IDB_WARNING("Failed to get new file info!");
  2013             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  2016           if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) {
  2017             IDB_WARNING("Failed to get internal steam!");
  2018             return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  2021           // XXXbent This is where we should send a message back to the child to
  2022           //         update the file id.
  2024           Transaction()->AddFileInfo(blob, fileInfo);
  2028       StructuredCloneFile* file = cloneWriteInfo.mFiles.AppendElement();
  2029       file->mFile = blob;
  2030       file->mFileInfo.swap(fileInfo);
  2031       file->mInputStream.swap(inputStream);
  2035   Key key(aKey);
  2037   nsTArray<IndexUpdateInfo> updateInfo(aUpdateInfoArray);
  2039   nsRefPtr<AddHelper> helper =
  2040     new AddHelper(mTransaction, request, this, Move(cloneWriteInfo), key,
  2041                   aOverwrite, updateInfo);
  2043   nsresult rv = helper->DispatchToTransactionPool();
  2044   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2046 #ifdef IDB_PROFILER_USE_MARKS
  2047   if (aOverwrite) {
  2048     IDB_PROFILER_MARK("IndexedDB Request %llu: "
  2049                       "database(%s).transaction(%s).objectStore(%s).%s(%s)",
  2050                       "IDBRequest[%llu] MT IDBObjectStore.put()",
  2051                       request->GetSerialNumber(),
  2052                       IDB_PROFILER_STRING(Transaction()->Database()),
  2053                       IDB_PROFILER_STRING(Transaction()),
  2054                       IDB_PROFILER_STRING(this),
  2055                       key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
  2057   else {
  2058     IDB_PROFILER_MARK("IndexedDB Request %llu: "
  2059                       "database(%s).transaction(%s).objectStore(%s).add(%s)",
  2060                       "IDBRequest[%llu] MT IDBObjectStore.add()",
  2061                       request->GetSerialNumber(),
  2062                       IDB_PROFILER_STRING(Transaction()->Database()),
  2063                       IDB_PROFILER_STRING(Transaction()),
  2064                       IDB_PROFILER_STRING(this),
  2065                       key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
  2067 #endif
  2069   request.forget(_retval);
  2070   return NS_OK;
  2073 already_AddRefed<IDBRequest>
  2074 IDBObjectStore::GetInternal(IDBKeyRange* aKeyRange, ErrorResult& aRv)
  2076   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2077   NS_ASSERTION(aKeyRange, "Null pointer!");
  2079   if (!mTransaction->IsOpen()) {
  2080     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2081     return nullptr;
  2084   nsRefPtr<IDBRequest> request = GenerateRequest(this);
  2085   if (!request) {
  2086     IDB_WARNING("Failed to generate request!");
  2087     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2088     return nullptr;
  2091   nsRefPtr<GetHelper> helper =
  2092     new GetHelper(mTransaction, request, this, aKeyRange);
  2094   nsresult rv = helper->DispatchToTransactionPool();
  2095   if (NS_FAILED(rv)) {
  2096     IDB_WARNING("Failed to dispatch!");
  2097     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2098     return nullptr;
  2101   IDB_PROFILER_MARK("IndexedDB Request %llu: "
  2102                     "database(%s).transaction(%s).objectStore(%s).get(%s)",
  2103                     "IDBRequest[%llu] MT IDBObjectStore.get()",
  2104                     request->GetSerialNumber(),
  2105                     IDB_PROFILER_STRING(Transaction()->Database()),
  2106                     IDB_PROFILER_STRING(Transaction()),
  2107                     IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
  2109   return request.forget();
  2112 already_AddRefed<IDBRequest>
  2113 IDBObjectStore::GetAllInternal(IDBKeyRange* aKeyRange,
  2114                                uint32_t aLimit, ErrorResult& aRv)
  2116   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2118   if (!mTransaction->IsOpen()) {
  2119     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2120     return nullptr;
  2123   nsRefPtr<IDBRequest> request = GenerateRequest(this);
  2124   if (!request) {
  2125     IDB_WARNING("Failed to generate request!");
  2126     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2127     return nullptr;
  2130   nsRefPtr<GetAllHelper> helper =
  2131     new GetAllHelper(mTransaction, request, this, aKeyRange, aLimit);
  2133   nsresult rv = helper->DispatchToTransactionPool();
  2134   if (NS_FAILED(rv)) {
  2135     IDB_WARNING("Failed to dispatch!");
  2136     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2137     return nullptr;
  2140   IDB_PROFILER_MARK("IndexedDB Request %llu: "
  2141                     "database(%s).transaction(%s).objectStore(%s)."
  2142                     "getAll(%s, %lu)",
  2143                     "IDBRequest[%llu] MT IDBObjectStore.getAll()",
  2144                     request->GetSerialNumber(),
  2145                     IDB_PROFILER_STRING(Transaction()->Database()),
  2146                     IDB_PROFILER_STRING(Transaction()),
  2147                     IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
  2148                     aLimit);
  2150   return request.forget();
  2153 already_AddRefed<IDBRequest>
  2154 IDBObjectStore::GetAllKeysInternal(IDBKeyRange* aKeyRange, uint32_t aLimit,
  2155                                    ErrorResult& aRv)
  2157   MOZ_ASSERT(NS_IsMainThread());
  2159   if (!mTransaction->IsOpen()) {
  2160     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2161     return nullptr;
  2164   nsRefPtr<IDBRequest> request = GenerateRequest(this);
  2165   if (!request) {
  2166     IDB_WARNING("Failed to generate request!");
  2167     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2168     return nullptr;
  2171   nsRefPtr<GetAllKeysHelper> helper =
  2172     new GetAllKeysHelper(mTransaction, request, this, aKeyRange, aLimit);
  2174   nsresult rv = helper->DispatchToTransactionPool();
  2175   if (NS_FAILED(rv)) {
  2176     IDB_WARNING("Failed to dispatch!");
  2177     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2178     return nullptr;
  2181   IDB_PROFILER_MARK("IndexedDB Request %llu: "
  2182                     "database(%s).transaction(%s).objectStore(%s)."
  2183                     "getAllKeys(%s, %lu)",
  2184                     "IDBRequest[%llu] MT IDBObjectStore.getAllKeys()",
  2185                     request->GetSerialNumber(),
  2186                     IDB_PROFILER_STRING(Transaction()->Database()),
  2187                     IDB_PROFILER_STRING(Transaction()),
  2188                     IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
  2189                     aLimit);
  2191   return request.forget();
  2194 already_AddRefed<IDBRequest>
  2195 IDBObjectStore::DeleteInternal(IDBKeyRange* aKeyRange,
  2196                                ErrorResult& aRv)
  2198   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2199   NS_ASSERTION(aKeyRange, "Null key range!");
  2201   if (!mTransaction->IsOpen()) {
  2202     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2203     return nullptr;
  2206   if (!IsWriteAllowed()) {
  2207     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
  2208     return nullptr;
  2211   nsRefPtr<IDBRequest> request = GenerateRequest(this);
  2212   if (!request) {
  2213     IDB_WARNING("Failed to generate request!");
  2214     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2215     return nullptr;
  2218   nsRefPtr<DeleteHelper> helper =
  2219     new DeleteHelper(mTransaction, request, this, aKeyRange);
  2221   nsresult rv = helper->DispatchToTransactionPool();
  2222   if (NS_FAILED(rv)) {
  2223     IDB_WARNING("Failed to dispatch!");
  2224     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2225     return nullptr;
  2228   IDB_PROFILER_MARK("IndexedDB Request %llu: "
  2229                     "database(%s).transaction(%s).objectStore(%s).delete(%s)",
  2230                     "IDBRequest[%llu] MT IDBObjectStore.delete()",
  2231                     request->GetSerialNumber(),
  2232                     IDB_PROFILER_STRING(Transaction()->Database()),
  2233                     IDB_PROFILER_STRING(Transaction()),
  2234                     IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
  2236   return request.forget();
  2239 already_AddRefed<IDBRequest>
  2240 IDBObjectStore::Clear(ErrorResult& aRv)
  2242   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2244   if (!mTransaction->IsOpen()) {
  2245     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2246     return nullptr;
  2249   if (!IsWriteAllowed()) {
  2250     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
  2251     return nullptr;
  2254   nsRefPtr<IDBRequest> request = GenerateRequest(this);
  2255   if (!request) {
  2256     IDB_WARNING("Failed to generate request!");
  2257     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2258     return nullptr;
  2261   nsRefPtr<ClearHelper> helper(new ClearHelper(mTransaction, request, this));
  2263   nsresult rv = helper->DispatchToTransactionPool();
  2264   if (NS_FAILED(rv)) {
  2265     IDB_WARNING("Failed to dispatch!");
  2266     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2267     return nullptr;
  2270   IDB_PROFILER_MARK("IndexedDB Request %llu: "
  2271                     "database(%s).transaction(%s).objectStore(%s).clear()",
  2272                     "IDBRequest[%llu] MT IDBObjectStore.clear()",
  2273                     request->GetSerialNumber(),
  2274                     IDB_PROFILER_STRING(Transaction()->Database()),
  2275                     IDB_PROFILER_STRING(Transaction()),
  2276                     IDB_PROFILER_STRING(this));
  2278   return request.forget();
  2281 already_AddRefed<IDBRequest>
  2282 IDBObjectStore::CountInternal(IDBKeyRange* aKeyRange, ErrorResult& aRv)
  2284   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2286   if (!mTransaction->IsOpen()) {
  2287     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2288     return nullptr;
  2291   nsRefPtr<IDBRequest> request = GenerateRequest(this);
  2292   if (!request) {
  2293     IDB_WARNING("Failed to generate request!");
  2294     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2295     return nullptr;
  2298   nsRefPtr<CountHelper> helper =
  2299     new CountHelper(mTransaction, request, this, aKeyRange);
  2300   nsresult rv = helper->DispatchToTransactionPool();
  2301   if (NS_FAILED(rv)) {
  2302     IDB_WARNING("Failed to dispatch!");
  2303     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2304     return nullptr;
  2307   IDB_PROFILER_MARK("IndexedDB Request %llu: "
  2308                     "database(%s).transaction(%s).objectStore(%s).count(%s)",
  2309                     "IDBRequest[%llu] MT IDBObjectStore.count()",
  2310                     request->GetSerialNumber(),
  2311                     IDB_PROFILER_STRING(Transaction()->Database()),
  2312                     IDB_PROFILER_STRING(Transaction()),
  2313                     IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
  2315   return request.forget();
  2318 already_AddRefed<IDBRequest>
  2319 IDBObjectStore::OpenCursorInternal(IDBKeyRange* aKeyRange,
  2320                                    size_t aDirection, ErrorResult& aRv)
  2322   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2324   if (!mTransaction->IsOpen()) {
  2325     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2326     return nullptr;
  2329   IDBCursor::Direction direction =
  2330     static_cast<IDBCursor::Direction>(aDirection);
  2332   nsRefPtr<IDBRequest> request = GenerateRequest(this);
  2333   if (!request) {
  2334     IDB_WARNING("Failed to generate request!");
  2335     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2336     return nullptr;
  2339   nsRefPtr<OpenCursorHelper> helper =
  2340     new OpenCursorHelper(mTransaction, request, this, aKeyRange, direction);
  2342   nsresult rv = helper->DispatchToTransactionPool();
  2343   if (NS_FAILED(rv)) {
  2344     IDB_WARNING("Failed to dispatch!");
  2345     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2346     return nullptr;
  2349   IDB_PROFILER_MARK("IndexedDB Request %llu: "
  2350                     "database(%s).transaction(%s).objectStore(%s)."
  2351                     "openCursor(%s, %s)",
  2352                     "IDBRequest[%llu] MT IDBObjectStore.openCursor()",
  2353                     request->GetSerialNumber(),
  2354                     IDB_PROFILER_STRING(Transaction()->Database()),
  2355                     IDB_PROFILER_STRING(Transaction()),
  2356                     IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
  2357                     IDB_PROFILER_STRING(direction));
  2359   return request.forget();
  2362 nsresult
  2363 IDBObjectStore::OpenCursorFromChildProcess(
  2364                             IDBRequest* aRequest,
  2365                             size_t aDirection,
  2366                             const Key& aKey,
  2367                             const SerializedStructuredCloneReadInfo& aCloneInfo,
  2368                             nsTArray<StructuredCloneFile>& aBlobs,
  2369                             IDBCursor** _retval)
  2371   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2372   NS_ASSERTION((!aCloneInfo.dataLength && !aCloneInfo.data) ||
  2373                (aCloneInfo.dataLength && aCloneInfo.data),
  2374                "Inconsistent clone info!");
  2376   IDBCursor::Direction direction =
  2377     static_cast<IDBCursor::Direction>(aDirection);
  2379   StructuredCloneReadInfo cloneInfo;
  2381   if (!cloneInfo.SetFromSerialized(aCloneInfo)) {
  2382     IDB_WARNING("Failed to copy clone buffer!");
  2383     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  2386   cloneInfo.mFiles.SwapElements(aBlobs);
  2388   nsRefPtr<IDBCursor> cursor =
  2389     IDBCursor::Create(aRequest, mTransaction, this, direction, Key(),
  2390                       EmptyCString(), EmptyCString(), aKey, Move(cloneInfo));
  2391   IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2393   NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!");
  2395   cursor.forget(_retval);
  2396   return NS_OK;
  2399 nsresult
  2400 IDBObjectStore::OpenCursorFromChildProcess(IDBRequest* aRequest,
  2401                                            size_t aDirection,
  2402                                            const Key& aKey,
  2403                                            IDBCursor** _retval)
  2405   MOZ_ASSERT(NS_IsMainThread());
  2406   MOZ_ASSERT(aRequest);
  2408   auto direction = static_cast<IDBCursor::Direction>(aDirection);
  2410   nsRefPtr<IDBCursor> cursor =
  2411     IDBCursor::Create(aRequest, mTransaction, this, direction, Key(),
  2412                       EmptyCString(), EmptyCString(), aKey);
  2413   IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2415   cursor.forget(_retval);
  2416   return NS_OK;
  2419 already_AddRefed<IDBRequest>
  2420 IDBObjectStore::OpenKeyCursorInternal(IDBKeyRange* aKeyRange, size_t aDirection,
  2421                                       ErrorResult& aRv)
  2423   MOZ_ASSERT(NS_IsMainThread());
  2425   if (!mTransaction->IsOpen()) {
  2426     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2427     return nullptr;
  2430   nsRefPtr<IDBRequest> request = GenerateRequest(this);
  2431   if (!request) {
  2432     IDB_WARNING("Failed to generate request!");
  2433     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2434     return nullptr;
  2437   auto direction = static_cast<IDBCursor::Direction>(aDirection);
  2439   nsRefPtr<OpenKeyCursorHelper> helper =
  2440     new OpenKeyCursorHelper(mTransaction, request, this, aKeyRange, direction);
  2442   nsresult rv = helper->DispatchToTransactionPool();
  2443   if (NS_FAILED(rv)) {
  2444     IDB_WARNING("Failed to dispatch!");
  2445     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2446     return nullptr;
  2449   IDB_PROFILER_MARK("IndexedDB Request %llu: "
  2450                     "database(%s).transaction(%s).objectStore(%s)."
  2451                     "openKeyCursor(%s, %s)",
  2452                     "IDBRequest[%llu] MT IDBObjectStore.openKeyCursor()",
  2453                     request->GetSerialNumber(),
  2454                     IDB_PROFILER_STRING(Transaction()->Database()),
  2455                     IDB_PROFILER_STRING(Transaction()),
  2456                     IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
  2457                     IDB_PROFILER_STRING(direction));
  2459   return request.forget();
  2462 void
  2463 IDBObjectStore::SetInfo(ObjectStoreInfo* aInfo)
  2465   NS_ASSERTION(NS_IsMainThread(), "Wrong thread");
  2466   NS_ASSERTION(aInfo != mInfo, "This is nonsense");
  2468   mInfo = aInfo;
  2471 already_AddRefed<IDBIndex>
  2472 IDBObjectStore::CreateIndexInternal(const IndexInfo& aInfo, ErrorResult& aRv)
  2474   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2476   IndexInfo* indexInfo = mInfo->indexes.AppendElement();
  2478   indexInfo->name = aInfo.name;
  2479   indexInfo->id = aInfo.id;
  2480   indexInfo->keyPath = aInfo.keyPath;
  2481   indexInfo->unique = aInfo.unique;
  2482   indexInfo->multiEntry = aInfo.multiEntry;
  2484   // Don't leave this in the list if we fail below!
  2485   AutoRemoveIndex autoRemove(mInfo, aInfo.name);
  2487   nsRefPtr<IDBIndex> index = IDBIndex::Create(this, indexInfo, true);
  2489   mCreatedIndexes.AppendElement(index);
  2491   if (IndexedDatabaseManager::IsMainProcess()) {
  2492     nsRefPtr<CreateIndexHelper> helper =
  2493       new CreateIndexHelper(mTransaction, index);
  2495     nsresult rv = helper->DispatchToTransactionPool();
  2496     if (NS_FAILED(rv)) {
  2497       IDB_WARNING("Failed to dispatch!");
  2498       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2499       return nullptr;
  2503   autoRemove.forget();
  2505   IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
  2506                     "database(%s).transaction(%s).objectStore(%s)."
  2507                     "createIndex(%s)",
  2508                     "MT IDBObjectStore.createIndex()",
  2509                     IDB_PROFILER_STRING(Transaction()->Database()),
  2510                     IDB_PROFILER_STRING(Transaction()),
  2511                     IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(index));
  2513   return index.forget();
  2516 already_AddRefed<IDBIndex>
  2517 IDBObjectStore::Index(const nsAString& aName, ErrorResult &aRv)
  2519   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2521   if (mTransaction->IsFinished()) {
  2522     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2523     return nullptr;
  2526   IndexInfo* indexInfo = nullptr;
  2527   uint32_t indexCount = mInfo->indexes.Length();
  2528   for (uint32_t index = 0; index < indexCount; index++) {
  2529     if (mInfo->indexes[index].name == aName) {
  2530       indexInfo = &(mInfo->indexes[index]);
  2531       break;
  2535   if (!indexInfo) {
  2536     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
  2537     return nullptr;
  2540   nsRefPtr<IDBIndex> retval;
  2541   for (uint32_t i = 0; i < mCreatedIndexes.Length(); i++) {
  2542     nsRefPtr<IDBIndex>& index = mCreatedIndexes[i];
  2543     if (index->Name() == aName) {
  2544       retval = index;
  2545       break;
  2549   if (!retval) {
  2550     retval = IDBIndex::Create(this, indexInfo, false);
  2551     if (!retval) {
  2552       IDB_WARNING("Failed to create index!");
  2553       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2554       return nullptr;
  2557     if (!mCreatedIndexes.AppendElement(retval)) {
  2558       IDB_WARNING("Out of memory!");
  2559       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2560       return nullptr;
  2564   return retval.forget();
  2567 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore)
  2569 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore)
  2570   NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
  2571   NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKeyPath)
  2572 NS_IMPL_CYCLE_COLLECTION_TRACE_END
  2574 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore)
  2575   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
  2576   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
  2578   for (uint32_t i = 0; i < tmp->mCreatedIndexes.Length(); i++) {
  2579     NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCreatedIndexes[i]");
  2580     cb.NoteXPCOMChild(static_cast<nsISupports*>(tmp->mCreatedIndexes[i].get()));
  2582 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
  2584 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore)
  2585   NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
  2587   // Don't unlink mTransaction!
  2589   tmp->mCreatedIndexes.Clear();
  2591   tmp->mCachedKeyPath = JSVAL_VOID;
  2593   if (tmp->mRooted) {
  2594     mozilla::DropJSObjects(tmp);
  2595     tmp->mRooted = false;
  2597 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
  2599 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBObjectStore)
  2600   NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
  2601   NS_INTERFACE_MAP_ENTRY(nsISupports)
  2602 NS_INTERFACE_MAP_END
  2604 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBObjectStore)
  2605 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBObjectStore)
  2607 JSObject*
  2608 IDBObjectStore::WrapObject(JSContext* aCx)
  2610   return IDBObjectStoreBinding::Wrap(aCx, this);
  2613 void
  2614 IDBObjectStore::GetKeyPath(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
  2615                            ErrorResult& aRv)
  2617   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2619   if (!JSVAL_IS_VOID(mCachedKeyPath)) {
  2620     JS::ExposeValueToActiveJS(mCachedKeyPath);
  2621     aResult.set(mCachedKeyPath);
  2622     return;
  2625   aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
  2626   if (NS_WARN_IF(aRv.Failed())) {
  2627     return;
  2630   if (JSVAL_IS_GCTHING(mCachedKeyPath)) {
  2631     mozilla::HoldJSObjects(this);
  2632     mRooted = true;
  2635   JS::ExposeValueToActiveJS(mCachedKeyPath);
  2636   aResult.set(mCachedKeyPath);
  2639 already_AddRefed<DOMStringList>
  2640 IDBObjectStore::GetIndexNames(ErrorResult& aRv)
  2642   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2644   nsRefPtr<DOMStringList> list(new DOMStringList());
  2646   nsTArray<nsString>& names = list->StringArray();
  2647   uint32_t count = mInfo->indexes.Length();
  2648   names.SetCapacity(count);
  2650   for (uint32_t index = 0; index < count; index++) {
  2651     names.InsertElementSorted(mInfo->indexes[index].name);
  2654   return list.forget();
  2657 already_AddRefed<IDBRequest>
  2658 IDBObjectStore::Get(JSContext* aCx, JS::Handle<JS::Value> aKey,
  2659                     ErrorResult& aRv)
  2661   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2663   if (!mTransaction->IsOpen()) {
  2664     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2665     return nullptr;
  2668   nsRefPtr<IDBKeyRange> keyRange;
  2669   aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
  2670   ENSURE_SUCCESS(aRv, nullptr);
  2672   if (!keyRange) {
  2673     // Must specify a key or keyRange for get().
  2674     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
  2675     return nullptr;
  2678   return GetInternal(keyRange, aRv);
  2681 already_AddRefed<IDBRequest>
  2682 IDBObjectStore::GetAll(JSContext* aCx,
  2683                        JS::Handle<JS::Value> aKey,
  2684                        const Optional<uint32_t>& aLimit, ErrorResult& aRv)
  2686   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2688   if (!mTransaction->IsOpen()) {
  2689     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2690     return nullptr;
  2693   nsRefPtr<IDBKeyRange> keyRange;
  2694   aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
  2695   ENSURE_SUCCESS(aRv, nullptr);
  2697   uint32_t limit = UINT32_MAX;
  2698   if (aLimit.WasPassed() && aLimit.Value() != 0) {
  2699     limit = aLimit.Value();
  2702   return GetAllInternal(keyRange, limit, aRv);
  2705 already_AddRefed<IDBRequest>
  2706 IDBObjectStore::Delete(JSContext* aCx, JS::Handle<JS::Value> aKey,
  2707                        ErrorResult& aRv)
  2709   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2711   if (!mTransaction->IsOpen()) {
  2712     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2713     return nullptr;
  2716   if (!IsWriteAllowed()) {
  2717     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
  2718     return nullptr;
  2721   nsRefPtr<IDBKeyRange> keyRange;
  2722   aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
  2723   ENSURE_SUCCESS(aRv, nullptr);
  2725   if (!keyRange) {
  2726     // Must specify a key or keyRange for delete().
  2727     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
  2728     return nullptr;
  2731   return DeleteInternal(keyRange, aRv);
  2734 already_AddRefed<IDBRequest>
  2735 IDBObjectStore::OpenCursor(JSContext* aCx,
  2736                            JS::Handle<JS::Value> aRange,
  2737                            IDBCursorDirection aDirection, ErrorResult& aRv)
  2739   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2741   if (!mTransaction->IsOpen()) {
  2742     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2743     return nullptr;
  2746   nsRefPtr<IDBKeyRange> keyRange;
  2747   aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
  2748   ENSURE_SUCCESS(aRv, nullptr);
  2750   IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
  2751   size_t argDirection = static_cast<size_t>(direction);
  2753   return OpenCursorInternal(keyRange, argDirection, aRv);
  2756 already_AddRefed<IDBIndex>
  2757 IDBObjectStore::CreateIndex(JSContext* aCx, const nsAString& aName,
  2758                             const nsAString& aKeyPath,
  2759                             const IDBIndexParameters& aOptionalParameters,
  2760                             ErrorResult& aRv)
  2762   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2764   KeyPath keyPath(0);
  2765   if (NS_FAILED(KeyPath::Parse(aCx, aKeyPath, &keyPath)) ||
  2766       !keyPath.IsValid()) {
  2767     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  2768     return nullptr;
  2771   return CreateIndex(aCx, aName, keyPath, aOptionalParameters, aRv);
  2774 already_AddRefed<IDBIndex>
  2775 IDBObjectStore::CreateIndex(JSContext* aCx, const nsAString& aName,
  2776                             const Sequence<nsString >& aKeyPath,
  2777                             const IDBIndexParameters& aOptionalParameters,
  2778                             ErrorResult& aRv)
  2780   NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!");
  2782   if (!aKeyPath.Length()) {
  2783     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  2784     return nullptr;
  2787   KeyPath keyPath(0);
  2788   if (NS_FAILED(KeyPath::Parse(aCx, aKeyPath, &keyPath))) {
  2789     aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR);
  2790     return nullptr;
  2793   return CreateIndex(aCx, aName, keyPath, aOptionalParameters, aRv);
  2796 already_AddRefed<IDBIndex>
  2797 IDBObjectStore::CreateIndex(JSContext* aCx, const nsAString& aName,
  2798                             KeyPath& aKeyPath,
  2799                             const IDBIndexParameters& aOptionalParameters,
  2800                             ErrorResult& aRv)
  2802   // Check name and current mode
  2803   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
  2805   if (!transaction ||
  2806       transaction != mTransaction ||
  2807       mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
  2808     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
  2809     return nullptr;
  2812   bool found = false;
  2813   uint32_t indexCount = mInfo->indexes.Length();
  2814   for (uint32_t index = 0; index < indexCount; index++) {
  2815     if (mInfo->indexes[index].name == aName) {
  2816       found = true;
  2817       break;
  2821   if (found) {
  2822     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR);
  2823     return nullptr;
  2826   NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
  2828 #ifdef DEBUG
  2829   for (uint32_t index = 0; index < mCreatedIndexes.Length(); index++) {
  2830     if (mCreatedIndexes[index]->Name() == aName) {
  2831       NS_ERROR("Already created this one!");
  2834 #endif
  2836   if (aOptionalParameters.mMultiEntry && aKeyPath.IsArray()) {
  2837     aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR);
  2838     return nullptr;
  2841   DatabaseInfo* databaseInfo = mTransaction->DBInfo();
  2843   IndexInfo info;
  2845   info.name = aName;
  2846   info.id = databaseInfo->nextIndexId++;
  2847   info.keyPath = aKeyPath;
  2848   info.unique = aOptionalParameters.mUnique;
  2849   info.multiEntry = aOptionalParameters.mMultiEntry;
  2851   return CreateIndexInternal(info, aRv);
  2854 void
  2855 IDBObjectStore::DeleteIndex(const nsAString& aName, ErrorResult& aRv)
  2857   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  2859   IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction();
  2861   if (!transaction ||
  2862       transaction != mTransaction ||
  2863       mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) {
  2864     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
  2865     return;
  2868   NS_ASSERTION(mTransaction->IsOpen(), "Impossible!");
  2870   uint32_t index = 0;
  2871   for (; index < mInfo->indexes.Length(); index++) {
  2872     if (mInfo->indexes[index].name == aName) {
  2873       break;
  2877   if (index == mInfo->indexes.Length()) {
  2878     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR);
  2879     return;
  2882   if (IndexedDatabaseManager::IsMainProcess()) {
  2883     nsRefPtr<DeleteIndexHelper> helper =
  2884       new DeleteIndexHelper(mTransaction, this, aName);
  2886     nsresult rv = helper->DispatchToTransactionPool();
  2887     if (NS_FAILED(rv)) {
  2888       IDB_WARNING("Failed to dispatch!");
  2889       aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  2890       return;
  2893   else {
  2894     NS_ASSERTION(mActorChild, "Must have an actor here!");
  2896     mActorChild->SendDeleteIndex(nsString(aName));
  2899   mInfo->indexes.RemoveElementAt(index);
  2901   for (uint32_t i = 0; i < mCreatedIndexes.Length(); i++) {
  2902     if (mCreatedIndexes[i]->Name() == aName) {
  2903       mCreatedIndexes.RemoveElementAt(i);
  2904       break;
  2908   IDB_PROFILER_MARK("IndexedDB Pseudo-request: "
  2909                     "database(%s).transaction(%s).objectStore(%s)."
  2910                     "deleteIndex(\"%s\")",
  2911                     "MT IDBObjectStore.deleteIndex()",
  2912                     IDB_PROFILER_STRING(Transaction()->Database()),
  2913                     IDB_PROFILER_STRING(Transaction()),
  2914                     IDB_PROFILER_STRING(this),
  2915                     NS_ConvertUTF16toUTF8(aName).get());
  2918 already_AddRefed<IDBRequest>
  2919 IDBObjectStore::Count(JSContext* aCx,
  2920                       JS::Handle<JS::Value> aKey,
  2921                       ErrorResult& aRv)
  2923   if (!mTransaction->IsOpen()) {
  2924     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2925     return nullptr;
  2928   nsRefPtr<IDBKeyRange> keyRange;
  2929   aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
  2930   ENSURE_SUCCESS(aRv, nullptr);
  2932   return CountInternal(keyRange, aRv);
  2935 already_AddRefed<IDBRequest>
  2936 IDBObjectStore::GetAllKeys(JSContext* aCx,
  2937                            JS::Handle<JS::Value> aKey,
  2938                            const Optional<uint32_t>& aLimit, ErrorResult& aRv)
  2940   MOZ_ASSERT(NS_IsMainThread());
  2942   if (!mTransaction->IsOpen()) {
  2943     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2944     return nullptr;
  2947   nsRefPtr<IDBKeyRange> keyRange;
  2948   aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
  2949   ENSURE_SUCCESS(aRv, nullptr);
  2951   uint32_t limit = UINT32_MAX;
  2952   if (aLimit.WasPassed() && aLimit.Value() != 0) {
  2953     limit = aLimit.Value();
  2956   return GetAllKeysInternal(keyRange, limit, aRv);
  2959 already_AddRefed<IDBRequest>
  2960 IDBObjectStore::OpenKeyCursor(JSContext* aCx,
  2961                               JS::Handle<JS::Value> aRange,
  2962                               IDBCursorDirection aDirection, ErrorResult& aRv)
  2964   MOZ_ASSERT(NS_IsMainThread());
  2966   if (!mTransaction->IsOpen()) {
  2967     aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
  2968     return nullptr;
  2971   nsRefPtr<IDBKeyRange> keyRange;
  2972   aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
  2973   ENSURE_SUCCESS(aRv, nullptr);
  2975   IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
  2977   return OpenKeyCursorInternal(keyRange, static_cast<size_t>(direction), aRv);
  2980 inline nsresult
  2981 CopyData(nsIInputStream* aInputStream, nsIOutputStream* aOutputStream)
  2983   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  2984   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  2986   PROFILER_LABEL("IndexedDB", "CopyData");
  2988   nsresult rv;
  2990   do {
  2991     char copyBuffer[FILE_COPY_BUFFER_SIZE];
  2993     uint32_t numRead;
  2994     rv = aInputStream->Read(copyBuffer, sizeof(copyBuffer), &numRead);
  2995     NS_ENSURE_SUCCESS(rv, rv);
  2997     if (!numRead) {
  2998       break;
  3001     uint32_t numWrite;
  3002     rv = aOutputStream->Write(copyBuffer, numRead, &numWrite);
  3003     if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) {
  3004       rv = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
  3006     NS_ENSURE_SUCCESS(rv, rv);
  3008     NS_ENSURE_TRUE(numWrite == numRead, NS_ERROR_FAILURE);
  3009   } while (true);
  3011   rv = aOutputStream->Flush();
  3012   NS_ENSURE_SUCCESS(rv, rv);
  3014   return NS_OK;
  3017 void
  3018 ObjectStoreHelper::ReleaseMainThreadObjects()
  3020   mObjectStore = nullptr;
  3021   AsyncConnectionHelper::ReleaseMainThreadObjects();
  3024 nsresult
  3025 ObjectStoreHelper::Dispatch(nsIEventTarget* aDatabaseThread)
  3027   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3029   PROFILER_MAIN_THREAD_LABEL("IndexedDB", "ObjectStoreHelper::Dispatch");
  3031   if (IndexedDatabaseManager::IsMainProcess()) {
  3032     return AsyncConnectionHelper::Dispatch(aDatabaseThread);
  3035   // If we've been invalidated then there's no point sending anything to the
  3036   // parent process.
  3037   if (mObjectStore->Transaction()->Database()->IsInvalidated()) {
  3038     IDB_REPORT_INTERNAL_ERR();
  3039     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  3042   IndexedDBObjectStoreChild* objectStoreActor = mObjectStore->GetActorChild();
  3043   NS_ASSERTION(objectStoreActor, "Must have an actor here!");
  3045   ObjectStoreRequestParams params;
  3046   nsresult rv = PackArgumentsForParentProcess(params);
  3047   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3049   NoDispatchEventTarget target;
  3050   rv = AsyncConnectionHelper::Dispatch(&target);
  3051   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3053   mActor =
  3054     new IndexedDBObjectStoreRequestChild(this, mObjectStore, params.type());
  3055   objectStoreActor->SendPIndexedDBRequestConstructor(mActor, params);
  3057   return NS_OK;
  3060 void
  3061 NoRequestObjectStoreHelper::ReleaseMainThreadObjects()
  3063   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3064   mObjectStore = nullptr;
  3065   AsyncConnectionHelper::ReleaseMainThreadObjects();
  3068 nsresult
  3069 NoRequestObjectStoreHelper::UnpackResponseFromParentProcess(
  3070                                             const ResponseValue& aResponseValue)
  3072   MOZ_CRASH();
  3075 AsyncConnectionHelper::ChildProcessSendResult
  3076 NoRequestObjectStoreHelper::SendResponseToChildProcess(nsresult aResultCode)
  3078   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3079   return Success_NotSent;
  3082 nsresult
  3083 NoRequestObjectStoreHelper::OnSuccess()
  3085   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3086   return NS_OK;
  3089 void
  3090 NoRequestObjectStoreHelper::OnError()
  3092   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3093   mTransaction->Abort(GetResultCode());
  3096 // This is a duplicate of the js engine's byte munging in StructuredClone.cpp
  3097 uint64_t
  3098 ReinterpretDoubleAsUInt64(double d)
  3100   union {
  3101     double d;
  3102     uint64_t u;
  3103   } pun;
  3104   pun.d = d;
  3105   return pun.u;
  3108 nsresult
  3109 AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
  3111   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  3112   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3113   NS_ASSERTION(aConnection, "Passed a null connection!");
  3115   PROFILER_LABEL("IndexedDB", "AddHelper::DoDatabaseWork");
  3117   if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
  3118     NS_WARNING("Refusing to add more data because disk space is low!");
  3119     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
  3122   nsresult rv;
  3123   bool keyUnset = mKey.IsUnset();
  3124   int64_t osid = mObjectStore->Id();
  3125   const KeyPath& keyPath = mObjectStore->GetKeyPath();
  3127   // The "|| keyUnset" here is mostly a debugging tool. If a key isn't
  3128   // specified we should never have a collision and so it shouldn't matter
  3129   // if we allow overwrite or not. By not allowing overwrite we raise
  3130   // detectable errors rather than corrupting data
  3131   nsCOMPtr<mozIStorageStatement> stmt = !mOverwrite || keyUnset ?
  3132     mTransaction->GetCachedStatement(
  3133       "INSERT INTO object_data (object_store_id, key_value, data, file_ids) "
  3134       "VALUES (:osid, :key_value, :data, :file_ids)") :
  3135     mTransaction->GetCachedStatement(
  3136       "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data, "
  3137                                           "file_ids) "
  3138       "VALUES (:osid, :key_value, :data, :file_ids)");
  3139   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3141   mozStorageStatementScoper scoper(stmt);
  3143   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid);
  3144   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3146   NS_ASSERTION(!keyUnset || mObjectStore->IsAutoIncrement(),
  3147                "Should have key unless autoincrement");
  3149   int64_t autoIncrementNum = 0;
  3151   if (mObjectStore->IsAutoIncrement()) {
  3152     if (keyUnset) {
  3153       autoIncrementNum = mObjectStore->Info()->nextAutoIncrementId;
  3155       MOZ_ASSERT(autoIncrementNum > 0,
  3156                  "Generated key must always be a positive integer");
  3158       if (autoIncrementNum > (1LL << 53)) {
  3159         IDB_REPORT_INTERNAL_ERR();
  3160         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  3163       mKey.SetFromInteger(autoIncrementNum);
  3165     else if (mKey.IsFloat() &&
  3166              mKey.ToFloat() >= mObjectStore->Info()->nextAutoIncrementId) {
  3167       autoIncrementNum = floor(mKey.ToFloat());
  3170     if (keyUnset && keyPath.IsValid()) {
  3171       // Special case where someone put an object into an autoIncrement'ing
  3172       // objectStore with no key in its keyPath set. We needed to figure out
  3173       // which row id we would get above before we could set that properly.
  3175       LittleEndian::writeUint64((char*)mCloneWriteInfo.mCloneBuffer.data() +
  3176                                 mCloneWriteInfo.mOffsetToKeyProp,
  3177                                 ReinterpretDoubleAsUInt64(static_cast<double>(
  3178                                                           autoIncrementNum)));
  3182   mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key_value"));
  3185   // Compress the bytes before adding into the database.
  3186   const char* uncompressed =
  3187     reinterpret_cast<const char*>(mCloneWriteInfo.mCloneBuffer.data());
  3188   size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes();
  3190   // We don't have a smart pointer class that calls moz_free, so we need to
  3191   // manage | compressed | manually.
  3193     size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength);
  3194     // moz_malloc is equivalent to NS_Alloc, which we use because mozStorage
  3195     // expects to be able to free the adopted pointer with NS_Free.
  3196     char* compressed = (char*)moz_malloc(compressedLength);
  3197     NS_ENSURE_TRUE(compressed, NS_ERROR_OUT_OF_MEMORY);
  3199     snappy::RawCompress(uncompressed, uncompressedLength, compressed,
  3200                         &compressedLength);
  3202     uint8_t* dataBuffer = reinterpret_cast<uint8_t*>(compressed);
  3203     size_t dataBufferLength = compressedLength;
  3205     // If this call succeeds, | compressed | is now owned by the statement, and
  3206     // we are no longer responsible for it.
  3207     rv = stmt->BindAdoptedBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer,
  3208                                      dataBufferLength);
  3209     if (NS_FAILED(rv)) {
  3210       moz_free(compressed);
  3212     IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3215   // Handle blobs
  3216   uint32_t length = mCloneWriteInfo.mFiles.Length();
  3217   if (length) {
  3218     nsRefPtr<FileManager> fileManager = mDatabase->Manager();
  3220     nsCOMPtr<nsIFile> directory = fileManager->GetDirectory();
  3221     IDB_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3223     nsCOMPtr<nsIFile> journalDirectory = fileManager->EnsureJournalDirectory();
  3224     IDB_ENSURE_TRUE(journalDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3226     nsAutoString fileIds;
  3228     for (uint32_t index = 0; index < length; index++) {
  3229       StructuredCloneFile& cloneFile = mCloneWriteInfo.mFiles[index];
  3231       FileInfo* fileInfo = cloneFile.mFileInfo;
  3232       nsIInputStream* inputStream = cloneFile.mInputStream;
  3234       int64_t id = fileInfo->Id();
  3235       if (inputStream) {
  3236         // Create a journal file first
  3237         nsCOMPtr<nsIFile> nativeFile =
  3238           fileManager->GetFileForId(journalDirectory, id);
  3239         IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3241         rv = nativeFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644);
  3242         IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3244         // Now we can copy the blob
  3245         nativeFile = fileManager->GetFileForId(directory, id);
  3246         IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3248         IDBDatabase* database = mObjectStore->Transaction()->Database();
  3249         nsRefPtr<FileOutputStream> outputStream =
  3250           FileOutputStream::Create(database->Type(), database->Group(),
  3251                                    database->Origin(), nativeFile);
  3252         IDB_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3254         rv = CopyData(inputStream, outputStream);
  3255         if (NS_FAILED(rv) &&
  3256             NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) {
  3257           IDB_REPORT_INTERNAL_ERR();
  3258           rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  3260         NS_ENSURE_SUCCESS(rv, rv);
  3262         cloneFile.mFile->AddFileInfo(fileInfo);
  3265       if (index) {
  3266         fileIds.Append(NS_LITERAL_STRING(" "));
  3268       fileIds.AppendInt(id);
  3271     rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds);
  3273   else {
  3274     rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids"));
  3276   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3278   rv = stmt->Execute();
  3279   if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
  3280     NS_ASSERTION(!keyUnset, "Generated key had a collision!?");
  3281     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
  3283   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3285   int64_t objectDataId;
  3286   rv = aConnection->GetLastInsertRowID(&objectDataId);
  3287   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3289   // Update our indexes if needed.
  3290   if (mOverwrite || !mIndexUpdateInfo.IsEmpty()) {
  3291     rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey, mOverwrite,
  3292                                        objectDataId, mIndexUpdateInfo);
  3293     if (rv == NS_ERROR_STORAGE_CONSTRAINT) {
  3294       return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
  3296     IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3299   if (autoIncrementNum) {
  3300     mObjectStore->Info()->nextAutoIncrementId = autoIncrementNum + 1;
  3303   return NS_OK;
  3306 nsresult
  3307 AddHelper::GetSuccessResult(JSContext* aCx,
  3308                             JS::MutableHandle<JS::Value> aVal)
  3310   NS_ASSERTION(!mKey.IsUnset(), "Badness!");
  3312   mCloneWriteInfo.mCloneBuffer.clear();
  3314   return mKey.ToJSVal(aCx, aVal);
  3317 void
  3318 AddHelper::ReleaseMainThreadObjects()
  3320   IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo);
  3321   ObjectStoreHelper::ReleaseMainThreadObjects();
  3324 nsresult
  3325 AddHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
  3327   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3328   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3330   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  3331                              "AddHelper::PackArgumentsForParentProcess");
  3333   AddPutParams commonParams;
  3334   commonParams.cloneInfo() = mCloneWriteInfo;
  3335   commonParams.key() = mKey;
  3336   commonParams.indexUpdateInfos().AppendElements(mIndexUpdateInfo);
  3338   const nsTArray<StructuredCloneFile>& files = mCloneWriteInfo.mFiles;
  3340   if (!files.IsEmpty()) {
  3341     uint32_t fileCount = files.Length();
  3343     InfallibleTArray<PBlobChild*>& blobsChild = commonParams.blobsChild();
  3344     blobsChild.SetCapacity(fileCount);
  3346     ContentChild* contentChild = ContentChild::GetSingleton();
  3347     NS_ASSERTION(contentChild, "This should never be null!");
  3349     for (uint32_t index = 0; index < fileCount; index++) {
  3350       const StructuredCloneFile& file = files[index];
  3352       NS_ASSERTION(file.mFile, "This should never be null!");
  3353       NS_ASSERTION(!file.mFileInfo, "This is not yet supported!");
  3355       BlobChild* actor =
  3356         contentChild->GetOrCreateActorForBlob(file.mFile);
  3357       if (!actor) {
  3358         IDB_REPORT_INTERNAL_ERR();
  3359         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  3361       blobsChild.AppendElement(actor);
  3365   if (mOverwrite) {
  3366     PutParams putParams;
  3367     putParams.commonParams() = commonParams;
  3368     aParams = putParams;
  3370   else {
  3371     AddParams addParams;
  3372     addParams.commonParams() = commonParams;
  3373     aParams = addParams;
  3376   return NS_OK;
  3379 AsyncConnectionHelper::ChildProcessSendResult
  3380 AddHelper::SendResponseToChildProcess(nsresult aResultCode)
  3382   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3383   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3385   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  3386                              "AddHelper::SendResponseToChildProcess");
  3388   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
  3389   NS_ASSERTION(actor, "How did we get this far without an actor?");
  3391   ResponseValue response;
  3392   if (NS_FAILED(aResultCode)) {
  3393     response =  aResultCode;
  3395   else if (mOverwrite) {
  3396     PutResponse putResponse;
  3397     putResponse.key() = mKey;
  3398     response = putResponse;
  3400   else {
  3401     AddResponse addResponse;
  3402     addResponse.key() = mKey;
  3403     response = addResponse;
  3406   if (!actor->SendResponse(response)) {
  3407     return Error;
  3410   return Success_Sent;
  3413 nsresult
  3414 AddHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
  3416   NS_ASSERTION(aResponseValue.type() == ResponseValue::TAddResponse ||
  3417                aResponseValue.type() == ResponseValue::TPutResponse,
  3418                "Bad response type!");
  3420   mKey = mOverwrite ?
  3421          aResponseValue.get_PutResponse().key() :
  3422          aResponseValue.get_AddResponse().key();
  3424   return NS_OK;
  3427 nsresult
  3428 GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
  3430   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  3431   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3432   NS_ASSERTION(mKeyRange, "Must have a key range here!");
  3434   PROFILER_LABEL("IndexedDB", "GetHelper::DoDatabaseWork [IDBObjectStore.cpp]");
  3436   nsCString keyRangeClause;
  3437   mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause);
  3439   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
  3441   nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
  3442                                        "WHERE object_store_id = :osid") +
  3443                     keyRangeClause + NS_LITERAL_CSTRING(" LIMIT 1");
  3445   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
  3446   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3448   mozStorageStatementScoper scoper(stmt);
  3450   nsresult rv =
  3451     stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore->Id());
  3452   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3454   rv = mKeyRange->BindToStatement(stmt);
  3455   NS_ENSURE_SUCCESS(rv, rv);
  3457   bool hasResult;
  3458   rv = stmt->ExecuteStep(&hasResult);
  3459   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3461   if (hasResult) {
  3462     rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
  3463       mDatabase, mCloneReadInfo);
  3464     NS_ENSURE_SUCCESS(rv, rv);
  3467   return NS_OK;
  3470 nsresult
  3471 GetHelper::GetSuccessResult(JSContext* aCx,
  3472                             JS::MutableHandle<JS::Value> aVal)
  3474   bool result = IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, aVal);
  3476   mCloneReadInfo.mCloneBuffer.clear();
  3478   NS_ENSURE_TRUE(result, NS_ERROR_DOM_DATA_CLONE_ERR);
  3479   return NS_OK;
  3482 void
  3483 GetHelper::ReleaseMainThreadObjects()
  3485   mKeyRange = nullptr;
  3486   IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
  3487   ObjectStoreHelper::ReleaseMainThreadObjects();
  3490 nsresult
  3491 GetHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
  3493   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3494   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3495   NS_ASSERTION(mKeyRange, "This should never be null!");
  3497   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  3498                              "GetHelper::PackArgumentsForParentProcess "
  3499                              "[IDBObjectStore.cpp]");
  3501   GetParams params;
  3503   mKeyRange->ToSerializedKeyRange(params.keyRange());
  3505   aParams = params;
  3506   return NS_OK;
  3509 AsyncConnectionHelper::ChildProcessSendResult
  3510 GetHelper::SendResponseToChildProcess(nsresult aResultCode)
  3512   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3513   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3515   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  3516                              "GetHelper::SendResponseToChildProcess "
  3517                              "[IDBObjectStore.cpp]");
  3519   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
  3520   NS_ASSERTION(actor, "How did we get this far without an actor?");
  3522   InfallibleTArray<PBlobParent*> blobsParent;
  3524   if (NS_SUCCEEDED(aResultCode)) {
  3525     IDBDatabase* database = mObjectStore->Transaction()->Database();
  3526     NS_ASSERTION(database, "This should never be null!");
  3528     ContentParent* contentParent = database->GetContentParent();
  3529     NS_ASSERTION(contentParent, "This should never be null!");
  3531     FileManager* fileManager = database->Manager();
  3532     NS_ASSERTION(fileManager, "This should never be null!");
  3534     const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
  3536     aResultCode =
  3537       IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
  3538                                            blobsParent);
  3539     if (NS_FAILED(aResultCode)) {
  3540       NS_WARNING("ConvertBlobsToActors failed!");
  3544   ResponseValue response;
  3545   if (NS_FAILED(aResultCode)) {
  3546     response = aResultCode;
  3548   else {
  3549     GetResponse getResponse;
  3550     getResponse.cloneInfo() = mCloneReadInfo;
  3551     getResponse.blobsParent().SwapElements(blobsParent);
  3552     response = getResponse;
  3555   if (!actor->SendResponse(response)) {
  3556     return Error;
  3559   return Success_Sent;
  3562 nsresult
  3563 GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
  3565   NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse,
  3566                "Bad response type!");
  3568   const GetResponse& getResponse = aResponseValue.get_GetResponse();
  3569   const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo();
  3571   NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
  3572                (cloneInfo.dataLength && cloneInfo.data),
  3573                "Inconsistent clone info!");
  3575   if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
  3576     IDB_WARNING("Failed to copy clone buffer!");
  3577     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  3580   IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
  3581                                        mCloneReadInfo.mFiles);
  3582   return NS_OK;
  3585 nsresult
  3586 DeleteHelper::DoDatabaseWork(mozIStorageConnection* /*aConnection */)
  3588   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  3589   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3590   NS_ASSERTION(mKeyRange, "Must have a key range here!");
  3592   PROFILER_LABEL("IndexedDB", "DeleteHelper::DoDatabaseWork");
  3594   nsCString keyRangeClause;
  3595   mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause);
  3597   NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
  3599   nsCString query = NS_LITERAL_CSTRING("DELETE FROM object_data "
  3600                                        "WHERE object_store_id = :osid") +
  3601                     keyRangeClause;
  3603   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
  3604   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3606   mozStorageStatementScoper scoper(stmt);
  3608   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
  3609                                       mObjectStore->Id());
  3610   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3612   rv = mKeyRange->BindToStatement(stmt);
  3613   NS_ENSURE_SUCCESS(rv, rv);
  3615   rv = stmt->Execute();
  3616   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3618   return NS_OK;
  3621 nsresult
  3622 DeleteHelper::GetSuccessResult(JSContext* aCx,
  3623                                JS::MutableHandle<JS::Value> aVal)
  3625   aVal.setUndefined();
  3626   return NS_OK;
  3629 nsresult
  3630 DeleteHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
  3632   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3633   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3634   NS_ASSERTION(mKeyRange, "This should never be null!");
  3636   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  3637                              "DeleteHelper::PackArgumentsForParentProcess");
  3639   DeleteParams params;
  3641   mKeyRange->ToSerializedKeyRange(params.keyRange());
  3643   aParams = params;
  3644   return NS_OK;
  3647 AsyncConnectionHelper::ChildProcessSendResult
  3648 DeleteHelper::SendResponseToChildProcess(nsresult aResultCode)
  3650   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3651   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3653   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  3654                              "DeleteHelper::SendResponseToChildProcess");
  3656   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
  3657   NS_ASSERTION(actor, "How did we get this far without an actor?");
  3659   ResponseValue response;
  3660   if (NS_FAILED(aResultCode)) {
  3661     response = aResultCode;
  3663   else {
  3664     response = DeleteResponse();
  3667   if (!actor->SendResponse(response)) {
  3668     return Error;
  3671   return Success_Sent;
  3674 nsresult
  3675 DeleteHelper::UnpackResponseFromParentProcess(
  3676                                             const ResponseValue& aResponseValue)
  3678   NS_ASSERTION(aResponseValue.type() == ResponseValue::TDeleteResponse,
  3679                "Bad response type!");
  3681   return NS_OK;
  3684 nsresult
  3685 ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
  3687   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  3688   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3689   NS_ASSERTION(aConnection, "Passed a null connection!");
  3691   PROFILER_LABEL("IndexedDB", "ClearHelper::DoDatabaseWork");
  3693   nsCOMPtr<mozIStorageStatement> stmt =
  3694     mTransaction->GetCachedStatement(
  3695       NS_LITERAL_CSTRING("DELETE FROM object_data "
  3696                          "WHERE object_store_id = :osid"));
  3697   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3699   mozStorageStatementScoper scoper(stmt);
  3701   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
  3702                                       mObjectStore->Id());
  3703   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3705   rv = stmt->Execute();
  3706   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3708   return NS_OK;
  3711 nsresult
  3712 ClearHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
  3714   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3715   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3717   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  3718                              "ClearHelper::PackArgumentsForParentProcess");
  3720   aParams = ClearParams();
  3721   return NS_OK;
  3724 AsyncConnectionHelper::ChildProcessSendResult
  3725 ClearHelper::SendResponseToChildProcess(nsresult aResultCode)
  3727   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3728   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3730   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  3731                              "ClearHelper::SendResponseToChildProcess");
  3733   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
  3734   NS_ASSERTION(actor, "How did we get this far without an actor?");
  3736   ResponseValue response;
  3737   if (NS_FAILED(aResultCode)) {
  3738     response = aResultCode;
  3740   else {
  3741     response = ClearResponse();
  3744   if (!actor->SendResponse(response)) {
  3745     return Error;
  3748   return Success_Sent;
  3751 nsresult
  3752 ClearHelper::UnpackResponseFromParentProcess(
  3753                                             const ResponseValue& aResponseValue)
  3755   NS_ASSERTION(aResponseValue.type() == ResponseValue::TClearResponse,
  3756                "Bad response type!");
  3758   return NS_OK;
  3761 nsresult
  3762 OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
  3764   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  3765   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3767   PROFILER_LABEL("IndexedDB",
  3768                  "OpenCursorHelper::DoDatabaseWork [IDBObjectStore.cpp]");
  3770   NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
  3772   nsCString keyRangeClause;
  3773   if (mKeyRange) {
  3774     mKeyRange->GetBindingClause(keyValue, keyRangeClause);
  3777   nsAutoCString directionClause;
  3778   switch (mDirection) {
  3779     case IDBCursor::NEXT:
  3780     case IDBCursor::NEXT_UNIQUE:
  3781       directionClause.AssignLiteral(" ORDER BY key_value ASC");
  3782       break;
  3784     case IDBCursor::PREV:
  3785     case IDBCursor::PREV_UNIQUE:
  3786       directionClause.AssignLiteral(" ORDER BY key_value DESC");
  3787       break;
  3789     default:
  3790       NS_NOTREACHED("Unknown direction type!");
  3793   nsCString firstQuery = NS_LITERAL_CSTRING("SELECT key_value, data, file_ids "
  3794                                             "FROM object_data "
  3795                                             "WHERE object_store_id = :id") +
  3796                          keyRangeClause + directionClause +
  3797                          NS_LITERAL_CSTRING(" LIMIT 1");
  3799   nsCOMPtr<mozIStorageStatement> stmt =
  3800     mTransaction->GetCachedStatement(firstQuery);
  3801   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3803   mozStorageStatementScoper scoper(stmt);
  3805   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
  3806                                       mObjectStore->Id());
  3807   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3809   if (mKeyRange) {
  3810     rv = mKeyRange->BindToStatement(stmt);
  3811     NS_ENSURE_SUCCESS(rv, rv);
  3814   bool hasResult;
  3815   rv = stmt->ExecuteStep(&hasResult);
  3816   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3818   if (!hasResult) {
  3819     mKey.Unset();
  3820     return NS_OK;
  3823   rv = mKey.SetFromStatement(stmt, 0);
  3824   NS_ENSURE_SUCCESS(rv, rv);
  3826   rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 1, 2,
  3827     mDatabase, mCloneReadInfo);
  3828   NS_ENSURE_SUCCESS(rv, rv);
  3830   // Now we need to make the query to get the next match.
  3831   keyRangeClause.Truncate();
  3832   nsAutoCString continueToKeyRangeClause;
  3834   NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
  3835   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
  3837   switch (mDirection) {
  3838     case IDBCursor::NEXT:
  3839     case IDBCursor::NEXT_UNIQUE:
  3840       AppendConditionClause(keyValue, currentKey, false, false,
  3841                             keyRangeClause);
  3842       AppendConditionClause(keyValue, currentKey, false, true,
  3843                             continueToKeyRangeClause);
  3844       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
  3845         AppendConditionClause(keyValue, rangeKey, true,
  3846                               !mKeyRange->IsUpperOpen(), keyRangeClause);
  3847         AppendConditionClause(keyValue, rangeKey, true,
  3848                               !mKeyRange->IsUpperOpen(),
  3849                               continueToKeyRangeClause);
  3850         mRangeKey = mKeyRange->Upper();
  3852       break;
  3854     case IDBCursor::PREV:
  3855     case IDBCursor::PREV_UNIQUE:
  3856       AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause);
  3857       AppendConditionClause(keyValue, currentKey, true, true,
  3858                            continueToKeyRangeClause);
  3859       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
  3860         AppendConditionClause(keyValue, rangeKey, false,
  3861                               !mKeyRange->IsLowerOpen(), keyRangeClause);
  3862         AppendConditionClause(keyValue, rangeKey, false,
  3863                               !mKeyRange->IsLowerOpen(),
  3864                               continueToKeyRangeClause);
  3865         mRangeKey = mKeyRange->Lower();
  3867       break;
  3869     default:
  3870       NS_NOTREACHED("Unknown direction type!");
  3873   NS_NAMED_LITERAL_CSTRING(queryStart, "SELECT key_value, data, file_ids "
  3874                                        "FROM object_data "
  3875                                        "WHERE object_store_id = :id");
  3877   mContinueQuery = queryStart + keyRangeClause + directionClause +
  3878                    NS_LITERAL_CSTRING(" LIMIT ");
  3880   mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause +
  3881                      NS_LITERAL_CSTRING(" LIMIT ");
  3883   return NS_OK;
  3886 nsresult
  3887 OpenCursorHelper::EnsureCursor()
  3889   if (mCursor || mKey.IsUnset()) {
  3890     return NS_OK;
  3893   mSerializedCloneReadInfo = mCloneReadInfo;
  3895   NS_ASSERTION(mSerializedCloneReadInfo.data &&
  3896                mSerializedCloneReadInfo.dataLength,
  3897                "Shouldn't be possible!");
  3899   nsRefPtr<IDBCursor> cursor =
  3900     IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection,
  3901                       mRangeKey, mContinueQuery, mContinueToQuery, mKey,
  3902                       Move(mCloneReadInfo));
  3903   IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3905   NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!");
  3907   mCursor.swap(cursor);
  3908   return NS_OK;
  3911 nsresult
  3912 OpenCursorHelper::GetSuccessResult(JSContext* aCx,
  3913                                    JS::MutableHandle<JS::Value> aVal)
  3915   nsresult rv = EnsureCursor();
  3916   NS_ENSURE_SUCCESS(rv, rv);
  3918   if (mCursor) {
  3919     rv = WrapNative(aCx, mCursor, aVal);
  3920     IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  3922   else {
  3923     aVal.setUndefined();
  3926   return NS_OK;
  3929 void
  3930 OpenCursorHelper::ReleaseMainThreadObjects()
  3932   mKeyRange = nullptr;
  3933   IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
  3935   mCursor = nullptr;
  3937   // These don't need to be released on the main thread but they're only valid
  3938   // as long as mCursor is set.
  3939   mSerializedCloneReadInfo.data = nullptr;
  3940   mSerializedCloneReadInfo.dataLength = 0;
  3942   ObjectStoreHelper::ReleaseMainThreadObjects();
  3945 nsresult
  3946 OpenCursorHelper::PackArgumentsForParentProcess(
  3947                                               ObjectStoreRequestParams& aParams)
  3949   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3950   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3952   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  3953                              "OpenCursorHelper::PackArgumentsForParentProcess "
  3954                              "[IDBObjectStore.cpp]");
  3956   OpenCursorParams params;
  3958   if (mKeyRange) {
  3959     KeyRange keyRange;
  3960     mKeyRange->ToSerializedKeyRange(keyRange);
  3961     params.optionalKeyRange() = keyRange;
  3963   else {
  3964     params.optionalKeyRange() = mozilla::void_t();
  3967   params.direction() = mDirection;
  3969   aParams = params;
  3970   return NS_OK;
  3973 AsyncConnectionHelper::ChildProcessSendResult
  3974 OpenCursorHelper::SendResponseToChildProcess(nsresult aResultCode)
  3976   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  3977   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  3978   NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
  3980   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  3981                              "OpenCursorHelper::SendResponseToChildProcess "
  3982                              "[IDBObjectStore.cpp]");
  3984   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
  3985   NS_ASSERTION(actor, "How did we get this far without an actor?");
  3987   InfallibleTArray<PBlobParent*> blobsParent;
  3989   if (NS_SUCCEEDED(aResultCode)) {
  3990     IDBDatabase* database = mObjectStore->Transaction()->Database();
  3991     NS_ASSERTION(database, "This should never be null!");
  3993     ContentParent* contentParent = database->GetContentParent();
  3994     NS_ASSERTION(contentParent, "This should never be null!");
  3996     FileManager* fileManager = database->Manager();
  3997     NS_ASSERTION(fileManager, "This should never be null!");
  3999     const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
  4001     aResultCode =
  4002       IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
  4003                                            blobsParent);
  4004     if (NS_FAILED(aResultCode)) {
  4005       NS_WARNING("ConvertBlobsToActors failed!");
  4009   if (NS_SUCCEEDED(aResultCode)) {
  4010     nsresult rv = EnsureCursor();
  4011     if (NS_FAILED(rv)) {
  4012       NS_WARNING("EnsureCursor failed!");
  4013       aResultCode = rv;
  4017   ResponseValue response;
  4018   if (NS_FAILED(aResultCode)) {
  4019     response = aResultCode;
  4021   else {
  4022     OpenCursorResponse openCursorResponse;
  4024     if (!mCursor) {
  4025       openCursorResponse = mozilla::void_t();
  4027     else {
  4028       IndexedDBObjectStoreParent* objectStoreActor =
  4029         mObjectStore->GetActorParent();
  4030       NS_ASSERTION(objectStoreActor, "Must have an actor here!");
  4032       IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent();
  4033       NS_ASSERTION(requestActor, "Must have an actor here!");
  4035       NS_ASSERTION(mSerializedCloneReadInfo.data &&
  4036                    mSerializedCloneReadInfo.dataLength,
  4037                    "Shouldn't be possible!");
  4039       ObjectStoreCursorConstructorParams params;
  4040       params.requestParent() = requestActor;
  4041       params.direction() = mDirection;
  4042       params.key() = mKey;
  4043       params.optionalCloneInfo() = mSerializedCloneReadInfo;
  4044       params.blobsParent().SwapElements(blobsParent);
  4046       if (!objectStoreActor->OpenCursor(mCursor, params, openCursorResponse)) {
  4047         return Error;
  4051     response = openCursorResponse;
  4054   if (!actor->SendResponse(response)) {
  4055     return Error;
  4058   return Success_Sent;
  4061 nsresult
  4062 OpenCursorHelper::UnpackResponseFromParentProcess(
  4063                                             const ResponseValue& aResponseValue)
  4065   NS_ASSERTION(aResponseValue.type() == ResponseValue::TOpenCursorResponse,
  4066                "Bad response type!");
  4067   NS_ASSERTION(aResponseValue.get_OpenCursorResponse().type() ==
  4068                OpenCursorResponse::Tvoid_t ||
  4069                aResponseValue.get_OpenCursorResponse().type() ==
  4070                OpenCursorResponse::TPIndexedDBCursorChild,
  4071                "Bad response union type!");
  4072   NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
  4074   const OpenCursorResponse& response =
  4075     aResponseValue.get_OpenCursorResponse();
  4077   switch (response.type()) {
  4078     case OpenCursorResponse::Tvoid_t:
  4079       break;
  4081     case OpenCursorResponse::TPIndexedDBCursorChild: {
  4082       IndexedDBCursorChild* actor =
  4083         static_cast<IndexedDBCursorChild*>(
  4084           response.get_PIndexedDBCursorChild());
  4086       mCursor = actor->ForgetStrongCursor();
  4087       NS_ASSERTION(mCursor, "This should never be null!");
  4089     } break;
  4091     default:
  4092       MOZ_CRASH();
  4095   return NS_OK;
  4098 nsresult
  4099 OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
  4101   MOZ_ASSERT(!NS_IsMainThread());
  4102   MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
  4104   PROFILER_LABEL("IndexedDB",
  4105                  "OpenKeyCursorHelper::DoDatabaseWork [IDBObjectStore.cpp]");
  4107   NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
  4108   NS_NAMED_LITERAL_CSTRING(id, "id");
  4109   NS_NAMED_LITERAL_CSTRING(openLimit, " LIMIT ");
  4111   nsAutoCString queryStart = NS_LITERAL_CSTRING("SELECT ") + keyValue +
  4112                              NS_LITERAL_CSTRING(" FROM object_data WHERE "
  4113                                                 "object_store_id = :") +
  4114                              id;
  4116   nsAutoCString keyRangeClause;
  4117   if (mKeyRange) {
  4118     mKeyRange->GetBindingClause(keyValue, keyRangeClause);
  4121   nsAutoCString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + keyValue;
  4122   switch (mDirection) {
  4123     case IDBCursor::NEXT:
  4124     case IDBCursor::NEXT_UNIQUE:
  4125       directionClause.AppendLiteral(" ASC");
  4126       break;
  4128     case IDBCursor::PREV:
  4129     case IDBCursor::PREV_UNIQUE:
  4130       directionClause.AppendLiteral(" DESC");
  4131       break;
  4133     default:
  4134       MOZ_ASSUME_UNREACHABLE("Unknown direction type!");
  4137   nsCString firstQuery = queryStart + keyRangeClause + directionClause +
  4138                          openLimit + NS_LITERAL_CSTRING("1");
  4140   nsCOMPtr<mozIStorageStatement> stmt =
  4141     mTransaction->GetCachedStatement(firstQuery);
  4142   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4144   mozStorageStatementScoper scoper(stmt);
  4146   nsresult rv = stmt->BindInt64ByName(id, mObjectStore->Id());
  4147   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4149   if (mKeyRange) {
  4150     rv = mKeyRange->BindToStatement(stmt);
  4151     NS_ENSURE_SUCCESS(rv, rv);
  4154   bool hasResult;
  4155   rv = stmt->ExecuteStep(&hasResult);
  4156   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4158   if (!hasResult) {
  4159     mKey.Unset();
  4160     return NS_OK;
  4163   rv = mKey.SetFromStatement(stmt, 0);
  4164   NS_ENSURE_SUCCESS(rv, rv);
  4166   // Now we need to make the query to get the next match.
  4167   keyRangeClause.Truncate();
  4168   nsAutoCString continueToKeyRangeClause;
  4170   NS_NAMED_LITERAL_CSTRING(currentKey, "current_key");
  4171   NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
  4173   switch (mDirection) {
  4174     case IDBCursor::NEXT:
  4175     case IDBCursor::NEXT_UNIQUE:
  4176       AppendConditionClause(keyValue, currentKey, false, false,
  4177                             keyRangeClause);
  4178       AppendConditionClause(keyValue, currentKey, false, true,
  4179                             continueToKeyRangeClause);
  4180       if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
  4181         AppendConditionClause(keyValue, rangeKey, true,
  4182                               !mKeyRange->IsUpperOpen(), keyRangeClause);
  4183         AppendConditionClause(keyValue, rangeKey, true,
  4184                               !mKeyRange->IsUpperOpen(),
  4185                               continueToKeyRangeClause);
  4186         mRangeKey = mKeyRange->Upper();
  4188       break;
  4190     case IDBCursor::PREV:
  4191     case IDBCursor::PREV_UNIQUE:
  4192       AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause);
  4193       AppendConditionClause(keyValue, currentKey, true, true,
  4194                             continueToKeyRangeClause);
  4195       if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
  4196         AppendConditionClause(keyValue, rangeKey, false,
  4197                               !mKeyRange->IsLowerOpen(), keyRangeClause);
  4198         AppendConditionClause(keyValue, rangeKey, false,
  4199                               !mKeyRange->IsLowerOpen(),
  4200                               continueToKeyRangeClause);
  4201         mRangeKey = mKeyRange->Lower();
  4203       break;
  4205     default:
  4206       MOZ_ASSUME_UNREACHABLE("Unknown direction type!");
  4209   mContinueQuery = queryStart + keyRangeClause + directionClause + openLimit;
  4210   mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause +
  4211                      openLimit;
  4213   return NS_OK;
  4216 nsresult
  4217 OpenKeyCursorHelper::EnsureCursor()
  4219   MOZ_ASSERT(NS_IsMainThread());
  4221   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  4222                              "OpenKeyCursorHelper::EnsureCursor "
  4223                              "[IDBObjectStore.cpp]");
  4225   if (mCursor || mKey.IsUnset()) {
  4226     return NS_OK;
  4229   mCursor = IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection,
  4230                               mRangeKey, mContinueQuery, mContinueToQuery,
  4231                               mKey);
  4232   IDB_ENSURE_TRUE(mCursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4234   return NS_OK;
  4237 nsresult
  4238 OpenKeyCursorHelper::GetSuccessResult(JSContext* aCx,
  4239                                       JS::MutableHandle<JS::Value> aVal)
  4241   MOZ_ASSERT(NS_IsMainThread());
  4243   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  4244                              "OpenKeyCursorHelper::GetSuccessResult "
  4245                              "[IDBObjectStore.cpp]");
  4247   nsresult rv = EnsureCursor();
  4248   NS_ENSURE_SUCCESS(rv, rv);
  4250   if (mCursor) {
  4251     rv = WrapNative(aCx, mCursor, aVal);
  4252     IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4254   else {
  4255     aVal.setUndefined();
  4258   return NS_OK;
  4261 void
  4262 OpenKeyCursorHelper::ReleaseMainThreadObjects()
  4264   MOZ_ASSERT(NS_IsMainThread());
  4266   mKeyRange = nullptr;
  4267   mCursor = nullptr;
  4269   ObjectStoreHelper::ReleaseMainThreadObjects();
  4272 nsresult
  4273 OpenKeyCursorHelper::PackArgumentsForParentProcess(
  4274                                               ObjectStoreRequestParams& aParams)
  4276   MOZ_ASSERT(NS_IsMainThread());
  4277   MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
  4279   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  4280                              "OpenKeyCursorHelper::"
  4281                              "PackArgumentsForParentProcess "
  4282                              "[IDBObjectStore.cpp]");
  4284   OpenKeyCursorParams params;
  4286   if (mKeyRange) {
  4287     KeyRange keyRange;
  4288     mKeyRange->ToSerializedKeyRange(keyRange);
  4289     params.optionalKeyRange() = keyRange;
  4291   else {
  4292     params.optionalKeyRange() = mozilla::void_t();
  4295   params.direction() = mDirection;
  4297   aParams = params;
  4298   return NS_OK;
  4301 AsyncConnectionHelper::ChildProcessSendResult
  4302 OpenKeyCursorHelper::SendResponseToChildProcess(nsresult aResultCode)
  4304   MOZ_ASSERT(NS_IsMainThread());
  4305   MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
  4306   MOZ_ASSERT(!mCursor);
  4308   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  4309                              "OpenKeyCursorHelper::SendResponseToChildProcess "
  4310                              "[IDBObjectStore.cpp]");
  4312   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
  4313   MOZ_ASSERT(actor);
  4315   if (NS_SUCCEEDED(aResultCode)) {
  4316     nsresult rv = EnsureCursor();
  4317     if (NS_FAILED(rv)) {
  4318       NS_WARNING("EnsureCursor failed!");
  4319       aResultCode = rv;
  4323   ResponseValue response;
  4324   if (NS_FAILED(aResultCode)) {
  4325     response = aResultCode;
  4326   } else {
  4327     OpenCursorResponse openCursorResponse;
  4329     if (!mCursor) {
  4330       openCursorResponse = mozilla::void_t();
  4332     else {
  4333       IndexedDBObjectStoreParent* objectStoreActor =
  4334         mObjectStore->GetActorParent();
  4335       MOZ_ASSERT(objectStoreActor);
  4337       IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent();
  4338       MOZ_ASSERT(requestActor);
  4340       ObjectStoreCursorConstructorParams params;
  4341       params.requestParent() = requestActor;
  4342       params.direction() = mDirection;
  4343       params.key() = mKey;
  4344       params.optionalCloneInfo() = mozilla::void_t();
  4346       if (!objectStoreActor->OpenCursor(mCursor, params, openCursorResponse)) {
  4347         return Error;
  4351     response = openCursorResponse;
  4354   if (!actor->SendResponse(response)) {
  4355     return Error;
  4358   return Success_Sent;
  4361 nsresult
  4362 OpenKeyCursorHelper::UnpackResponseFromParentProcess(
  4363                                             const ResponseValue& aResponseValue)
  4365   MOZ_ASSERT(NS_IsMainThread());
  4366   MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
  4367   MOZ_ASSERT(aResponseValue.type() == ResponseValue::TOpenCursorResponse);
  4368   MOZ_ASSERT(aResponseValue.get_OpenCursorResponse().type() ==
  4369                OpenCursorResponse::Tvoid_t ||
  4370              aResponseValue.get_OpenCursorResponse().type() ==
  4371                OpenCursorResponse::TPIndexedDBCursorChild);
  4372   MOZ_ASSERT(!mCursor);
  4374   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  4375                              "OpenKeyCursorHelper::"
  4376                              "UnpackResponseFromParentProcess "
  4377                              "[IDBObjectStore.cpp]");
  4379   const OpenCursorResponse& response =
  4380     aResponseValue.get_OpenCursorResponse();
  4382   switch (response.type()) {
  4383     case OpenCursorResponse::Tvoid_t:
  4384       break;
  4386     case OpenCursorResponse::TPIndexedDBCursorChild: {
  4387       IndexedDBCursorChild* actor =
  4388         static_cast<IndexedDBCursorChild*>(
  4389           response.get_PIndexedDBCursorChild());
  4391       mCursor = actor->ForgetStrongCursor();
  4392       NS_ASSERTION(mCursor, "This should never be null!");
  4394     } break;
  4396     default:
  4397       MOZ_CRASH("Unknown response union type!");
  4400   return NS_OK;
  4403 nsresult
  4404 CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
  4406   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  4407   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  4409   PROFILER_LABEL("IndexedDB", "CreateIndexHelper::DoDatabaseWork");
  4411   if (IndexedDatabaseManager::InLowDiskSpaceMode()) {
  4412     NS_WARNING("Refusing to create index because disk space is low!");
  4413     return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR;
  4416   // Insert the data into the database.
  4417   nsCOMPtr<mozIStorageStatement> stmt =
  4418     mTransaction->GetCachedStatement(
  4419     "INSERT INTO object_store_index (id, name, key_path, unique_index, "
  4420       "multientry, object_store_id) "
  4421     "VALUES (:id, :name, :key_path, :unique, :multientry, :osid)"
  4422   );
  4423   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4425   mozStorageStatementScoper scoper(stmt);
  4427   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"),
  4428                                       mIndex->Id());
  4429   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4431   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mIndex->Name());
  4432   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4434   nsAutoString keyPathSerialization;
  4435   mIndex->GetKeyPath().SerializeToString(keyPathSerialization);
  4436   rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"),
  4437                               keyPathSerialization);
  4438   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4440   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("unique"),
  4441                              mIndex->IsUnique() ? 1 : 0);
  4442   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4444   rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("multientry"),
  4445                              mIndex->IsMultiEntry() ? 1 : 0);
  4446   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4448   rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
  4449                              mIndex->ObjectStore()->Id());
  4450   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4452   if (NS_FAILED(stmt->Execute())) {
  4453     return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR;
  4456 #ifdef DEBUG
  4458     int64_t id;
  4459     aConnection->GetLastInsertRowID(&id);
  4460     NS_ASSERTION(mIndex->Id() == id, "Bad index id!");
  4462 #endif
  4464   // Now we need to populate the index with data from the object store.
  4465   rv = InsertDataFromObjectStore(aConnection);
  4466   if (NS_FAILED(rv)) {
  4467     return rv;
  4470   return NS_OK;
  4473 void
  4474 CreateIndexHelper::ReleaseMainThreadObjects()
  4476   mIndex = nullptr;
  4477   NoRequestObjectStoreHelper::ReleaseMainThreadObjects();
  4480 nsresult
  4481 CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection)
  4483   nsCOMPtr<mozIStorageStatement> stmt =
  4484     mTransaction->GetCachedStatement(
  4485       NS_LITERAL_CSTRING("SELECT id, data, file_ids, key_value FROM "
  4486                          "object_data WHERE object_store_id = :osid"));
  4487   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4489   mozStorageStatementScoper scoper(stmt);
  4491   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
  4492                                       mIndex->ObjectStore()->Id());
  4493   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4495   IDB_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, 
  4496                                     NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4498   bool hasResult;
  4499   rv = stmt->ExecuteStep(&hasResult);
  4500   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4501   if (!hasResult) {
  4502     // Bail early if we have no data to avoid creating the below runtime
  4503     return NS_OK;
  4506   ThreadLocalJSRuntime* tlsEntry =
  4507     reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex));
  4509   if (!tlsEntry) {
  4510     tlsEntry = ThreadLocalJSRuntime::Create();
  4511     IDB_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4513     PR_SetThreadPrivate(sTLSIndex, tlsEntry);
  4516   JSContext* cx = tlsEntry->Context();
  4517   JSAutoRequest ar(cx);
  4518   JSAutoCompartment ac(cx, tlsEntry->Global());
  4520   do {
  4521     StructuredCloneReadInfo cloneReadInfo;
  4522     rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 1, 2,
  4523       mDatabase, cloneReadInfo);
  4524     NS_ENSURE_SUCCESS(rv, rv);
  4526     JSAutoStructuredCloneBuffer& buffer = cloneReadInfo.mCloneBuffer;
  4528     JSStructuredCloneCallbacks callbacks = {
  4529       IDBObjectStore::StructuredCloneReadCallback<CreateIndexDeserializationTraits>,
  4530       nullptr,
  4531       nullptr,
  4532       nullptr,
  4533       nullptr,
  4534       nullptr
  4535     };
  4537     JS::Rooted<JS::Value> clone(cx);
  4538     if (!buffer.read(cx, &clone, &callbacks, &cloneReadInfo)) {
  4539       NS_WARNING("Failed to deserialize structured clone data!");
  4540       return NS_ERROR_DOM_DATA_CLONE_ERR;
  4543     nsTArray<IndexUpdateInfo> updateInfo;
  4544     rv = IDBObjectStore::AppendIndexUpdateInfo(mIndex->Id(),
  4545                                                mIndex->GetKeyPath(),
  4546                                                mIndex->IsUnique(),
  4547                                                mIndex->IsMultiEntry(),
  4548                                                tlsEntry->Context(),
  4549                                                clone, updateInfo);
  4550     NS_ENSURE_SUCCESS(rv, rv);
  4552     int64_t objectDataID = stmt->AsInt64(0);
  4554     Key key;
  4555     rv = key.SetFromStatement(stmt, 3);
  4556     NS_ENSURE_SUCCESS(rv, rv);
  4558     rv = IDBObjectStore::UpdateIndexes(mTransaction, mIndex->Id(),
  4559                                        key, false, objectDataID, updateInfo);
  4560     NS_ENSURE_SUCCESS(rv, rv);
  4562   } while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult);
  4563   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4565   return NS_OK;
  4568 void
  4569 CreateIndexHelper::DestroyTLSEntry(void* aPtr)
  4571   delete reinterpret_cast<ThreadLocalJSRuntime *>(aPtr);
  4574 nsresult
  4575 DeleteIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
  4577   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  4578   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  4580   PROFILER_LABEL("IndexedDB", "DeleteIndexHelper::DoDatabaseWork");
  4582   nsCOMPtr<mozIStorageStatement> stmt =
  4583     mTransaction->GetCachedStatement(
  4584       "DELETE FROM object_store_index "
  4585       "WHERE name = :name "
  4586     );
  4587   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4589   mozStorageStatementScoper scoper(stmt);
  4591   nsresult rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mName);
  4592   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4594   if (NS_FAILED(stmt->Execute())) {
  4595     return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR;
  4598   return NS_OK;
  4601 nsresult
  4602 GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
  4604   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  4605   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  4607   PROFILER_LABEL("IndexedDB",
  4608                  "GetAllHelper::DoDatabaseWork [IDBObjectStore.cpp]");
  4610   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
  4611   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
  4613   nsAutoCString keyRangeClause;
  4614   if (mKeyRange) {
  4615     if (!mKeyRange->Lower().IsUnset()) {
  4616       keyRangeClause = NS_LITERAL_CSTRING(" AND key_value");
  4617       if (mKeyRange->IsLowerOpen()) {
  4618         keyRangeClause.AppendLiteral(" > :");
  4620       else {
  4621         keyRangeClause.AppendLiteral(" >= :");
  4623       keyRangeClause.Append(lowerKeyName);
  4626     if (!mKeyRange->Upper().IsUnset()) {
  4627       keyRangeClause += NS_LITERAL_CSTRING(" AND key_value");
  4628       if (mKeyRange->IsUpperOpen()) {
  4629         keyRangeClause.AppendLiteral(" < :");
  4631       else {
  4632         keyRangeClause.AppendLiteral(" <= :");
  4634       keyRangeClause.Append(upperKeyName);
  4638   nsAutoCString limitClause;
  4639   if (mLimit != UINT32_MAX) {
  4640     limitClause.AssignLiteral(" LIMIT ");
  4641     limitClause.AppendInt(mLimit);
  4644   nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
  4645                                        "WHERE object_store_id = :osid") +
  4646                     keyRangeClause +
  4647                     NS_LITERAL_CSTRING(" ORDER BY key_value ASC") +
  4648                     limitClause;
  4650   mCloneReadInfos.SetCapacity(50);
  4652   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
  4653   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4655   mozStorageStatementScoper scoper(stmt);
  4657   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
  4658                                       mObjectStore->Id());
  4659   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4661   if (mKeyRange) {
  4662     if (!mKeyRange->Lower().IsUnset()) {
  4663       rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
  4664       NS_ENSURE_SUCCESS(rv, rv);
  4666     if (!mKeyRange->Upper().IsUnset()) {
  4667       rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
  4668       NS_ENSURE_SUCCESS(rv, rv);
  4672   bool hasResult;
  4673   while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
  4674     if (mCloneReadInfos.Capacity() == mCloneReadInfos.Length()) {
  4675       mCloneReadInfos.SetCapacity(mCloneReadInfos.Capacity() * 2);
  4678     StructuredCloneReadInfo* readInfo = mCloneReadInfos.AppendElement();
  4679     NS_ASSERTION(readInfo, "Shouldn't fail since SetCapacity succeeded!");
  4681     rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
  4682       mDatabase, *readInfo);
  4683     NS_ENSURE_SUCCESS(rv, rv);
  4685   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4687   return NS_OK;
  4690 nsresult
  4691 GetAllHelper::GetSuccessResult(JSContext* aCx,
  4692                                JS::MutableHandle<JS::Value> aVal)
  4694   NS_ASSERTION(mCloneReadInfos.Length() <= mLimit, "Too many results!");
  4696   nsresult rv = ConvertToArrayAndCleanup(aCx, mCloneReadInfos, aVal);
  4698   NS_ASSERTION(mCloneReadInfos.IsEmpty(),
  4699                "Should have cleared in ConvertToArrayAndCleanup");
  4700   NS_ENSURE_SUCCESS(rv, rv);
  4702   return NS_OK;
  4705 void
  4706 GetAllHelper::ReleaseMainThreadObjects()
  4708   mKeyRange = nullptr;
  4709   for (uint32_t index = 0; index < mCloneReadInfos.Length(); index++) {
  4710     IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos[index]);
  4712   ObjectStoreHelper::ReleaseMainThreadObjects();
  4715 nsresult
  4716 GetAllHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
  4718   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  4719   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  4721   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  4722                              "GetAllHelper::PackArgumentsForParentProcess "
  4723                              "[IDBObjectStore.cpp]");
  4725   GetAllParams params;
  4727   if (mKeyRange) {
  4728     KeyRange keyRange;
  4729     mKeyRange->ToSerializedKeyRange(keyRange);
  4730     params.optionalKeyRange() = keyRange;
  4732   else {
  4733     params.optionalKeyRange() = mozilla::void_t();
  4736   params.limit() = mLimit;
  4738   aParams = params;
  4739   return NS_OK;
  4742 AsyncConnectionHelper::ChildProcessSendResult
  4743 GetAllHelper::SendResponseToChildProcess(nsresult aResultCode)
  4745   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  4746   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  4748   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  4749                              "GetAllHelper::SendResponseToChildProcess "
  4750                              "[IDBObjectStore.cpp]");
  4752   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
  4753   NS_ASSERTION(actor, "How did we get this far without an actor?");
  4755   GetAllResponse getAllResponse;
  4756   if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) {
  4757     IDBDatabase* database = mObjectStore->Transaction()->Database();
  4758     NS_ASSERTION(database, "This should never be null!");
  4760     ContentParent* contentParent = database->GetContentParent();
  4761     NS_ASSERTION(contentParent, "This should never be null!");
  4763     FileManager* fileManager = database->Manager();
  4764     NS_ASSERTION(fileManager, "This should never be null!");
  4766     uint32_t length = mCloneReadInfos.Length();
  4768     InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
  4769       getAllResponse.cloneInfos();
  4770     infos.SetCapacity(length);
  4772     InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
  4773     blobArrays.SetCapacity(length);
  4775     for (uint32_t index = 0;
  4776          NS_SUCCEEDED(aResultCode) && index < length;
  4777          index++) {
  4778       // Append the structured clone data.
  4779       const StructuredCloneReadInfo& clone = mCloneReadInfos[index];
  4780       SerializedStructuredCloneReadInfo* info = infos.AppendElement();
  4781       *info = clone;
  4783       // Now take care of the files.
  4784       const nsTArray<StructuredCloneFile>& files = clone.mFiles;
  4785       BlobArray* blobArray = blobArrays.AppendElement();
  4786       InfallibleTArray<PBlobParent*>& blobs = blobArray->blobsParent();
  4788       aResultCode =
  4789         IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
  4790                                              blobs);
  4791       if (NS_FAILED(aResultCode)) {
  4792         NS_WARNING("ConvertBlobsToActors failed!");
  4793         break;
  4798   ResponseValue response;
  4799   if (NS_FAILED(aResultCode)) {
  4800     response = aResultCode;
  4802   else {
  4803     response = getAllResponse;
  4806   if (!actor->SendResponse(response)) {
  4807     return Error;
  4810   return Success_Sent;
  4813 nsresult
  4814 GetAllHelper::UnpackResponseFromParentProcess(
  4815                                             const ResponseValue& aResponseValue)
  4817   NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse,
  4818                "Bad response type!");
  4820   const GetAllResponse& getAllResponse = aResponseValue.get_GetAllResponse();
  4821   const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
  4822     getAllResponse.cloneInfos();
  4823   const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
  4825   mCloneReadInfos.SetCapacity(cloneInfos.Length());
  4827   for (uint32_t index = 0; index < cloneInfos.Length(); index++) {
  4828     const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
  4829     const InfallibleTArray<PBlobChild*>& blobs = blobArrays[index].blobsChild();
  4831     StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
  4832     if (!destInfo->SetFromSerialized(srcInfo)) {
  4833       IDB_WARNING("Failed to copy clone buffer!");
  4834       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  4837     IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
  4840   return NS_OK;
  4843 nsresult
  4844 GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
  4846   MOZ_ASSERT(!NS_IsMainThread());
  4847   MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
  4849   PROFILER_LABEL("IndexedDB",
  4850                  "GetAllKeysHelper::DoDatabaseWork [IDObjectStore.cpp]");
  4852   NS_NAMED_LITERAL_CSTRING(keyValue, "key_value");
  4854   nsAutoCString keyRangeClause;
  4855   if (mKeyRange) {
  4856     mKeyRange->GetBindingClause(keyValue, keyRangeClause);
  4859   nsAutoCString limitClause;
  4860   if (mLimit != UINT32_MAX) {
  4861     limitClause = NS_LITERAL_CSTRING(" LIMIT ");
  4862     limitClause.AppendInt(mLimit);
  4865   NS_NAMED_LITERAL_CSTRING(osid, "osid");
  4867   nsCString query = NS_LITERAL_CSTRING("SELECT ") + keyValue +
  4868                     NS_LITERAL_CSTRING(" FROM object_data WHERE "
  4869                                        "object_store_id = :") +
  4870                     osid + keyRangeClause +
  4871                     NS_LITERAL_CSTRING(" ORDER BY key_value ASC") +
  4872                     limitClause;
  4874   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
  4875   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4877   mozStorageStatementScoper scoper(stmt);
  4879   nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id());
  4880   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4882   if (mKeyRange) {
  4883     rv = mKeyRange->BindToStatement(stmt);
  4884     NS_ENSURE_SUCCESS(rv, rv);
  4887   mKeys.SetCapacity(std::min<uint32_t>(50, mLimit));
  4889   bool hasResult;
  4890   while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
  4891     if (mKeys.Capacity() == mKeys.Length()) {
  4892       mKeys.SetCapacity(mKeys.Capacity() * 2);
  4895     Key* key = mKeys.AppendElement();
  4896     NS_ASSERTION(key, "This shouldn't fail!");
  4898     rv = key->SetFromStatement(stmt, 0);
  4899     NS_ENSURE_SUCCESS(rv, rv);
  4901   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  4903   return NS_OK;
  4906 nsresult
  4907 GetAllKeysHelper::GetSuccessResult(JSContext* aCx,
  4908                                    JS::MutableHandle<JS::Value> aVal)
  4910   MOZ_ASSERT(NS_IsMainThread());
  4911   MOZ_ASSERT(mKeys.Length() <= mLimit);
  4913   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  4914                              "GetAllKeysHelper::GetSuccessResult "
  4915                              "[IDBObjectStore.cpp]");
  4917   nsTArray<Key> keys;
  4918   mKeys.SwapElements(keys);
  4920   JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
  4921   if (!array) {
  4922     IDB_WARNING("Failed to make array!");
  4923     return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  4926   if (!keys.IsEmpty()) {
  4927     if (!JS_SetArrayLength(aCx, array, keys.Length())) {
  4928       IDB_WARNING("Failed to set array length!");
  4929       return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  4932     for (uint32_t index = 0, count = keys.Length(); index < count; index++) {
  4933       const Key& key = keys[index];
  4934       MOZ_ASSERT(!key.IsUnset());
  4936       JS::Rooted<JS::Value> value(aCx);
  4937       nsresult rv = key.ToJSVal(aCx, &value);
  4938       if (NS_FAILED(rv)) {
  4939         NS_WARNING("Failed to get jsval for key!");
  4940         return rv;
  4943       if (!JS_SetElement(aCx, array, index, value)) {
  4944         IDB_WARNING("Failed to set array element!");
  4945         return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  4950   aVal.setObject(*array);
  4951   return NS_OK;
  4954 void
  4955 GetAllKeysHelper::ReleaseMainThreadObjects()
  4957   MOZ_ASSERT(NS_IsMainThread());
  4959   mKeyRange = nullptr;
  4961   ObjectStoreHelper::ReleaseMainThreadObjects();
  4964 nsresult
  4965 GetAllKeysHelper::PackArgumentsForParentProcess(
  4966                                               ObjectStoreRequestParams& aParams)
  4968   MOZ_ASSERT(NS_IsMainThread());
  4969   MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
  4971   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  4972                              "GetAllKeysHelper::PackArgumentsForParentProcess "
  4973                              "[IDBObjectStore.cpp]");
  4975   GetAllKeysParams params;
  4977   if (mKeyRange) {
  4978     KeyRange keyRange;
  4979     mKeyRange->ToSerializedKeyRange(keyRange);
  4980     params.optionalKeyRange() = keyRange;
  4981   } else {
  4982     params.optionalKeyRange() = mozilla::void_t();
  4985   params.limit() = mLimit;
  4987   aParams = params;
  4988   return NS_OK;
  4991 AsyncConnectionHelper::ChildProcessSendResult
  4992 GetAllKeysHelper::SendResponseToChildProcess(nsresult aResultCode)
  4994   MOZ_ASSERT(NS_IsMainThread());
  4995   MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
  4997   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  4998                              "GetAllKeysHelper::SendResponseToChildProcess "
  4999                              "[IDBObjectStore.cpp]");
  5001   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
  5002   MOZ_ASSERT(actor);
  5004   ResponseValue response;
  5005   if (NS_FAILED(aResultCode)) {
  5006     response = aResultCode;
  5008   else {
  5009     GetAllKeysResponse getAllKeysResponse;
  5010     getAllKeysResponse.keys().AppendElements(mKeys);
  5011     response = getAllKeysResponse;
  5014   if (!actor->SendResponse(response)) {
  5015     return Error;
  5018   return Success_Sent;
  5021 nsresult
  5022 GetAllKeysHelper::UnpackResponseFromParentProcess(
  5023                                             const ResponseValue& aResponseValue)
  5025   MOZ_ASSERT(NS_IsMainThread());
  5026   MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
  5027   MOZ_ASSERT(aResponseValue.type() == ResponseValue::TGetAllKeysResponse);
  5029   mKeys.AppendElements(aResponseValue.get_GetAllKeysResponse().keys());
  5030   return NS_OK;
  5033 nsresult
  5034 CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
  5036   NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  5037   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  5039   PROFILER_LABEL("IndexedDB",
  5040                  "CountHelper::DoDatabaseWork [IDBObjectStore.cpp]");
  5042   NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
  5043   NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
  5045   nsAutoCString keyRangeClause;
  5046   if (mKeyRange) {
  5047     if (!mKeyRange->Lower().IsUnset()) {
  5048       keyRangeClause = NS_LITERAL_CSTRING(" AND key_value");
  5049       if (mKeyRange->IsLowerOpen()) {
  5050         keyRangeClause.AppendLiteral(" > :");
  5052       else {
  5053         keyRangeClause.AppendLiteral(" >= :");
  5055       keyRangeClause.Append(lowerKeyName);
  5058     if (!mKeyRange->Upper().IsUnset()) {
  5059       keyRangeClause += NS_LITERAL_CSTRING(" AND key_value");
  5060       if (mKeyRange->IsUpperOpen()) {
  5061         keyRangeClause.AppendLiteral(" < :");
  5063       else {
  5064         keyRangeClause.AppendLiteral(" <= :");
  5066       keyRangeClause.Append(upperKeyName);
  5070   nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM object_data "
  5071                                        "WHERE object_store_id = :osid") +
  5072                     keyRangeClause;
  5074   nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
  5075   IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  5077   mozStorageStatementScoper scoper(stmt);
  5079   nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"),
  5080                                       mObjectStore->Id());
  5081   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  5083   if (mKeyRange) {
  5084     if (!mKeyRange->Lower().IsUnset()) {
  5085       rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
  5086       NS_ENSURE_SUCCESS(rv, rv);
  5088     if (!mKeyRange->Upper().IsUnset()) {
  5089       rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
  5090       NS_ENSURE_SUCCESS(rv, rv);
  5094   bool hasResult;
  5095   rv = stmt->ExecuteStep(&hasResult);
  5096   IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  5097   IDB_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  5099   mCount = stmt->AsInt64(0);
  5100   return NS_OK;
  5103 nsresult
  5104 CountHelper::GetSuccessResult(JSContext* aCx,
  5105                               JS::MutableHandle<JS::Value> aVal)
  5107   aVal.setNumber(static_cast<double>(mCount));
  5108   return NS_OK;
  5111 void
  5112 CountHelper::ReleaseMainThreadObjects()
  5114   mKeyRange = nullptr;
  5115   ObjectStoreHelper::ReleaseMainThreadObjects();
  5118 nsresult
  5119 CountHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams)
  5121   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  5122   NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  5124   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  5125                              "CountHelper::PackArgumentsForParentProcess "
  5126                              "[IDBObjectStore.cpp]");
  5128   CountParams params;
  5130   if (mKeyRange) {
  5131     KeyRange keyRange;
  5132     mKeyRange->ToSerializedKeyRange(keyRange);
  5133     params.optionalKeyRange() = keyRange;
  5135   else {
  5136     params.optionalKeyRange() = mozilla::void_t();
  5139   aParams = params;
  5140   return NS_OK;
  5143 AsyncConnectionHelper::ChildProcessSendResult
  5144 CountHelper::SendResponseToChildProcess(nsresult aResultCode)
  5146   NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  5147   NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  5149   PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  5150                              "CountHelper::SendResponseToChildProcess "
  5151                              "[IDBObjectStore.cpp]");
  5153   IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
  5154   NS_ASSERTION(actor, "How did we get this far without an actor?");
  5156   ResponseValue response;
  5157   if (NS_FAILED(aResultCode)) {
  5158     response = aResultCode;
  5160   else {
  5161     CountResponse countResponse = mCount;
  5162     response = countResponse;
  5165   if (!actor->SendResponse(response)) {
  5166     return Error;
  5169   return Success_Sent;
  5172 nsresult
  5173 CountHelper::UnpackResponseFromParentProcess(
  5174                                             const ResponseValue& aResponseValue)
  5176   NS_ASSERTION(aResponseValue.type() == ResponseValue::TCountResponse,
  5177                "Bad response type!");
  5179   mCount = aResponseValue.get_CountResponse().count();
  5180   return NS_OK;

mercurial