dom/indexedDB/IDBCursor.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

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

mercurial