dom/indexedDB/IDBCursor.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/dom/indexedDB/IDBCursor.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1347 @@
     1.4 +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* vim: set ts=2 et sw=2 tw=80: */
     1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.9 +
    1.10 +#include "base/basictypes.h"
    1.11 +
    1.12 +#include "IDBCursor.h"
    1.13 +
    1.14 +#include "mozilla/storage.h"
    1.15 +#include "nsComponentManagerUtils.h"
    1.16 +#include "nsJSUtils.h"
    1.17 +#include "nsThreadUtils.h"
    1.18 +
    1.19 +#include "AsyncConnectionHelper.h"
    1.20 +#include "IDBEvents.h"
    1.21 +#include "IDBIndex.h"
    1.22 +#include "IDBObjectStore.h"
    1.23 +#include "IDBTransaction.h"
    1.24 +#include "ProfilerHelpers.h"
    1.25 +#include "ReportInternalError.h"
    1.26 +#include "TransactionThreadPool.h"
    1.27 +
    1.28 +#include "ipc/IndexedDBChild.h"
    1.29 +#include "ipc/IndexedDBParent.h"
    1.30 +
    1.31 +#include "IndexedDatabaseInlines.h"
    1.32 +#include "mozilla/dom/BindingDeclarations.h"
    1.33 +#include "mozilla/dom/UnionTypes.h"
    1.34 +
    1.35 +USING_INDEXEDDB_NAMESPACE
    1.36 +using namespace mozilla::dom::indexedDB::ipc;
    1.37 +using mozilla::dom::Optional;
    1.38 +using mozilla::dom::OwningIDBObjectStoreOrIDBIndex;
    1.39 +using mozilla::ErrorResult;
    1.40 +
    1.41 +static_assert(sizeof(size_t) >= sizeof(IDBCursor::Direction),
    1.42 +              "Relying on conversion between size_t and IDBCursor::Direction");
    1.43 +
    1.44 +namespace {
    1.45 +
    1.46 +class CursorHelper : public AsyncConnectionHelper
    1.47 +{
    1.48 +public:
    1.49 +  CursorHelper(IDBCursor* aCursor)
    1.50 +  : AsyncConnectionHelper(aCursor->Transaction(), aCursor->Request()),
    1.51 +    mCursor(aCursor), mActor(nullptr)
    1.52 +  {
    1.53 +    NS_ASSERTION(aCursor, "Null cursor!");
    1.54 +  }
    1.55 +
    1.56 +  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
    1.57 +
    1.58 +  virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread) MOZ_OVERRIDE;
    1.59 +
    1.60 +  virtual nsresult
    1.61 +  PackArgumentsForParentProcess(CursorRequestParams& aParams) = 0;
    1.62 +
    1.63 +  virtual nsresult
    1.64 +  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0;
    1.65 +
    1.66 +protected:
    1.67 +  virtual ~CursorHelper()
    1.68 +  { }
    1.69 +
    1.70 +  nsRefPtr<IDBCursor> mCursor;
    1.71 +
    1.72 +private:
    1.73 +  IndexedDBCursorRequestChild* mActor;
    1.74 +};
    1.75 +
    1.76 +} // anonymous namespace
    1.77 +
    1.78 +BEGIN_INDEXEDDB_NAMESPACE
    1.79 +
    1.80 +class ContinueHelper : public CursorHelper
    1.81 +{
    1.82 +public:
    1.83 +  ContinueHelper(IDBCursor* aCursor,
    1.84 +                 int32_t aCount)
    1.85 +  : CursorHelper(aCursor), mCount(aCount)
    1.86 +  {
    1.87 +    MOZ_ASSERT(NS_IsMainThread());
    1.88 +    MOZ_ASSERT(aCursor);
    1.89 +    MOZ_ASSERT(aCount > 0);
    1.90 +  }
    1.91 +
    1.92 +  virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
    1.93 +                                  MOZ_OVERRIDE;
    1.94 +
    1.95 +  virtual nsresult GetSuccessResult(JSContext* aCx,
    1.96 +                                    JS::MutableHandle<JS::Value> aVal)
    1.97 +                                    MOZ_OVERRIDE;
    1.98 +
    1.99 +  virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
   1.100 +
   1.101 +  virtual nsresult
   1.102 +  PackArgumentsForParentProcess(CursorRequestParams& aParams) MOZ_OVERRIDE;
   1.103 +
   1.104 +  virtual ChildProcessSendResult
   1.105 +  SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
   1.106 +
   1.107 +  virtual nsresult
   1.108 +  UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
   1.109 +                                  MOZ_OVERRIDE;
   1.110 +
   1.111 +protected:
   1.112 +  virtual ~ContinueHelper()
   1.113 +  {
   1.114 +    IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
   1.115 +  }
   1.116 +
   1.117 +  virtual nsresult
   1.118 +  BindArgumentsToStatement(mozIStorageStatement* aStatement) = 0;
   1.119 +
   1.120 +  virtual nsresult
   1.121 +  GatherResultsFromStatement(mozIStorageStatement* aStatement) = 0;
   1.122 +
   1.123 +  void UpdateCursorState()
   1.124 +  {
   1.125 +    mCursor->mCachedKey = JSVAL_VOID;
   1.126 +    mCursor->mCachedPrimaryKey = JSVAL_VOID;
   1.127 +    mCursor->mCachedValue = JSVAL_VOID;
   1.128 +    mCursor->mHaveCachedKey = false;
   1.129 +    mCursor->mHaveCachedPrimaryKey = false;
   1.130 +    mCursor->mHaveCachedValue = false;
   1.131 +    mCursor->mContinueCalled = false;
   1.132 +
   1.133 +    if (mKey.IsUnset()) {
   1.134 +      mCursor->mHaveValue = false;
   1.135 +    } else {
   1.136 +      MOZ_ASSERT(mCursor->mType == IDBCursor::OBJECTSTORE ||
   1.137 +                 mCursor->mType == IDBCursor::OBJECTSTOREKEY ||
   1.138 +                 !mObjectKey.IsUnset());
   1.139 +
   1.140 +      // Set new values.
   1.141 +      mCursor->mKey = mKey;
   1.142 +      mCursor->mObjectKey = mObjectKey;
   1.143 +      mCursor->mContinueToKey.Unset();
   1.144 +
   1.145 +      mCursor->mCloneReadInfo = Move(mCloneReadInfo);
   1.146 +      mCloneReadInfo.mCloneBuffer.clear();
   1.147 +    }
   1.148 +  }
   1.149 +
   1.150 +  int32_t mCount;
   1.151 +  Key mKey;
   1.152 +  Key mObjectKey;
   1.153 +  StructuredCloneReadInfo mCloneReadInfo;
   1.154 +};
   1.155 +
   1.156 +class ContinueObjectStoreHelper : public ContinueHelper
   1.157 +{
   1.158 +public:
   1.159 +  ContinueObjectStoreHelper(IDBCursor* aCursor,
   1.160 +                            uint32_t aCount)
   1.161 +  : ContinueHelper(aCursor, aCount)
   1.162 +  { }
   1.163 +
   1.164 +protected:
   1.165 +  virtual ~ContinueObjectStoreHelper()
   1.166 +  { }
   1.167 +
   1.168 +private:
   1.169 +  nsresult BindArgumentsToStatement(mozIStorageStatement* aStatement);
   1.170 +  nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
   1.171 +};
   1.172 +
   1.173 +class ContinueObjectStoreKeyHelper : public ContinueObjectStoreHelper
   1.174 +{
   1.175 +public:
   1.176 +  ContinueObjectStoreKeyHelper(IDBCursor* aCursor,
   1.177 +                               uint32_t aCount)
   1.178 +  : ContinueObjectStoreHelper(aCursor, aCount)
   1.179 +  { }
   1.180 +
   1.181 +private:
   1.182 +  virtual ~ContinueObjectStoreKeyHelper()
   1.183 +  { }
   1.184 +
   1.185 +  virtual nsresult
   1.186 +  GatherResultsFromStatement(mozIStorageStatement* aStatement) MOZ_OVERRIDE;
   1.187 +};
   1.188 +
   1.189 +class ContinueIndexHelper : public ContinueHelper
   1.190 +{
   1.191 +public:
   1.192 +  ContinueIndexHelper(IDBCursor* aCursor,
   1.193 +                      uint32_t aCount)
   1.194 +  : ContinueHelper(aCursor, aCount)
   1.195 +  { }
   1.196 +
   1.197 +protected:
   1.198 +  virtual ~ContinueIndexHelper()
   1.199 +  { }
   1.200 +
   1.201 +private:
   1.202 +  nsresult BindArgumentsToStatement(mozIStorageStatement* aStatement);
   1.203 +  nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
   1.204 +};
   1.205 +
   1.206 +class ContinueIndexObjectHelper : public ContinueIndexHelper
   1.207 +{
   1.208 +public:
   1.209 +  ContinueIndexObjectHelper(IDBCursor* aCursor,
   1.210 +                            uint32_t aCount)
   1.211 +  : ContinueIndexHelper(aCursor, aCount)
   1.212 +  { }
   1.213 +
   1.214 +private:
   1.215 +  virtual ~ContinueIndexObjectHelper()
   1.216 +  { }
   1.217 +
   1.218 +  nsresult GatherResultsFromStatement(mozIStorageStatement* aStatement);
   1.219 +};
   1.220 +
   1.221 +END_INDEXEDDB_NAMESPACE
   1.222 +
   1.223 +// static
   1.224 +already_AddRefed<IDBCursor>
   1.225 +IDBCursor::Create(IDBRequest* aRequest,
   1.226 +                  IDBTransaction* aTransaction,
   1.227 +                  IDBObjectStore* aObjectStore,
   1.228 +                  Direction aDirection,
   1.229 +                  const Key& aRangeKey,
   1.230 +                  const nsACString& aContinueQuery,
   1.231 +                  const nsACString& aContinueToQuery,
   1.232 +                  const Key& aKey,
   1.233 +                  StructuredCloneReadInfo&& aCloneReadInfo)
   1.234 +{
   1.235 +  NS_ASSERTION(aObjectStore, "Null pointer!");
   1.236 +  NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
   1.237 +
   1.238 +  nsRefPtr<IDBCursor> cursor =
   1.239 +    IDBCursor::CreateCommon(aRequest, aTransaction, aObjectStore, aDirection,
   1.240 +                            aRangeKey, aContinueQuery, aContinueToQuery);
   1.241 +  NS_ASSERTION(cursor, "This shouldn't fail!");
   1.242 +
   1.243 +  cursor->mObjectStore = aObjectStore;
   1.244 +  cursor->mType = OBJECTSTORE;
   1.245 +  cursor->mKey = aKey;
   1.246 +  cursor->mCloneReadInfo = Move(aCloneReadInfo);
   1.247 +
   1.248 +  return cursor.forget();
   1.249 +}
   1.250 +
   1.251 +// static
   1.252 +already_AddRefed<IDBCursor>
   1.253 +IDBCursor::Create(IDBRequest* aRequest,
   1.254 +                  IDBTransaction* aTransaction,
   1.255 +                  IDBObjectStore* aObjectStore,
   1.256 +                  Direction aDirection,
   1.257 +                  const Key& aRangeKey,
   1.258 +                  const nsACString& aContinueQuery,
   1.259 +                  const nsACString& aContinueToQuery,
   1.260 +                  const Key& aKey)
   1.261 +{
   1.262 +  MOZ_ASSERT(aObjectStore);
   1.263 +  MOZ_ASSERT(!aKey.IsUnset());
   1.264 +
   1.265 +  nsRefPtr<IDBCursor> cursor =
   1.266 +    IDBCursor::CreateCommon(aRequest, aTransaction, aObjectStore, aDirection,
   1.267 +                            aRangeKey, aContinueQuery, aContinueToQuery);
   1.268 +  NS_ASSERTION(cursor, "This shouldn't fail!");
   1.269 +
   1.270 +  cursor->mObjectStore = aObjectStore;
   1.271 +  cursor->mType = OBJECTSTOREKEY;
   1.272 +  cursor->mKey = aKey;
   1.273 +
   1.274 +  return cursor.forget();
   1.275 +}
   1.276 +
   1.277 +// static
   1.278 +already_AddRefed<IDBCursor>
   1.279 +IDBCursor::Create(IDBRequest* aRequest,
   1.280 +                  IDBTransaction* aTransaction,
   1.281 +                  IDBIndex* aIndex,
   1.282 +                  Direction aDirection,
   1.283 +                  const Key& aRangeKey,
   1.284 +                  const nsACString& aContinueQuery,
   1.285 +                  const nsACString& aContinueToQuery,
   1.286 +                  const Key& aKey,
   1.287 +                  const Key& aObjectKey)
   1.288 +{
   1.289 +  NS_ASSERTION(aIndex, "Null pointer!");
   1.290 +  NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
   1.291 +  NS_ASSERTION(!aObjectKey.IsUnset(), "Bad key!");
   1.292 +
   1.293 +  nsRefPtr<IDBCursor> cursor =
   1.294 +    IDBCursor::CreateCommon(aRequest, aTransaction, aIndex->ObjectStore(),
   1.295 +                            aDirection, aRangeKey, aContinueQuery,
   1.296 +                            aContinueToQuery);
   1.297 +  NS_ASSERTION(cursor, "This shouldn't fail!");
   1.298 +
   1.299 +  cursor->mIndex = aIndex;
   1.300 +  cursor->mType = INDEXKEY;
   1.301 +  cursor->mKey = aKey,
   1.302 +  cursor->mObjectKey = aObjectKey;
   1.303 +
   1.304 +  return cursor.forget();
   1.305 +}
   1.306 +
   1.307 +// static
   1.308 +already_AddRefed<IDBCursor>
   1.309 +IDBCursor::Create(IDBRequest* aRequest,
   1.310 +                  IDBTransaction* aTransaction,
   1.311 +                  IDBIndex* aIndex,
   1.312 +                  Direction aDirection,
   1.313 +                  const Key& aRangeKey,
   1.314 +                  const nsACString& aContinueQuery,
   1.315 +                  const nsACString& aContinueToQuery,
   1.316 +                  const Key& aKey,
   1.317 +                  const Key& aObjectKey,
   1.318 +                  StructuredCloneReadInfo&& aCloneReadInfo)
   1.319 +{
   1.320 +  NS_ASSERTION(aIndex, "Null pointer!");
   1.321 +  NS_ASSERTION(!aKey.IsUnset(), "Bad key!");
   1.322 +
   1.323 +  nsRefPtr<IDBCursor> cursor =
   1.324 +    IDBCursor::CreateCommon(aRequest, aTransaction, aIndex->ObjectStore(),
   1.325 +                            aDirection, aRangeKey, aContinueQuery,
   1.326 +                            aContinueToQuery);
   1.327 +  NS_ASSERTION(cursor, "This shouldn't fail!");
   1.328 +
   1.329 +  cursor->mObjectStore = aIndex->ObjectStore();
   1.330 +  cursor->mIndex = aIndex;
   1.331 +  cursor->mType = INDEXOBJECT;
   1.332 +  cursor->mKey = aKey;
   1.333 +  cursor->mObjectKey = aObjectKey;
   1.334 +  cursor->mCloneReadInfo = Move(aCloneReadInfo);
   1.335 +
   1.336 +  return cursor.forget();
   1.337 +}
   1.338 +
   1.339 +// static
   1.340 +IDBCursor::Direction
   1.341 +IDBCursor::ConvertDirection(mozilla::dom::IDBCursorDirection aDirection)
   1.342 +{
   1.343 +  switch (aDirection) {
   1.344 +    case mozilla::dom::IDBCursorDirection::Next:
   1.345 +      return NEXT;
   1.346 +
   1.347 +    case mozilla::dom::IDBCursorDirection::Nextunique:
   1.348 +      return NEXT_UNIQUE;
   1.349 +
   1.350 +    case mozilla::dom::IDBCursorDirection::Prev:
   1.351 +      return PREV;
   1.352 +
   1.353 +    case mozilla::dom::IDBCursorDirection::Prevunique:
   1.354 +      return PREV_UNIQUE;
   1.355 +
   1.356 +    default:
   1.357 +      MOZ_ASSUME_UNREACHABLE("Unknown direction!");
   1.358 +  }
   1.359 +}
   1.360 +
   1.361 +// static
   1.362 +already_AddRefed<IDBCursor>
   1.363 +IDBCursor::CreateCommon(IDBRequest* aRequest,
   1.364 +                        IDBTransaction* aTransaction,
   1.365 +                        IDBObjectStore* aObjectStore,
   1.366 +                        Direction aDirection,
   1.367 +                        const Key& aRangeKey,
   1.368 +                        const nsACString& aContinueQuery,
   1.369 +                        const nsACString& aContinueToQuery)
   1.370 +{
   1.371 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   1.372 +  NS_ASSERTION(aRequest, "Null pointer!");
   1.373 +  NS_ASSERTION(aTransaction, "Null pointer!");
   1.374 +  NS_ASSERTION(aObjectStore, "Null pointer!");
   1.375 +  NS_ASSERTION(!aContinueQuery.IsEmpty() ||
   1.376 +               !IndexedDatabaseManager::IsMainProcess(),
   1.377 +               "Empty query!");
   1.378 +  NS_ASSERTION(!aContinueToQuery.IsEmpty() ||
   1.379 +               !IndexedDatabaseManager::IsMainProcess(),
   1.380 +               "Empty query!");
   1.381 +
   1.382 +  nsRefPtr<IDBCursor> cursor = new IDBCursor();
   1.383 +
   1.384 +  IDBDatabase* database = aTransaction->Database();
   1.385 +  cursor->mScriptOwner = database->GetScriptOwner();
   1.386 +
   1.387 +  if (cursor->mScriptOwner) {
   1.388 +    mozilla::HoldJSObjects(cursor.get());
   1.389 +    cursor->mRooted = true;
   1.390 +  }
   1.391 +
   1.392 +  cursor->mRequest = aRequest;
   1.393 +  cursor->mTransaction = aTransaction;
   1.394 +  cursor->mObjectStore = aObjectStore;
   1.395 +  cursor->mDirection = aDirection;
   1.396 +  cursor->mContinueQuery = aContinueQuery;
   1.397 +  cursor->mContinueToQuery = aContinueToQuery;
   1.398 +  cursor->mRangeKey = aRangeKey;
   1.399 +
   1.400 +  return cursor.forget();
   1.401 +}
   1.402 +
   1.403 +IDBCursor::IDBCursor()
   1.404 +: mScriptOwner(nullptr),
   1.405 +  mType(OBJECTSTORE),
   1.406 +  mDirection(IDBCursor::NEXT),
   1.407 +  mCachedKey(JSVAL_VOID),
   1.408 +  mCachedPrimaryKey(JSVAL_VOID),
   1.409 +  mCachedValue(JSVAL_VOID),
   1.410 +  mActorChild(nullptr),
   1.411 +  mActorParent(nullptr),
   1.412 +  mHaveCachedKey(false),
   1.413 +  mHaveCachedPrimaryKey(false),
   1.414 +  mHaveCachedValue(false),
   1.415 +  mRooted(false),
   1.416 +  mContinueCalled(false),
   1.417 +  mHaveValue(true)
   1.418 +{
   1.419 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   1.420 +
   1.421 +  SetIsDOMBinding();
   1.422 +}
   1.423 +
   1.424 +IDBCursor::~IDBCursor()
   1.425 +{
   1.426 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
   1.427 +
   1.428 +  NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
   1.429 +  if (mActorChild) {
   1.430 +    NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
   1.431 +    mActorChild->Send__delete__(mActorChild);
   1.432 +    NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
   1.433 +  }
   1.434 +
   1.435 +  DropJSObjects();
   1.436 +  IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
   1.437 +}
   1.438 +
   1.439 +void
   1.440 +IDBCursor::DropJSObjects()
   1.441 +{
   1.442 +  if (!mRooted) {
   1.443 +    return;
   1.444 +  }
   1.445 +  mScriptOwner = nullptr;
   1.446 +  mCachedKey = JSVAL_VOID;
   1.447 +  mCachedPrimaryKey = JSVAL_VOID;
   1.448 +  mCachedValue = JSVAL_VOID;
   1.449 +  mHaveCachedKey = false;
   1.450 +  mHaveCachedPrimaryKey = false;
   1.451 +  mHaveCachedValue = false;
   1.452 +  mRooted = false;
   1.453 +  mHaveValue = false;
   1.454 +  mozilla::DropJSObjects(this);
   1.455 +}
   1.456 +
   1.457 +void
   1.458 +IDBCursor::ContinueInternal(const Key& aKey, int32_t aCount, ErrorResult& aRv)
   1.459 +{
   1.460 +  MOZ_ASSERT(NS_IsMainThread());
   1.461 +  MOZ_ASSERT(aCount > 0);
   1.462 +
   1.463 +  if (!mTransaction->IsOpen()) {
   1.464 +    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
   1.465 +    return;
   1.466 +  }
   1.467 +
   1.468 +  if (!mHaveValue || mContinueCalled) {
   1.469 +    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   1.470 +    return;
   1.471 +  }
   1.472 +
   1.473 +  mContinueToKey = aKey;
   1.474 +
   1.475 +  MOZ_ASSERT(mRequest->ReadyState() == IDBRequestReadyState::Done);
   1.476 +
   1.477 +  mRequest->Reset();
   1.478 +
   1.479 +  nsRefPtr<ContinueHelper> helper;
   1.480 +  switch (mType) {
   1.481 +    case OBJECTSTORE:
   1.482 +      helper = new ContinueObjectStoreHelper(this, aCount);
   1.483 +      break;
   1.484 +
   1.485 +    case OBJECTSTOREKEY:
   1.486 +      helper = new ContinueObjectStoreKeyHelper(this, aCount);
   1.487 +      break;
   1.488 +
   1.489 +    case INDEXKEY:
   1.490 +      helper = new ContinueIndexHelper(this, aCount);
   1.491 +      break;
   1.492 +
   1.493 +    case INDEXOBJECT:
   1.494 +      helper = new ContinueIndexObjectHelper(this, aCount);
   1.495 +      break;
   1.496 +
   1.497 +    default:
   1.498 +      MOZ_ASSUME_UNREACHABLE("Unknown cursor type!");
   1.499 +  }
   1.500 +
   1.501 +  nsresult rv = helper->DispatchToTransactionPool();
   1.502 +  if (NS_FAILED(rv)) {
   1.503 +    IDB_WARNING("Failed to dispatch!");
   1.504 +    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
   1.505 +    return;
   1.506 +  }
   1.507 +
   1.508 +  mContinueCalled = true;
   1.509 +}
   1.510 +
   1.511 +NS_IMPL_CYCLE_COLLECTION_CLASS(IDBCursor)
   1.512 +
   1.513 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBCursor)
   1.514 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
   1.515 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRequest)
   1.516 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction)
   1.517 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore)
   1.518 +  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIndex)
   1.519 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
   1.520 +
   1.521 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBCursor)
   1.522 +  NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
   1.523 +  NS_ASSERTION(tmp->mHaveCachedKey || JSVAL_IS_VOID(tmp->mCachedKey),
   1.524 +               "Should have a cached key");
   1.525 +  NS_ASSERTION(tmp->mHaveCachedPrimaryKey ||
   1.526 +               JSVAL_IS_VOID(tmp->mCachedPrimaryKey),
   1.527 +               "Should have a cached primary key");
   1.528 +  NS_ASSERTION(tmp->mHaveCachedValue || JSVAL_IS_VOID(tmp->mCachedValue),
   1.529 +               "Should have a cached value");
   1.530 +  NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptOwner)
   1.531 +  NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKey)
   1.532 +  NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedPrimaryKey)
   1.533 +  NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedValue)
   1.534 +NS_IMPL_CYCLE_COLLECTION_TRACE_END
   1.535 +
   1.536 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBCursor)
   1.537 +  NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
   1.538 +  // Don't unlink mObjectStore, mIndex, or mTransaction!
   1.539 +  tmp->DropJSObjects();
   1.540 +  NS_IMPL_CYCLE_COLLECTION_UNLINK(mRequest)
   1.541 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END
   1.542 +
   1.543 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBCursor)
   1.544 +  NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
   1.545 +  NS_INTERFACE_MAP_ENTRY(nsISupports)
   1.546 +NS_INTERFACE_MAP_END
   1.547 +
   1.548 +NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBCursor)
   1.549 +NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBCursor)
   1.550 +
   1.551 +JSObject*
   1.552 +IDBCursor::WrapObject(JSContext* aCx)
   1.553 +{
   1.554 +  MOZ_ASSERT(NS_IsMainThread());
   1.555 +
   1.556 +  switch (mType) {
   1.557 +    case OBJECTSTORE:
   1.558 +    case INDEXOBJECT:
   1.559 +      return IDBCursorWithValueBinding::Wrap(aCx, this);
   1.560 +
   1.561 +    case OBJECTSTOREKEY:
   1.562 +    case INDEXKEY:
   1.563 +      return IDBCursorBinding::Wrap(aCx, this);
   1.564 +
   1.565 +    default:
   1.566 +      MOZ_ASSUME_UNREACHABLE("Bad type!");
   1.567 +  }
   1.568 +}
   1.569 +
   1.570 +mozilla::dom::IDBCursorDirection
   1.571 +IDBCursor::GetDirection() const
   1.572 +{
   1.573 +  MOZ_ASSERT(NS_IsMainThread());
   1.574 +
   1.575 +  switch (mDirection) {
   1.576 +    case NEXT:
   1.577 +      return mozilla::dom::IDBCursorDirection::Next;
   1.578 +
   1.579 +    case NEXT_UNIQUE:
   1.580 +      return mozilla::dom::IDBCursorDirection::Nextunique;
   1.581 +
   1.582 +    case PREV:
   1.583 +      return mozilla::dom::IDBCursorDirection::Prev;
   1.584 +
   1.585 +    case PREV_UNIQUE:
   1.586 +      return mozilla::dom::IDBCursorDirection::Prevunique;
   1.587 +
   1.588 +    default:
   1.589 +      MOZ_ASSUME_UNREACHABLE("Bad direction!");
   1.590 +  }
   1.591 +}
   1.592 +
   1.593 +void
   1.594 +IDBCursor::GetSource(OwningIDBObjectStoreOrIDBIndex& aSource) const
   1.595 +{
   1.596 +  MOZ_ASSERT(NS_IsMainThread());
   1.597 +
   1.598 +  switch (mType) {
   1.599 +    case OBJECTSTORE:
   1.600 +    case OBJECTSTOREKEY:
   1.601 +      MOZ_ASSERT(mObjectStore);
   1.602 +      aSource.SetAsIDBObjectStore() = mObjectStore;
   1.603 +      break;
   1.604 +
   1.605 +    case INDEXKEY:
   1.606 +    case INDEXOBJECT:
   1.607 +      MOZ_ASSERT(mIndex);
   1.608 +      aSource.SetAsIDBIndex() = mIndex;
   1.609 +      break;
   1.610 +
   1.611 +    default:
   1.612 +      MOZ_ASSUME_UNREACHABLE("Bad type!");
   1.613 +  }
   1.614 +}
   1.615 +
   1.616 +void
   1.617 +IDBCursor::GetKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
   1.618 +                  ErrorResult& aRv)
   1.619 +{
   1.620 +  MOZ_ASSERT(NS_IsMainThread());
   1.621 +  MOZ_ASSERT(!mKey.IsUnset() || !mHaveValue);
   1.622 +
   1.623 +  if (!mHaveValue) {
   1.624 +    aResult.setUndefined();
   1.625 +    return;
   1.626 +  }
   1.627 +
   1.628 +  if (!mHaveCachedKey) {
   1.629 +    if (!mRooted) {
   1.630 +      mozilla::HoldJSObjects(this);
   1.631 +      mRooted = true;
   1.632 +    }
   1.633 +
   1.634 +    aRv = mKey.ToJSVal(aCx, mCachedKey);
   1.635 +    if (NS_WARN_IF(aRv.Failed())) {
   1.636 +      return;
   1.637 +    }
   1.638 +
   1.639 +    mHaveCachedKey = true;
   1.640 +  }
   1.641 +
   1.642 +  JS::ExposeValueToActiveJS(mCachedKey);
   1.643 +  aResult.set(mCachedKey);
   1.644 +}
   1.645 +
   1.646 +void
   1.647 +IDBCursor::GetPrimaryKey(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
   1.648 +                         ErrorResult& aRv)
   1.649 +{
   1.650 +  MOZ_ASSERT(NS_IsMainThread());
   1.651 +
   1.652 +  if (!mHaveValue) {
   1.653 +    aResult.setUndefined();
   1.654 +    return;
   1.655 +  }
   1.656 +
   1.657 +  if (!mHaveCachedPrimaryKey) {
   1.658 +    if (!mRooted) {
   1.659 +      mozilla::HoldJSObjects(this);
   1.660 +      mRooted = true;
   1.661 +    }
   1.662 +
   1.663 +    const Key& key =
   1.664 +      (mType == OBJECTSTORE || mType == OBJECTSTOREKEY) ? mKey : mObjectKey;
   1.665 +    MOZ_ASSERT(!key.IsUnset());
   1.666 +
   1.667 +    aRv = key.ToJSVal(aCx, mCachedPrimaryKey);
   1.668 +    if (NS_WARN_IF(aRv.Failed())) {
   1.669 +      return;
   1.670 +    }
   1.671 +
   1.672 +    mHaveCachedPrimaryKey = true;
   1.673 +  }
   1.674 +
   1.675 +  JS::ExposeValueToActiveJS(mCachedPrimaryKey);
   1.676 +  aResult.set(mCachedPrimaryKey);
   1.677 +}
   1.678 +
   1.679 +void
   1.680 +IDBCursor::GetValue(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
   1.681 +                    ErrorResult& aRv)
   1.682 +{
   1.683 +  MOZ_ASSERT(NS_IsMainThread());
   1.684 +  MOZ_ASSERT(mType == OBJECTSTORE || mType == INDEXOBJECT);
   1.685 +
   1.686 +  if (!mHaveValue) {
   1.687 +    aResult.setUndefined();
   1.688 +    return;
   1.689 +  }
   1.690 +
   1.691 +  if (!mHaveCachedValue) {
   1.692 +    if (!mRooted) {
   1.693 +      mozilla::HoldJSObjects(this);
   1.694 +      mRooted = true;
   1.695 +    }
   1.696 +
   1.697 +    JS::Rooted<JS::Value> val(aCx);
   1.698 +    if (!IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, &val)) {
   1.699 +      aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
   1.700 +      return;
   1.701 +    }
   1.702 +
   1.703 +    mCloneReadInfo.mCloneBuffer.clear();
   1.704 +
   1.705 +    mCachedValue = val;
   1.706 +    mHaveCachedValue = true;
   1.707 +  }
   1.708 +
   1.709 +  JS::ExposeValueToActiveJS(mCachedValue);
   1.710 +  aResult.set(mCachedValue);
   1.711 +}
   1.712 +
   1.713 +void
   1.714 +IDBCursor::Continue(JSContext* aCx,
   1.715 +                    JS::Handle<JS::Value> aKey,
   1.716 +                    ErrorResult &aRv)
   1.717 +{
   1.718 +  MOZ_ASSERT(NS_IsMainThread());
   1.719 +
   1.720 +  Key key;
   1.721 +  aRv = key.SetFromJSVal(aCx, aKey);
   1.722 +  ENSURE_SUCCESS_VOID(aRv);
   1.723 +
   1.724 +  if (!key.IsUnset()) {
   1.725 +    switch (mDirection) {
   1.726 +      case IDBCursor::NEXT:
   1.727 +      case IDBCursor::NEXT_UNIQUE:
   1.728 +        if (key <= mKey) {
   1.729 +          aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
   1.730 +          return;
   1.731 +        }
   1.732 +        break;
   1.733 +
   1.734 +      case IDBCursor::PREV:
   1.735 +      case IDBCursor::PREV_UNIQUE:
   1.736 +        if (key >= mKey) {
   1.737 +          aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
   1.738 +          return;
   1.739 +        }
   1.740 +        break;
   1.741 +
   1.742 +      default:
   1.743 +        MOZ_ASSUME_UNREACHABLE("Unknown direction type!");
   1.744 +    }
   1.745 +  }
   1.746 +
   1.747 +  ContinueInternal(key, 1, aRv);
   1.748 +  if (aRv.Failed()) {
   1.749 +    return;
   1.750 +  }
   1.751 +
   1.752 +#ifdef IDB_PROFILER_USE_MARKS
   1.753 +  if (mType == OBJECTSTORE || mType == OBJECTSTOREKEY) {
   1.754 +    IDB_PROFILER_MARK("IndexedDB Request %llu: "
   1.755 +                      "database(%s).transaction(%s).objectStore(%s).cursor(%s)."
   1.756 +                      "continue(%s)",
   1.757 +                      "IDBRequest[%llu] MT IDBCursor.continue()",
   1.758 +                      Request()->GetSerialNumber(),
   1.759 +                      IDB_PROFILER_STRING(Transaction()->Database()),
   1.760 +                      IDB_PROFILER_STRING(Transaction()),
   1.761 +                      IDB_PROFILER_STRING(mObjectStore),
   1.762 +                      IDB_PROFILER_STRING(mDirection),
   1.763 +                      key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
   1.764 +  }
   1.765 +  else {
   1.766 +    IDB_PROFILER_MARK("IndexedDB Request %llu: "
   1.767 +                      "database(%s).transaction(%s).objectStore(%s).index(%s)."
   1.768 +                      "cursor(%s).continue(%s)",
   1.769 +                      "IDBRequest[%llu] MT IDBCursor.continue()",
   1.770 +                      Request()->GetSerialNumber(),
   1.771 +                      IDB_PROFILER_STRING(Transaction()->Database()),
   1.772 +                      IDB_PROFILER_STRING(Transaction()),
   1.773 +                      IDB_PROFILER_STRING(mObjectStore),
   1.774 +                      IDB_PROFILER_STRING(mIndex),
   1.775 +                      IDB_PROFILER_STRING(mDirection),
   1.776 +                      key.IsUnset() ? "" : IDB_PROFILER_STRING(key));
   1.777 +  }
   1.778 +#endif
   1.779 +}
   1.780 +
   1.781 +already_AddRefed<IDBRequest>
   1.782 +IDBCursor::Update(JSContext* aCx, JS::Handle<JS::Value> aValue,
   1.783 +                  ErrorResult& aRv)
   1.784 +{
   1.785 +  MOZ_ASSERT(NS_IsMainThread());
   1.786 +
   1.787 +  if (!mTransaction->IsOpen()) {
   1.788 +    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
   1.789 +    return nullptr;
   1.790 +  }
   1.791 +
   1.792 +  if (!mTransaction->IsWriteAllowed()) {
   1.793 +    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
   1.794 +    return nullptr;
   1.795 +  }
   1.796 +
   1.797 +  if (!mHaveValue || mType == OBJECTSTOREKEY || mType == INDEXKEY) {
   1.798 +    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   1.799 +    return nullptr;
   1.800 +  }
   1.801 +
   1.802 +  MOZ_ASSERT(mObjectStore);
   1.803 +  MOZ_ASSERT(!mKey.IsUnset());
   1.804 +  MOZ_ASSERT(mType == OBJECTSTORE || mType == INDEXOBJECT);
   1.805 +  MOZ_ASSERT_IF(mType == INDEXOBJECT, !mObjectKey.IsUnset());
   1.806 +
   1.807 +  const Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
   1.808 +
   1.809 +  nsRefPtr<IDBRequest> request;
   1.810 +  if (mObjectStore->HasValidKeyPath()) {
   1.811 +    // Make sure the object given has the correct keyPath value set on it.
   1.812 +    const KeyPath& keyPath = mObjectStore->GetKeyPath();
   1.813 +    Key key;
   1.814 +
   1.815 +    aRv = keyPath.ExtractKey(aCx, aValue, key);
   1.816 +    if (aRv.Failed()) {
   1.817 +      return nullptr;
   1.818 +    }
   1.819 +
   1.820 +    if (key != objectKey) {
   1.821 +      aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
   1.822 +      return nullptr;
   1.823 +    }
   1.824 +
   1.825 +    request = mObjectStore->Put(aCx, aValue, JS::UndefinedHandleValue, aRv);
   1.826 +    if (aRv.Failed()) {
   1.827 +      return nullptr;
   1.828 +    }
   1.829 +  }
   1.830 +  else {
   1.831 +    JS::Rooted<JS::Value> keyVal(aCx);
   1.832 +    aRv = objectKey.ToJSVal(aCx, &keyVal);
   1.833 +    ENSURE_SUCCESS(aRv, nullptr);
   1.834 +
   1.835 +    request = mObjectStore->Put(aCx, aValue, keyVal, aRv);
   1.836 +    if (aRv.Failed()) {
   1.837 +      return nullptr;
   1.838 +    }
   1.839 +  }
   1.840 +
   1.841 +#ifdef IDB_PROFILER_USE_MARKS
   1.842 +  {
   1.843 +    uint64_t requestSerial =
   1.844 +      static_cast<IDBRequest*>(request.get())->GetSerialNumber();
   1.845 +    if (mType == OBJECTSTORE) {
   1.846 +      IDB_PROFILER_MARK("IndexedDB Request %llu: "
   1.847 +                        "database(%s).transaction(%s).objectStore(%s)."
   1.848 +                        "cursor(%s).update(%s)",
   1.849 +                        "IDBRequest[%llu] MT IDBCursor.update()",
   1.850 +                        requestSerial,
   1.851 +                        IDB_PROFILER_STRING(mTransaction->Database()),
   1.852 +                        IDB_PROFILER_STRING(mTransaction),
   1.853 +                        IDB_PROFILER_STRING(mObjectStore),
   1.854 +                        IDB_PROFILER_STRING(mDirection),
   1.855 +                        mObjectStore->HasValidKeyPath() ? "" :
   1.856 +                          IDB_PROFILER_STRING(objectKey));
   1.857 +    }
   1.858 +    else {
   1.859 +      IDB_PROFILER_MARK("IndexedDB Request %llu: "
   1.860 +                        "database(%s).transaction(%s).objectStore(%s)."
   1.861 +                        "index(%s).cursor(%s).update(%s)",
   1.862 +                        "IDBRequest[%llu] MT IDBCursor.update()",
   1.863 +                        requestSerial,
   1.864 +                        IDB_PROFILER_STRING(mTransaction->Database()),
   1.865 +                        IDB_PROFILER_STRING(mTransaction),
   1.866 +                        IDB_PROFILER_STRING(mObjectStore),
   1.867 +                        IDB_PROFILER_STRING(mIndex),
   1.868 +                        IDB_PROFILER_STRING(mDirection),
   1.869 +                        mObjectStore->HasValidKeyPath() ? "" :
   1.870 +                          IDB_PROFILER_STRING(objectKey));
   1.871 +    }
   1.872 +  }
   1.873 +#endif
   1.874 +
   1.875 +  return request.forget();
   1.876 +}
   1.877 +
   1.878 +already_AddRefed<IDBRequest>
   1.879 +IDBCursor::Delete(JSContext* aCx, ErrorResult& aRv)
   1.880 +{
   1.881 +  MOZ_ASSERT(NS_IsMainThread());
   1.882 +
   1.883 +  if (!mTransaction->IsOpen()) {
   1.884 +    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
   1.885 +    return nullptr;
   1.886 +  }
   1.887 +
   1.888 +  if (!mTransaction->IsWriteAllowed()) {
   1.889 +    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR);
   1.890 +    return nullptr;
   1.891 +  }
   1.892 +
   1.893 +  if (!mHaveValue || mType == OBJECTSTOREKEY || mType == INDEXKEY) {
   1.894 +    aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR);
   1.895 +    return nullptr;
   1.896 +  }
   1.897 +
   1.898 +  MOZ_ASSERT(mObjectStore);
   1.899 +  MOZ_ASSERT(mType == OBJECTSTORE || mType == INDEXOBJECT);
   1.900 +  MOZ_ASSERT(!mKey.IsUnset());
   1.901 +
   1.902 +  const Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
   1.903 +
   1.904 +  JS::Rooted<JS::Value> key(aCx);
   1.905 +  aRv = objectKey.ToJSVal(aCx, &key);
   1.906 +  ENSURE_SUCCESS(aRv, nullptr);
   1.907 +
   1.908 +  nsRefPtr<IDBRequest> request = mObjectStore->Delete(aCx, key, aRv);
   1.909 +  ENSURE_SUCCESS(aRv, nullptr);
   1.910 +
   1.911 +#ifdef IDB_PROFILER_USE_MARKS
   1.912 +  {
   1.913 +    uint64_t requestSerial = request->GetSerialNumber();
   1.914 +    if (mType == OBJECTSTORE) {
   1.915 +      IDB_PROFILER_MARK("IndexedDB Request %llu: "
   1.916 +                        "database(%s).transaction(%s).objectStore(%s)."
   1.917 +                        "cursor(%s).delete(%s)",
   1.918 +                        "IDBRequest[%llu] MT IDBCursor.delete()",
   1.919 +                        requestSerial,
   1.920 +                        IDB_PROFILER_STRING(mTransaction->Database()),
   1.921 +                        IDB_PROFILER_STRING(mTransaction),
   1.922 +                        IDB_PROFILER_STRING(mObjectStore),
   1.923 +                        IDB_PROFILER_STRING(mDirection),
   1.924 +                        mObjectStore->HasValidKeyPath() ? "" :
   1.925 +                          IDB_PROFILER_STRING(objectKey));
   1.926 +    }
   1.927 +    else {
   1.928 +      IDB_PROFILER_MARK("IndexedDB Request %llu: "
   1.929 +                        "database(%s).transaction(%s).objectStore(%s)."
   1.930 +                        "index(%s).cursor(%s).delete(%s)",
   1.931 +                        "IDBRequest[%llu] MT IDBCursor.delete()",
   1.932 +                        requestSerial,
   1.933 +                        IDB_PROFILER_STRING(mTransaction->Database()),
   1.934 +                        IDB_PROFILER_STRING(mTransaction),
   1.935 +                        IDB_PROFILER_STRING(mObjectStore),
   1.936 +                        IDB_PROFILER_STRING(mIndex),
   1.937 +                        IDB_PROFILER_STRING(mDirection),
   1.938 +                        mObjectStore->HasValidKeyPath() ? "" :
   1.939 +                          IDB_PROFILER_STRING(objectKey));
   1.940 +    }
   1.941 +  }
   1.942 +#endif
   1.943 +
   1.944 +  return request.forget();
   1.945 +}
   1.946 +
   1.947 +void
   1.948 +IDBCursor::Advance(uint32_t aCount, ErrorResult &aRv)
   1.949 +{
   1.950 +  MOZ_ASSERT(NS_IsMainThread());
   1.951 +
   1.952 +  if (aCount < 1) {
   1.953 +    aRv.ThrowTypeError(MSG_INVALID_ADVANCE_COUNT);
   1.954 +    return;
   1.955 +  }
   1.956 +
   1.957 +  Key key;
   1.958 +  ContinueInternal(key, int32_t(aCount), aRv);
   1.959 +  ENSURE_SUCCESS_VOID(aRv);
   1.960 +
   1.961 +#ifdef IDB_PROFILER_USE_MARKS
   1.962 +  {
   1.963 +    if (mType == OBJECTSTORE || mType == OBJECTSTOREKEY) {
   1.964 +      IDB_PROFILER_MARK("IndexedDB Request %llu: "
   1.965 +                        "database(%s).transaction(%s).objectStore(%s)."
   1.966 +                        "cursor(%s).advance(%ld)",
   1.967 +                        "IDBRequest[%llu] MT IDBCursor.advance()",
   1.968 +                        Request()->GetSerialNumber(),
   1.969 +                        IDB_PROFILER_STRING(Transaction()->Database()),
   1.970 +                        IDB_PROFILER_STRING(Transaction()),
   1.971 +                        IDB_PROFILER_STRING(mObjectStore),
   1.972 +                        IDB_PROFILER_STRING(mDirection), aCount);
   1.973 +    }
   1.974 +    else {
   1.975 +      IDB_PROFILER_MARK("IndexedDB Request %llu: "
   1.976 +                        "database(%s).transaction(%s).objectStore(%s)."
   1.977 +                        "index(%s).cursor(%s).advance(%ld)",
   1.978 +                        "IDBRequest[%llu] MT IDBCursor.advance()",
   1.979 +                        Request()->GetSerialNumber(),
   1.980 +                        IDB_PROFILER_STRING(Transaction()->Database()),
   1.981 +                        IDB_PROFILER_STRING(Transaction()),
   1.982 +                        IDB_PROFILER_STRING(mObjectStore),
   1.983 +                        IDB_PROFILER_STRING(mIndex),
   1.984 +                        IDB_PROFILER_STRING(mDirection), aCount);
   1.985 +    }
   1.986 +  }
   1.987 +#endif
   1.988 +}
   1.989 +
   1.990 +void
   1.991 +CursorHelper::ReleaseMainThreadObjects()
   1.992 +{
   1.993 +  mCursor = nullptr;
   1.994 +  AsyncConnectionHelper::ReleaseMainThreadObjects();
   1.995 +}
   1.996 +
   1.997 +nsresult
   1.998 +CursorHelper::Dispatch(nsIEventTarget* aDatabaseThread)
   1.999 +{
  1.1000 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.1001 +
  1.1002 +  PROFILER_MAIN_THREAD_LABEL("IndexedDB", "CursorHelper::Dispatch");
  1.1003 +
  1.1004 +  if (IndexedDatabaseManager::IsMainProcess()) {
  1.1005 +    return AsyncConnectionHelper::Dispatch(aDatabaseThread);
  1.1006 +  }
  1.1007 +
  1.1008 +  // If we've been invalidated then there's no point sending anything to the
  1.1009 +  // parent process.
  1.1010 +  if (mCursor->Transaction()->Database()->IsInvalidated()) {
  1.1011 +    IDB_REPORT_INTERNAL_ERR();
  1.1012 +    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1.1013 +  }
  1.1014 +
  1.1015 +  IndexedDBCursorChild* cursorActor = mCursor->GetActorChild();
  1.1016 +  NS_ASSERTION(cursorActor, "Must have an actor here!");
  1.1017 +
  1.1018 +  CursorRequestParams params;
  1.1019 +  nsresult rv = PackArgumentsForParentProcess(params);
  1.1020 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1021 +
  1.1022 +  NoDispatchEventTarget target;
  1.1023 +  rv = AsyncConnectionHelper::Dispatch(&target);
  1.1024 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1025 +
  1.1026 +  mActor = new IndexedDBCursorRequestChild(this, mCursor, params.type());
  1.1027 +  cursorActor->SendPIndexedDBRequestConstructor(mActor, params);
  1.1028 +
  1.1029 +  return NS_OK;
  1.1030 +}
  1.1031 +
  1.1032 +nsresult
  1.1033 +ContinueHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
  1.1034 +{
  1.1035 +  NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
  1.1036 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.1037 +
  1.1038 +  PROFILER_LABEL("IndexedDB", "ContinueHelper::DoDatabaseWork");
  1.1039 +
  1.1040 +  // We need to pick a query based on whether or not the cursor's mContinueToKey
  1.1041 +  // is set. If it is unset then othing was passed to continue so we'll grab the
  1.1042 +  // next item in the database that is greater than (less than, if we're running
  1.1043 +  // a PREV cursor) the current key. If it is set then a key was passed to
  1.1044 +  // continue so we'll grab the next item in the database that is greater than
  1.1045 +  // (less than, if we're running a PREV cursor) or equal to the key that was
  1.1046 +  // specified.
  1.1047 +
  1.1048 +  nsAutoCString query;
  1.1049 +  if (mCursor->mContinueToKey.IsUnset()) {
  1.1050 +    query.Assign(mCursor->mContinueQuery);
  1.1051 +  }
  1.1052 +  else {
  1.1053 +    query.Assign(mCursor->mContinueToQuery);
  1.1054 +  }
  1.1055 +  NS_ASSERTION(!query.IsEmpty(), "Bad query!");
  1.1056 +
  1.1057 +  query.AppendInt(mCount);
  1.1058 +
  1.1059 +  nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
  1.1060 +  IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1061 +
  1.1062 +  mozStorageStatementScoper scoper(stmt);
  1.1063 +
  1.1064 +  nsresult rv = BindArgumentsToStatement(stmt);
  1.1065 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1066 +
  1.1067 +  NS_ASSERTION(mCount > 0, "Not ok!");
  1.1068 +
  1.1069 +  bool hasResult;
  1.1070 +  for (int32_t index = 0; index < mCount; index++) {
  1.1071 +    rv = stmt->ExecuteStep(&hasResult);
  1.1072 +    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1073 +
  1.1074 +    if (!hasResult) {
  1.1075 +      break;
  1.1076 +    }
  1.1077 +  }
  1.1078 +
  1.1079 +  if (hasResult) {
  1.1080 +    rv = GatherResultsFromStatement(stmt);
  1.1081 +    IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1082 +  }
  1.1083 +  else {
  1.1084 +    mKey.Unset();
  1.1085 +  }
  1.1086 +
  1.1087 +  return NS_OK;
  1.1088 +}
  1.1089 +
  1.1090 +nsresult
  1.1091 +ContinueHelper::GetSuccessResult(JSContext* aCx,
  1.1092 +                                 JS::MutableHandle<JS::Value> aVal)
  1.1093 +{
  1.1094 +  UpdateCursorState();
  1.1095 +
  1.1096 +  if (mKey.IsUnset()) {
  1.1097 +    aVal.setNull();
  1.1098 +  }
  1.1099 +  else {
  1.1100 +    nsresult rv = WrapNative(aCx, mCursor, aVal);
  1.1101 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1102 +  }
  1.1103 +
  1.1104 +  return NS_OK;
  1.1105 +}
  1.1106 +
  1.1107 +void
  1.1108 +ContinueHelper::ReleaseMainThreadObjects()
  1.1109 +{
  1.1110 +  IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
  1.1111 +  CursorHelper::ReleaseMainThreadObjects();
  1.1112 +}
  1.1113 +
  1.1114 +nsresult
  1.1115 +ContinueHelper::PackArgumentsForParentProcess(CursorRequestParams& aParams)
  1.1116 +{
  1.1117 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.1118 +  NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.1119 +
  1.1120 +  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  1.1121 +                             "ContinueHelper::PackArgumentsForParentProcess");
  1.1122 +
  1.1123 +  ContinueParams params;
  1.1124 +
  1.1125 +  params.key() = mCursor->mContinueToKey;
  1.1126 +  params.count() = uint32_t(mCount);
  1.1127 +
  1.1128 +  aParams = params;
  1.1129 +  return NS_OK;
  1.1130 +}
  1.1131 +
  1.1132 +AsyncConnectionHelper::ChildProcessSendResult
  1.1133 +ContinueHelper::SendResponseToChildProcess(nsresult aResultCode)
  1.1134 +{
  1.1135 +  NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
  1.1136 +  NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
  1.1137 +
  1.1138 +  PROFILER_MAIN_THREAD_LABEL("IndexedDB",
  1.1139 +                             "ContinueHelper::SendResponseToChildProcess");
  1.1140 +
  1.1141 +  IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
  1.1142 +  NS_ASSERTION(actor, "How did we get this far without an actor?");
  1.1143 +
  1.1144 +  InfallibleTArray<PBlobParent*> blobsParent;
  1.1145 +
  1.1146 +  if (NS_SUCCEEDED(aResultCode)) {
  1.1147 +    IDBDatabase* database = mTransaction->Database();
  1.1148 +    NS_ASSERTION(database, "This should never be null!");
  1.1149 +
  1.1150 +    ContentParent* contentParent = database->GetContentParent();
  1.1151 +    NS_ASSERTION(contentParent, "This should never be null!");
  1.1152 +
  1.1153 +    FileManager* fileManager = database->Manager();
  1.1154 +    NS_ASSERTION(fileManager, "This should never be null!");
  1.1155 +
  1.1156 +    const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
  1.1157 +
  1.1158 +    aResultCode =
  1.1159 +      IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
  1.1160 +                                           blobsParent);
  1.1161 +    if (NS_FAILED(aResultCode)) {
  1.1162 +      NS_WARNING("ConvertBlobsToActors failed!");
  1.1163 +    }
  1.1164 +  }
  1.1165 +
  1.1166 +  ResponseValue response;
  1.1167 +  if (NS_FAILED(aResultCode)) {
  1.1168 +    response = aResultCode;
  1.1169 +  }
  1.1170 +  else {
  1.1171 +    ContinueResponse continueResponse;
  1.1172 +    continueResponse.key() = mKey;
  1.1173 +    continueResponse.objectKey() = mObjectKey;
  1.1174 +    continueResponse.cloneInfo() = mCloneReadInfo;
  1.1175 +    continueResponse.blobsParent().SwapElements(blobsParent);
  1.1176 +    response = continueResponse;
  1.1177 +  }
  1.1178 +
  1.1179 +  if (!actor->SendResponse(response)) {
  1.1180 +    return Error;
  1.1181 +  }
  1.1182 +
  1.1183 +  UpdateCursorState();
  1.1184 +
  1.1185 +  return Success_Sent;
  1.1186 +}
  1.1187 +
  1.1188 +nsresult
  1.1189 +ContinueHelper::UnpackResponseFromParentProcess(
  1.1190 +                                            const ResponseValue& aResponseValue)
  1.1191 +{
  1.1192 +  NS_ASSERTION(aResponseValue.type() == ResponseValue::TContinueResponse,
  1.1193 +               "Bad response type!");
  1.1194 +
  1.1195 +  const ContinueResponse& response = aResponseValue.get_ContinueResponse();
  1.1196 +
  1.1197 +  mKey = response.key();
  1.1198 +  mObjectKey = response.objectKey();
  1.1199 +
  1.1200 +  const SerializedStructuredCloneReadInfo& cloneInfo = response.cloneInfo();
  1.1201 +
  1.1202 +  NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
  1.1203 +               (cloneInfo.dataLength && cloneInfo.data),
  1.1204 +               "Inconsistent clone info!");
  1.1205 +
  1.1206 +  if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
  1.1207 +    IDB_WARNING("Failed to copy clone buffer!");
  1.1208 +    return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
  1.1209 +  }
  1.1210 +
  1.1211 +  IDBObjectStore::ConvertActorsToBlobs(response.blobsChild(),
  1.1212 +                                       mCloneReadInfo.mFiles);
  1.1213 +  return NS_OK;
  1.1214 +}
  1.1215 +
  1.1216 +nsresult
  1.1217 +ContinueObjectStoreHelper::BindArgumentsToStatement(
  1.1218 +                                               mozIStorageStatement* aStatement)
  1.1219 +{
  1.1220 +  MOZ_ASSERT(!NS_IsMainThread());
  1.1221 +  MOZ_ASSERT(aStatement);
  1.1222 +
  1.1223 +  // Bind object store id.
  1.1224 +  nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
  1.1225 +                                            mCursor->mObjectStore->Id());
  1.1226 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1227 +
  1.1228 +  NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
  1.1229 +  NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
  1.1230 +
  1.1231 +  // Bind current key.
  1.1232 +  const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
  1.1233 +                          mCursor->mKey :
  1.1234 +                          mCursor->mContinueToKey;
  1.1235 +
  1.1236 +  rv = currentKey.BindToStatement(aStatement, currentKeyName);
  1.1237 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1238 +
  1.1239 +  // Bind range key if it is specified.
  1.1240 +  const Key& rangeKey = mCursor->mRangeKey;
  1.1241 +
  1.1242 +  if (!rangeKey.IsUnset()) {
  1.1243 +    rv = rangeKey.BindToStatement(aStatement, rangeKeyName);
  1.1244 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1245 +  }
  1.1246 +
  1.1247 +  return NS_OK;
  1.1248 +}
  1.1249 +
  1.1250 +nsresult
  1.1251 +ContinueObjectStoreHelper::GatherResultsFromStatement(
  1.1252 +                                               mozIStorageStatement* aStatement)
  1.1253 +{
  1.1254 +  MOZ_ASSERT(!NS_IsMainThread());
  1.1255 +  MOZ_ASSERT(aStatement);
  1.1256 +
  1.1257 +  // Figure out what kind of key we have next.
  1.1258 +  nsresult rv = mKey.SetFromStatement(aStatement, 0);
  1.1259 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1260 +
  1.1261 +  rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 1, 2,
  1.1262 +                                                               mDatabase,
  1.1263 +                                                               mCloneReadInfo);
  1.1264 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1265 +
  1.1266 +  return NS_OK;
  1.1267 +}
  1.1268 +
  1.1269 +nsresult
  1.1270 +ContinueObjectStoreKeyHelper::GatherResultsFromStatement(
  1.1271 +                                               mozIStorageStatement* aStatement)
  1.1272 +{
  1.1273 +  MOZ_ASSERT(!NS_IsMainThread());
  1.1274 +  MOZ_ASSERT(aStatement);
  1.1275 +
  1.1276 +  nsresult rv = mKey.SetFromStatement(aStatement, 0);
  1.1277 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1278 +
  1.1279 +  return NS_OK;
  1.1280 +}
  1.1281 +
  1.1282 +nsresult
  1.1283 +ContinueIndexHelper::BindArgumentsToStatement(mozIStorageStatement* aStatement)
  1.1284 +{
  1.1285 +  // Bind index id.
  1.1286 +  nsresult rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"),
  1.1287 +                                            mCursor->mIndex->Id());
  1.1288 +  IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
  1.1289 +
  1.1290 +  NS_NAMED_LITERAL_CSTRING(currentKeyName, "current_key");
  1.1291 +
  1.1292 +  // Bind current key.
  1.1293 +  const Key& currentKey = mCursor->mContinueToKey.IsUnset() ?
  1.1294 +                          mCursor->mKey :
  1.1295 +                          mCursor->mContinueToKey;
  1.1296 +
  1.1297 +  rv = currentKey.BindToStatement(aStatement, currentKeyName);
  1.1298 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1299 +
  1.1300 +  // Bind range key if it is specified.
  1.1301 +  if (!mCursor->mRangeKey.IsUnset()) {
  1.1302 +    NS_NAMED_LITERAL_CSTRING(rangeKeyName, "range_key");
  1.1303 +    rv = mCursor->mRangeKey.BindToStatement(aStatement, rangeKeyName);
  1.1304 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1305 +  }
  1.1306 +
  1.1307 +  // Bind object key if duplicates are allowed and we're not continuing to a
  1.1308 +  // specific key.
  1.1309 +  if ((mCursor->mDirection == IDBCursor::NEXT ||
  1.1310 +       mCursor->mDirection == IDBCursor::PREV) &&
  1.1311 +       mCursor->mContinueToKey.IsUnset()) {
  1.1312 +    NS_ASSERTION(!mCursor->mObjectKey.IsUnset(), "Bad key!");
  1.1313 +
  1.1314 +    NS_NAMED_LITERAL_CSTRING(objectKeyName, "object_key");
  1.1315 +    rv = mCursor->mObjectKey.BindToStatement(aStatement, objectKeyName);
  1.1316 +    NS_ENSURE_SUCCESS(rv, rv);
  1.1317 +  }
  1.1318 +
  1.1319 +  return NS_OK;
  1.1320 +}
  1.1321 +
  1.1322 +nsresult
  1.1323 +ContinueIndexHelper::GatherResultsFromStatement(
  1.1324 +                                               mozIStorageStatement* aStatement)
  1.1325 +{
  1.1326 +  nsresult rv = mKey.SetFromStatement(aStatement, 0);
  1.1327 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1328 +
  1.1329 +  rv = mObjectKey.SetFromStatement(aStatement, 1);
  1.1330 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1331 +
  1.1332 +  return NS_OK;
  1.1333 +}
  1.1334 +
  1.1335 +nsresult
  1.1336 +ContinueIndexObjectHelper::GatherResultsFromStatement(
  1.1337 +                                               mozIStorageStatement* aStatement)
  1.1338 +{
  1.1339 +  nsresult rv = mKey.SetFromStatement(aStatement, 0);
  1.1340 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1341 +
  1.1342 +  rv = mObjectKey.SetFromStatement(aStatement, 1);
  1.1343 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1344 +
  1.1345 +  rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(aStatement, 2, 3,
  1.1346 +    mDatabase, mCloneReadInfo);
  1.1347 +  NS_ENSURE_SUCCESS(rv, rv);
  1.1348 +
  1.1349 +  return NS_OK;
  1.1350 +}

mercurial