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 +}