1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/dom/indexedDB/IDBObjectStore.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,5181 @@ 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 "IDBObjectStore.h" 1.13 + 1.14 +#include "mozilla/dom/ipc/nsIRemoteBlob.h" 1.15 +#include "nsIOutputStream.h" 1.16 + 1.17 +#include <algorithm> 1.18 +#include "jsfriendapi.h" 1.19 +#include "mozilla/dom/ContentChild.h" 1.20 +#include "mozilla/dom/ContentParent.h" 1.21 +#include "mozilla/dom/FileHandleBinding.h" 1.22 +#include "mozilla/dom/StructuredCloneTags.h" 1.23 +#include "mozilla/dom/ipc/Blob.h" 1.24 +#include "mozilla/dom/quota/FileStreams.h" 1.25 +#include "mozilla/Endian.h" 1.26 +#include "mozilla/storage.h" 1.27 +#include "nsContentUtils.h" 1.28 +#include "nsDOMClassInfo.h" 1.29 +#include "nsDOMFile.h" 1.30 +#include "mozilla/dom/DOMStringList.h" 1.31 +#include "nsJSUtils.h" 1.32 +#include "nsServiceManagerUtils.h" 1.33 +#include "nsThreadUtils.h" 1.34 +#include "snappy/snappy.h" 1.35 + 1.36 +#include "AsyncConnectionHelper.h" 1.37 +#include "IDBCursor.h" 1.38 +#include "IDBEvents.h" 1.39 +#include "IDBFileHandle.h" 1.40 +#include "IDBIndex.h" 1.41 +#include "IDBKeyRange.h" 1.42 +#include "IDBTransaction.h" 1.43 +#include "DatabaseInfo.h" 1.44 +#include "KeyPath.h" 1.45 +#include "ProfilerHelpers.h" 1.46 +#include "ReportInternalError.h" 1.47 + 1.48 +#include "ipc/IndexedDBChild.h" 1.49 +#include "ipc/IndexedDBParent.h" 1.50 + 1.51 +#include "IndexedDatabaseInlines.h" 1.52 +#include "nsCharSeparatedTokenizer.h" 1.53 + 1.54 +#define FILE_COPY_BUFFER_SIZE 32768 1.55 + 1.56 +USING_INDEXEDDB_NAMESPACE 1.57 +using namespace mozilla::dom; 1.58 +using namespace mozilla::dom::indexedDB::ipc; 1.59 +using mozilla::dom::quota::FileOutputStream; 1.60 +using mozilla::ErrorResult; 1.61 +using mozilla::fallible_t; 1.62 +using mozilla::LittleEndian; 1.63 +using mozilla::Move; 1.64 +using mozilla::NativeEndian; 1.65 + 1.66 +BEGIN_INDEXEDDB_NAMESPACE 1.67 + 1.68 +struct FileHandleData 1.69 +{ 1.70 + nsString type; 1.71 + nsString name; 1.72 +}; 1.73 + 1.74 +struct BlobOrFileData 1.75 +{ 1.76 + BlobOrFileData() 1.77 + : tag(0), size(0), lastModifiedDate(UINT64_MAX) 1.78 + { } 1.79 + 1.80 + uint32_t tag; 1.81 + uint64_t size; 1.82 + nsString type; 1.83 + nsString name; 1.84 + uint64_t lastModifiedDate; 1.85 +}; 1.86 + 1.87 +END_INDEXEDDB_NAMESPACE 1.88 + 1.89 +namespace { 1.90 + 1.91 +inline 1.92 +bool 1.93 +IgnoreNothing(char16_t c) 1.94 +{ 1.95 + return false; 1.96 +} 1.97 + 1.98 +class ObjectStoreHelper : public AsyncConnectionHelper 1.99 +{ 1.100 +public: 1.101 + ObjectStoreHelper(IDBTransaction* aTransaction, 1.102 + IDBRequest* aRequest, 1.103 + IDBObjectStore* aObjectStore) 1.104 + : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore), 1.105 + mActor(nullptr) 1.106 + { 1.107 + NS_ASSERTION(aTransaction, "Null transaction!"); 1.108 + NS_ASSERTION(aRequest, "Null request!"); 1.109 + NS_ASSERTION(aObjectStore, "Null object store!"); 1.110 + } 1.111 + 1.112 + virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; 1.113 + 1.114 + virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread) MOZ_OVERRIDE; 1.115 + 1.116 + virtual nsresult 1.117 + PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) = 0; 1.118 + 1.119 + virtual nsresult 1.120 + UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0; 1.121 + 1.122 +protected: 1.123 + nsRefPtr<IDBObjectStore> mObjectStore; 1.124 + 1.125 +private: 1.126 + IndexedDBObjectStoreRequestChild* mActor; 1.127 +}; 1.128 + 1.129 +class NoRequestObjectStoreHelper : public AsyncConnectionHelper 1.130 +{ 1.131 +public: 1.132 + NoRequestObjectStoreHelper(IDBTransaction* aTransaction, 1.133 + IDBObjectStore* aObjectStore) 1.134 + : AsyncConnectionHelper(aTransaction, nullptr), mObjectStore(aObjectStore) 1.135 + { 1.136 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.137 + NS_ASSERTION(aTransaction, "Null transaction!"); 1.138 + NS_ASSERTION(aObjectStore, "Null object store!"); 1.139 + } 1.140 + 1.141 + virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; 1.142 + 1.143 + virtual nsresult UnpackResponseFromParentProcess( 1.144 + const ResponseValue& aResponseValue) 1.145 + MOZ_OVERRIDE; 1.146 + 1.147 + virtual ChildProcessSendResult 1.148 + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; 1.149 + 1.150 + virtual nsresult OnSuccess() MOZ_OVERRIDE; 1.151 + 1.152 + virtual void OnError() MOZ_OVERRIDE; 1.153 + 1.154 +protected: 1.155 + nsRefPtr<IDBObjectStore> mObjectStore; 1.156 +}; 1.157 + 1.158 +class AddHelper : public ObjectStoreHelper 1.159 +{ 1.160 +public: 1.161 + AddHelper(IDBTransaction* aTransaction, 1.162 + IDBRequest* aRequest, 1.163 + IDBObjectStore* aObjectStore, 1.164 + StructuredCloneWriteInfo&& aCloneWriteInfo, 1.165 + const Key& aKey, 1.166 + bool aOverwrite, 1.167 + nsTArray<IndexUpdateInfo>& aIndexUpdateInfo) 1.168 + : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), 1.169 + mCloneWriteInfo(Move(aCloneWriteInfo)), 1.170 + mKey(aKey), 1.171 + mOverwrite(aOverwrite) 1.172 + { 1.173 + mIndexUpdateInfo.SwapElements(aIndexUpdateInfo); 1.174 + } 1.175 + 1.176 + ~AddHelper() 1.177 + { 1.178 + IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo); 1.179 + } 1.180 + 1.181 + virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) 1.182 + MOZ_OVERRIDE; 1.183 + 1.184 + virtual nsresult GetSuccessResult(JSContext* aCx, 1.185 + JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; 1.186 + 1.187 + virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; 1.188 + 1.189 + virtual nsresult 1.190 + PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; 1.191 + 1.192 + virtual ChildProcessSendResult 1.193 + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; 1.194 + 1.195 + virtual nsresult 1.196 + UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.197 + MOZ_OVERRIDE; 1.198 + 1.199 +private: 1.200 + // These may change in the autoincrement case. 1.201 + StructuredCloneWriteInfo mCloneWriteInfo; 1.202 + Key mKey; 1.203 + nsTArray<IndexUpdateInfo> mIndexUpdateInfo; 1.204 + const bool mOverwrite; 1.205 +}; 1.206 + 1.207 +class GetHelper : public ObjectStoreHelper 1.208 +{ 1.209 +public: 1.210 + GetHelper(IDBTransaction* aTransaction, 1.211 + IDBRequest* aRequest, 1.212 + IDBObjectStore* aObjectStore, 1.213 + IDBKeyRange* aKeyRange) 1.214 + : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), 1.215 + mKeyRange(aKeyRange) 1.216 + { 1.217 + NS_ASSERTION(aKeyRange, "Null key range!"); 1.218 + } 1.219 + 1.220 + ~GetHelper() 1.221 + { 1.222 + IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo); 1.223 + } 1.224 + 1.225 + virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) 1.226 + MOZ_OVERRIDE; 1.227 + 1.228 + virtual nsresult GetSuccessResult(JSContext* aCx, 1.229 + JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; 1.230 + 1.231 + virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; 1.232 + 1.233 + virtual nsresult 1.234 + PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; 1.235 + 1.236 + virtual ChildProcessSendResult 1.237 + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; 1.238 + 1.239 + virtual nsresult 1.240 + UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.241 + MOZ_OVERRIDE; 1.242 + 1.243 +protected: 1.244 + // In-params. 1.245 + nsRefPtr<IDBKeyRange> mKeyRange; 1.246 + 1.247 +private: 1.248 + // Out-params. 1.249 + StructuredCloneReadInfo mCloneReadInfo; 1.250 +}; 1.251 + 1.252 +class DeleteHelper : public GetHelper 1.253 +{ 1.254 +public: 1.255 + DeleteHelper(IDBTransaction* aTransaction, 1.256 + IDBRequest* aRequest, 1.257 + IDBObjectStore* aObjectStore, 1.258 + IDBKeyRange* aKeyRange) 1.259 + : GetHelper(aTransaction, aRequest, aObjectStore, aKeyRange) 1.260 + { } 1.261 + 1.262 + virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) 1.263 + MOZ_OVERRIDE; 1.264 + 1.265 + virtual nsresult GetSuccessResult(JSContext* aCx, 1.266 + JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; 1.267 + 1.268 + virtual nsresult 1.269 + PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; 1.270 + 1.271 + virtual ChildProcessSendResult 1.272 + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; 1.273 + 1.274 + virtual nsresult 1.275 + UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.276 + MOZ_OVERRIDE; 1.277 +}; 1.278 + 1.279 +class ClearHelper : public ObjectStoreHelper 1.280 +{ 1.281 +public: 1.282 + ClearHelper(IDBTransaction* aTransaction, 1.283 + IDBRequest* aRequest, 1.284 + IDBObjectStore* aObjectStore) 1.285 + : ObjectStoreHelper(aTransaction, aRequest, aObjectStore) 1.286 + { } 1.287 + 1.288 + virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) 1.289 + MOZ_OVERRIDE; 1.290 + 1.291 + virtual nsresult 1.292 + PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; 1.293 + 1.294 + virtual ChildProcessSendResult 1.295 + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; 1.296 + 1.297 + virtual nsresult 1.298 + UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.299 + MOZ_OVERRIDE; 1.300 +}; 1.301 + 1.302 +class OpenCursorHelper : public ObjectStoreHelper 1.303 +{ 1.304 +public: 1.305 + OpenCursorHelper(IDBTransaction* aTransaction, 1.306 + IDBRequest* aRequest, 1.307 + IDBObjectStore* aObjectStore, 1.308 + IDBKeyRange* aKeyRange, 1.309 + IDBCursor::Direction aDirection) 1.310 + : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), 1.311 + mKeyRange(aKeyRange), mDirection(aDirection) 1.312 + { } 1.313 + 1.314 + ~OpenCursorHelper() 1.315 + { 1.316 + IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo); 1.317 + } 1.318 + 1.319 + virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) 1.320 + MOZ_OVERRIDE; 1.321 + 1.322 + virtual nsresult GetSuccessResult(JSContext* aCx, 1.323 + JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; 1.324 + 1.325 + virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; 1.326 + 1.327 + virtual nsresult 1.328 + PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; 1.329 + 1.330 + virtual ChildProcessSendResult 1.331 + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; 1.332 + 1.333 + virtual nsresult 1.334 + UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.335 + MOZ_OVERRIDE; 1.336 + 1.337 +private: 1.338 + nsresult EnsureCursor(); 1.339 + 1.340 + // In-params. 1.341 + nsRefPtr<IDBKeyRange> mKeyRange; 1.342 + const IDBCursor::Direction mDirection; 1.343 + 1.344 + // Out-params. 1.345 + Key mKey; 1.346 + StructuredCloneReadInfo mCloneReadInfo; 1.347 + nsCString mContinueQuery; 1.348 + nsCString mContinueToQuery; 1.349 + Key mRangeKey; 1.350 + 1.351 + // Only used in the parent process. 1.352 + nsRefPtr<IDBCursor> mCursor; 1.353 + SerializedStructuredCloneReadInfo mSerializedCloneReadInfo; 1.354 +}; 1.355 + 1.356 +class OpenKeyCursorHelper MOZ_FINAL : public ObjectStoreHelper 1.357 +{ 1.358 +public: 1.359 + OpenKeyCursorHelper(IDBTransaction* aTransaction, 1.360 + IDBRequest* aRequest, 1.361 + IDBObjectStore* aObjectStore, 1.362 + IDBKeyRange* aKeyRange, 1.363 + IDBCursor::Direction aDirection) 1.364 + : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), 1.365 + mKeyRange(aKeyRange), mDirection(aDirection) 1.366 + { } 1.367 + 1.368 + virtual nsresult 1.369 + DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE; 1.370 + 1.371 + virtual nsresult 1.372 + GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) 1.373 + MOZ_OVERRIDE; 1.374 + 1.375 + virtual void 1.376 + ReleaseMainThreadObjects() MOZ_OVERRIDE; 1.377 + 1.378 + virtual nsresult 1.379 + PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; 1.380 + 1.381 + virtual ChildProcessSendResult 1.382 + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; 1.383 + 1.384 + virtual nsresult 1.385 + UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.386 + MOZ_OVERRIDE; 1.387 + 1.388 +private: 1.389 + ~OpenKeyCursorHelper() 1.390 + { } 1.391 + 1.392 + nsresult EnsureCursor(); 1.393 + 1.394 + // In-params. 1.395 + nsRefPtr<IDBKeyRange> mKeyRange; 1.396 + const IDBCursor::Direction mDirection; 1.397 + 1.398 + // Out-params. 1.399 + Key mKey; 1.400 + nsCString mContinueQuery; 1.401 + nsCString mContinueToQuery; 1.402 + Key mRangeKey; 1.403 + 1.404 + // Only used in the parent process. 1.405 + nsRefPtr<IDBCursor> mCursor; 1.406 +}; 1.407 + 1.408 +class CreateIndexHelper : public NoRequestObjectStoreHelper 1.409 +{ 1.410 +public: 1.411 + CreateIndexHelper(IDBTransaction* aTransaction, IDBIndex* aIndex) 1.412 + : NoRequestObjectStoreHelper(aTransaction, aIndex->ObjectStore()), 1.413 + mIndex(aIndex) 1.414 + { 1.415 + if (sTLSIndex == BAD_TLS_INDEX) { 1.416 + PR_NewThreadPrivateIndex(&sTLSIndex, DestroyTLSEntry); 1.417 + } 1.418 + 1.419 + NS_ASSERTION(sTLSIndex != BAD_TLS_INDEX, 1.420 + "PR_NewThreadPrivateIndex failed!"); 1.421 + } 1.422 + 1.423 + virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) 1.424 + MOZ_OVERRIDE; 1.425 + 1.426 + virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; 1.427 + 1.428 +private: 1.429 + nsresult InsertDataFromObjectStore(mozIStorageConnection* aConnection); 1.430 + 1.431 + static void DestroyTLSEntry(void* aPtr); 1.432 + 1.433 + static unsigned sTLSIndex; 1.434 + 1.435 + // In-params. 1.436 + nsRefPtr<IDBIndex> mIndex; 1.437 +}; 1.438 + 1.439 +unsigned CreateIndexHelper::sTLSIndex = unsigned(BAD_TLS_INDEX); 1.440 + 1.441 +class DeleteIndexHelper : public NoRequestObjectStoreHelper 1.442 +{ 1.443 +public: 1.444 + DeleteIndexHelper(IDBTransaction* aTransaction, 1.445 + IDBObjectStore* aObjectStore, 1.446 + const nsAString& aName) 1.447 + : NoRequestObjectStoreHelper(aTransaction, aObjectStore), mName(aName) 1.448 + { } 1.449 + 1.450 + virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) 1.451 + MOZ_OVERRIDE; 1.452 + 1.453 +private: 1.454 + // In-params 1.455 + nsString mName; 1.456 +}; 1.457 + 1.458 +class GetAllHelper : public ObjectStoreHelper 1.459 +{ 1.460 +public: 1.461 + GetAllHelper(IDBTransaction* aTransaction, 1.462 + IDBRequest* aRequest, 1.463 + IDBObjectStore* aObjectStore, 1.464 + IDBKeyRange* aKeyRange, 1.465 + const uint32_t aLimit) 1.466 + : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), 1.467 + mKeyRange(aKeyRange), mLimit(aLimit) 1.468 + { } 1.469 + 1.470 + ~GetAllHelper() 1.471 + { 1.472 + for (uint32_t index = 0; index < mCloneReadInfos.Length(); index++) { 1.473 + IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos[index]); 1.474 + } 1.475 + } 1.476 + 1.477 + virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) 1.478 + MOZ_OVERRIDE; 1.479 + 1.480 + virtual nsresult GetSuccessResult(JSContext* aCx, 1.481 + JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; 1.482 + 1.483 + virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; 1.484 + 1.485 + virtual nsresult 1.486 + PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; 1.487 + 1.488 + virtual ChildProcessSendResult 1.489 + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; 1.490 + 1.491 + virtual nsresult 1.492 + UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.493 + MOZ_OVERRIDE; 1.494 + 1.495 +protected: 1.496 + // In-params. 1.497 + nsRefPtr<IDBKeyRange> mKeyRange; 1.498 + const uint32_t mLimit; 1.499 + 1.500 +private: 1.501 + // Out-params. 1.502 + nsTArray<StructuredCloneReadInfo> mCloneReadInfos; 1.503 +}; 1.504 + 1.505 +class GetAllKeysHelper MOZ_FINAL : public ObjectStoreHelper 1.506 +{ 1.507 +public: 1.508 + GetAllKeysHelper(IDBTransaction* aTransaction, 1.509 + IDBRequest* aRequest, 1.510 + IDBObjectStore* aObjectStore, 1.511 + IDBKeyRange* aKeyRange, 1.512 + const uint32_t aLimit) 1.513 + : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), 1.514 + mKeyRange(aKeyRange), mLimit(aLimit) 1.515 + { } 1.516 + 1.517 + virtual nsresult 1.518 + DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE; 1.519 + 1.520 + virtual nsresult 1.521 + GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) 1.522 + MOZ_OVERRIDE; 1.523 + 1.524 + virtual void 1.525 + ReleaseMainThreadObjects() MOZ_OVERRIDE; 1.526 + 1.527 + virtual nsresult 1.528 + PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; 1.529 + 1.530 + virtual ChildProcessSendResult 1.531 + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; 1.532 + 1.533 + virtual nsresult 1.534 + UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.535 + MOZ_OVERRIDE; 1.536 + 1.537 +private: 1.538 + ~GetAllKeysHelper() 1.539 + { } 1.540 + 1.541 + nsRefPtr<IDBKeyRange> mKeyRange; 1.542 + const uint32_t mLimit; 1.543 + nsTArray<Key> mKeys; 1.544 +}; 1.545 + 1.546 +class CountHelper : public ObjectStoreHelper 1.547 +{ 1.548 +public: 1.549 + CountHelper(IDBTransaction* aTransaction, 1.550 + IDBRequest* aRequest, 1.551 + IDBObjectStore* aObjectStore, 1.552 + IDBKeyRange* aKeyRange) 1.553 + : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), 1.554 + mKeyRange(aKeyRange), mCount(0) 1.555 + { } 1.556 + 1.557 + virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) 1.558 + MOZ_OVERRIDE; 1.559 + 1.560 + virtual nsresult GetSuccessResult(JSContext* aCx, 1.561 + JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; 1.562 + 1.563 + virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; 1.564 + 1.565 + virtual nsresult 1.566 + PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; 1.567 + 1.568 + virtual ChildProcessSendResult 1.569 + SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; 1.570 + 1.571 + virtual nsresult 1.572 + UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.573 + MOZ_OVERRIDE; 1.574 + 1.575 +private: 1.576 + nsRefPtr<IDBKeyRange> mKeyRange; 1.577 + uint64_t mCount; 1.578 +}; 1.579 + 1.580 +class MOZ_STACK_CLASS AutoRemoveIndex 1.581 +{ 1.582 +public: 1.583 + AutoRemoveIndex(ObjectStoreInfo* aObjectStoreInfo, 1.584 + const nsAString& aIndexName) 1.585 + : mObjectStoreInfo(aObjectStoreInfo), mIndexName(aIndexName) 1.586 + { } 1.587 + 1.588 + ~AutoRemoveIndex() 1.589 + { 1.590 + if (mObjectStoreInfo) { 1.591 + for (uint32_t i = 0; i < mObjectStoreInfo->indexes.Length(); i++) { 1.592 + if (mObjectStoreInfo->indexes[i].name == mIndexName) { 1.593 + mObjectStoreInfo->indexes.RemoveElementAt(i); 1.594 + break; 1.595 + } 1.596 + } 1.597 + } 1.598 + } 1.599 + 1.600 + void forget() 1.601 + { 1.602 + mObjectStoreInfo = nullptr; 1.603 + } 1.604 + 1.605 +private: 1.606 + ObjectStoreInfo* mObjectStoreInfo; 1.607 + nsString mIndexName; 1.608 +}; 1.609 + 1.610 +class ThreadLocalJSRuntime 1.611 +{ 1.612 + JSRuntime* mRuntime; 1.613 + JSContext* mContext; 1.614 + JSObject* mGlobal; 1.615 + 1.616 + static const JSClass sGlobalClass; 1.617 + static const unsigned sRuntimeHeapSize = 768 * 1024; 1.618 + 1.619 + ThreadLocalJSRuntime() 1.620 + : mRuntime(nullptr), mContext(nullptr), mGlobal(nullptr) 1.621 + { 1.622 + MOZ_COUNT_CTOR(ThreadLocalJSRuntime); 1.623 + } 1.624 + 1.625 + nsresult Init() 1.626 + { 1.627 + mRuntime = JS_NewRuntime(sRuntimeHeapSize, JS_NO_HELPER_THREADS); 1.628 + NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY); 1.629 + 1.630 + /* 1.631 + * Not setting this will cause JS_CHECK_RECURSION to report false 1.632 + * positives 1.633 + */ 1.634 + JS_SetNativeStackQuota(mRuntime, 128 * sizeof(size_t) * 1024); 1.635 + 1.636 + mContext = JS_NewContext(mRuntime, 0); 1.637 + NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY); 1.638 + 1.639 + JSAutoRequest ar(mContext); 1.640 + 1.641 + mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr, 1.642 + JS::FireOnNewGlobalHook); 1.643 + NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY); 1.644 + 1.645 + js::SetDefaultObjectForContext(mContext, mGlobal); 1.646 + return NS_OK; 1.647 + } 1.648 + 1.649 + public: 1.650 + static ThreadLocalJSRuntime *Create() 1.651 + { 1.652 + ThreadLocalJSRuntime *entry = new ThreadLocalJSRuntime(); 1.653 + NS_ENSURE_TRUE(entry, nullptr); 1.654 + 1.655 + if (NS_FAILED(entry->Init())) { 1.656 + delete entry; 1.657 + return nullptr; 1.658 + } 1.659 + 1.660 + return entry; 1.661 + } 1.662 + 1.663 + JSContext *Context() const 1.664 + { 1.665 + return mContext; 1.666 + } 1.667 + 1.668 + JSObject *Global() const 1.669 + { 1.670 + return mGlobal; 1.671 + } 1.672 + 1.673 + ~ThreadLocalJSRuntime() 1.674 + { 1.675 + MOZ_COUNT_DTOR(ThreadLocalJSRuntime); 1.676 + 1.677 + if (mContext) { 1.678 + JS_DestroyContext(mContext); 1.679 + } 1.680 + 1.681 + if (mRuntime) { 1.682 + JS_DestroyRuntime(mRuntime); 1.683 + } 1.684 + } 1.685 +}; 1.686 + 1.687 +const JSClass ThreadLocalJSRuntime::sGlobalClass = { 1.688 + "IndexedDBTransactionThreadGlobal", 1.689 + JSCLASS_GLOBAL_FLAGS, 1.690 + JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, 1.691 + JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, 1.692 + nullptr, nullptr, nullptr, nullptr, 1.693 + JS_GlobalObjectTraceHook 1.694 +}; 1.695 + 1.696 +inline 1.697 +already_AddRefed<IDBRequest> 1.698 +GenerateRequest(IDBObjectStore* aObjectStore) 1.699 +{ 1.700 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.701 + IDBDatabase* database = aObjectStore->Transaction()->Database(); 1.702 + return IDBRequest::Create(aObjectStore, database, 1.703 + aObjectStore->Transaction()); 1.704 +} 1.705 + 1.706 +struct MOZ_STACK_CLASS GetAddInfoClosure 1.707 +{ 1.708 + IDBObjectStore* mThis; 1.709 + StructuredCloneWriteInfo& mCloneWriteInfo; 1.710 + JS::Handle<JS::Value> mValue; 1.711 +}; 1.712 + 1.713 +nsresult 1.714 +GetAddInfoCallback(JSContext* aCx, void* aClosure) 1.715 +{ 1.716 + GetAddInfoClosure* data = static_cast<GetAddInfoClosure*>(aClosure); 1.717 + 1.718 + data->mCloneWriteInfo.mOffsetToKeyProp = 0; 1.719 + data->mCloneWriteInfo.mTransaction = data->mThis->Transaction(); 1.720 + 1.721 + if (!IDBObjectStore::SerializeValue(aCx, data->mCloneWriteInfo, data->mValue)) { 1.722 + return NS_ERROR_DOM_DATA_CLONE_ERR; 1.723 + } 1.724 + 1.725 + return NS_OK; 1.726 +} 1.727 + 1.728 +inline 1.729 +BlobChild* 1.730 +ActorFromRemoteBlob(nsIDOMBlob* aBlob) 1.731 +{ 1.732 + NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.733 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.734 + 1.735 + nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob); 1.736 + if (remoteBlob) { 1.737 + BlobChild* actor = 1.738 + static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob())); 1.739 + NS_ASSERTION(actor, "Null actor?!"); 1.740 + return actor; 1.741 + } 1.742 + return nullptr; 1.743 +} 1.744 + 1.745 +inline 1.746 +bool 1.747 +ResolveMysteryFile(nsIDOMBlob* aBlob, const nsString& aName, 1.748 + const nsString& aContentType, uint64_t aSize, 1.749 + uint64_t aLastModifiedDate) 1.750 +{ 1.751 + BlobChild* actor = ActorFromRemoteBlob(aBlob); 1.752 + if (actor) { 1.753 + return actor->SetMysteryBlobInfo(aName, aContentType, 1.754 + aSize, aLastModifiedDate); 1.755 + } 1.756 + return true; 1.757 +} 1.758 + 1.759 +inline 1.760 +bool 1.761 +ResolveMysteryBlob(nsIDOMBlob* aBlob, const nsString& aContentType, 1.762 + uint64_t aSize) 1.763 +{ 1.764 + BlobChild* actor = ActorFromRemoteBlob(aBlob); 1.765 + if (actor) { 1.766 + return actor->SetMysteryBlobInfo(aContentType, aSize); 1.767 + } 1.768 + return true; 1.769 +} 1.770 + 1.771 +class MainThreadDeserializationTraits 1.772 +{ 1.773 +public: 1.774 + static JSObject* CreateAndWrapFileHandle(JSContext* aCx, 1.775 + IDBDatabase* aDatabase, 1.776 + StructuredCloneFile& aFile, 1.777 + const FileHandleData& aData) 1.778 + { 1.779 + MOZ_ASSERT(NS_IsMainThread()); 1.780 + 1.781 + nsRefPtr<FileInfo>& fileInfo = aFile.mFileInfo; 1.782 + 1.783 + nsRefPtr<IDBFileHandle> fileHandle = IDBFileHandle::Create(aDatabase, 1.784 + aData.name, aData.type, fileInfo.forget()); 1.785 + 1.786 + return fileHandle->WrapObject(aCx); 1.787 + } 1.788 + 1.789 + static JSObject* CreateAndWrapBlobOrFile(JSContext* aCx, 1.790 + IDBDatabase* aDatabase, 1.791 + StructuredCloneFile& aFile, 1.792 + const BlobOrFileData& aData) 1.793 + { 1.794 + MOZ_ASSERT(NS_IsMainThread()); 1.795 + 1.796 + MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE || 1.797 + aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE || 1.798 + aData.tag == SCTAG_DOM_BLOB); 1.799 + 1.800 + nsresult rv = NS_OK; 1.801 + 1.802 + nsRefPtr<FileInfo>& fileInfo = aFile.mFileInfo; 1.803 + 1.804 + nsCOMPtr<nsIFile> nativeFile; 1.805 + if (!aFile.mFile) { 1.806 + FileManager* fileManager = aDatabase->Manager(); 1.807 + NS_ASSERTION(fileManager, "This should never be null!"); 1.808 + 1.809 + nsCOMPtr<nsIFile> directory = fileManager->GetDirectory(); 1.810 + if (!directory) { 1.811 + NS_WARNING("Failed to get directory!"); 1.812 + return nullptr; 1.813 + } 1.814 + 1.815 + nativeFile = fileManager->GetFileForId(directory, fileInfo->Id()); 1.816 + if (!nativeFile) { 1.817 + NS_WARNING("Failed to get file!"); 1.818 + return nullptr; 1.819 + } 1.820 + } 1.821 + 1.822 + if (aData.tag == SCTAG_DOM_BLOB) { 1.823 + nsCOMPtr<nsIDOMBlob> domBlob; 1.824 + if (aFile.mFile) { 1.825 + if (!ResolveMysteryBlob(aFile.mFile, aData.type, aData.size)) { 1.826 + return nullptr; 1.827 + } 1.828 + domBlob = aFile.mFile; 1.829 + } 1.830 + else { 1.831 + domBlob = new nsDOMFileFile(aData.type, aData.size, nativeFile, 1.832 + fileInfo); 1.833 + } 1.834 + 1.835 + JS::Rooted<JS::Value> wrappedBlob(aCx); 1.836 + rv = nsContentUtils::WrapNative(aCx, domBlob, &NS_GET_IID(nsIDOMBlob), 1.837 + &wrappedBlob); 1.838 + if (NS_FAILED(rv)) { 1.839 + NS_WARNING("Failed to wrap native!"); 1.840 + return nullptr; 1.841 + } 1.842 + 1.843 + return JSVAL_TO_OBJECT(wrappedBlob); 1.844 + } 1.845 + 1.846 + nsCOMPtr<nsIDOMFile> domFile; 1.847 + if (aFile.mFile) { 1.848 + if (!ResolveMysteryFile(aFile.mFile, aData.name, aData.type, aData.size, 1.849 + aData.lastModifiedDate)) { 1.850 + return nullptr; 1.851 + } 1.852 + domFile = do_QueryInterface(aFile.mFile); 1.853 + NS_ASSERTION(domFile, "This should never fail!"); 1.854 + } 1.855 + else { 1.856 + domFile = new nsDOMFileFile(aData.name, aData.type, aData.size, 1.857 + nativeFile, fileInfo); 1.858 + } 1.859 + 1.860 + JS::Rooted<JS::Value> wrappedFile(aCx); 1.861 + rv = nsContentUtils::WrapNative(aCx, domFile, &NS_GET_IID(nsIDOMFile), 1.862 + &wrappedFile); 1.863 + if (NS_FAILED(rv)) { 1.864 + NS_WARNING("Failed to wrap native!"); 1.865 + return nullptr; 1.866 + } 1.867 + 1.868 + return JSVAL_TO_OBJECT(wrappedFile); 1.869 + } 1.870 +}; 1.871 + 1.872 + 1.873 +class CreateIndexDeserializationTraits 1.874 +{ 1.875 +public: 1.876 + static JSObject* CreateAndWrapFileHandle(JSContext* aCx, 1.877 + IDBDatabase* aDatabase, 1.878 + StructuredCloneFile& aFile, 1.879 + const FileHandleData& aData) 1.880 + { 1.881 + // FileHandle can't be used in index creation, so just make a dummy object. 1.882 + return JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()); 1.883 + } 1.884 + 1.885 + static JSObject* CreateAndWrapBlobOrFile(JSContext* aCx, 1.886 + IDBDatabase* aDatabase, 1.887 + StructuredCloneFile& aFile, 1.888 + const BlobOrFileData& aData) 1.889 + { 1.890 + MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE || 1.891 + aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE || 1.892 + aData.tag == SCTAG_DOM_BLOB); 1.893 + 1.894 + // The following properties are available for use in index creation 1.895 + // Blob.size 1.896 + // Blob.type 1.897 + // File.name 1.898 + // File.lastModifiedDate 1.899 + 1.900 + JS::Rooted<JSObject*> obj(aCx, 1.901 + JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr())); 1.902 + if (!obj) { 1.903 + NS_WARNING("Failed to create object!"); 1.904 + return nullptr; 1.905 + } 1.906 + 1.907 + // Technically these props go on the proto, but this detail won't change 1.908 + // the results of index creation. 1.909 + 1.910 + JS::Rooted<JSString*> type(aCx, 1.911 + JS_NewUCStringCopyN(aCx, aData.type.get(), aData.type.Length())); 1.912 + if (!type || 1.913 + !JS_DefineProperty(aCx, obj, "size", double(aData.size), 0) || 1.914 + !JS_DefineProperty(aCx, obj, "type", type, 0)) { 1.915 + return nullptr; 1.916 + } 1.917 + 1.918 + if (aData.tag == SCTAG_DOM_BLOB) { 1.919 + return obj; 1.920 + } 1.921 + 1.922 + JS::Rooted<JSString*> name(aCx, 1.923 + JS_NewUCStringCopyN(aCx, aData.name.get(), aData.name.Length())); 1.924 + JS::Rooted<JSObject*> date(aCx, 1.925 + JS_NewDateObjectMsec(aCx, aData.lastModifiedDate)); 1.926 + if (!name || !date || 1.927 + !JS_DefineProperty(aCx, obj, "name", name, 0) || 1.928 + !JS_DefineProperty(aCx, obj, "lastModifiedDate", date, 0)) { 1.929 + return nullptr; 1.930 + } 1.931 + 1.932 + return obj; 1.933 + } 1.934 +}; 1.935 + 1.936 +} // anonymous namespace 1.937 + 1.938 +const JSClass IDBObjectStore::sDummyPropJSClass = { 1.939 + "dummy", 0, 1.940 + JS_PropertyStub, JS_DeletePropertyStub, 1.941 + JS_PropertyStub, JS_StrictPropertyStub, 1.942 + JS_EnumerateStub, JS_ResolveStub, 1.943 + JS_ConvertStub 1.944 +}; 1.945 + 1.946 +// static 1.947 +already_AddRefed<IDBObjectStore> 1.948 +IDBObjectStore::Create(IDBTransaction* aTransaction, 1.949 + ObjectStoreInfo* aStoreInfo, 1.950 + const nsACString& aDatabaseId, 1.951 + bool aCreating) 1.952 +{ 1.953 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.954 + 1.955 + nsRefPtr<IDBObjectStore> objectStore = new IDBObjectStore(); 1.956 + 1.957 + objectStore->mTransaction = aTransaction; 1.958 + objectStore->mName = aStoreInfo->name; 1.959 + objectStore->mId = aStoreInfo->id; 1.960 + objectStore->mKeyPath = aStoreInfo->keyPath; 1.961 + objectStore->mAutoIncrement = aStoreInfo->autoIncrement; 1.962 + objectStore->mDatabaseId = aDatabaseId; 1.963 + objectStore->mInfo = aStoreInfo; 1.964 + 1.965 + if (!IndexedDatabaseManager::IsMainProcess()) { 1.966 + IndexedDBTransactionChild* transactionActor = aTransaction->GetActorChild(); 1.967 + NS_ASSERTION(transactionActor, "Must have an actor here!"); 1.968 + 1.969 + ObjectStoreConstructorParams params; 1.970 + 1.971 + if (aCreating) { 1.972 + CreateObjectStoreParams createParams; 1.973 + createParams.info() = *aStoreInfo; 1.974 + params = createParams; 1.975 + } 1.976 + else { 1.977 + GetObjectStoreParams getParams; 1.978 + getParams.name() = aStoreInfo->name; 1.979 + params = getParams; 1.980 + } 1.981 + 1.982 + IndexedDBObjectStoreChild* actor = 1.983 + new IndexedDBObjectStoreChild(objectStore); 1.984 + 1.985 + transactionActor->SendPIndexedDBObjectStoreConstructor(actor, params); 1.986 + } 1.987 + 1.988 + return objectStore.forget(); 1.989 +} 1.990 + 1.991 +// static 1.992 +nsresult 1.993 +IDBObjectStore::AppendIndexUpdateInfo( 1.994 + int64_t aIndexID, 1.995 + const KeyPath& aKeyPath, 1.996 + bool aUnique, 1.997 + bool aMultiEntry, 1.998 + JSContext* aCx, 1.999 + JS::Handle<JS::Value> aVal, 1.1000 + nsTArray<IndexUpdateInfo>& aUpdateInfoArray) 1.1001 +{ 1.1002 + nsresult rv; 1.1003 + 1.1004 + if (!aMultiEntry) { 1.1005 + Key key; 1.1006 + rv = aKeyPath.ExtractKey(aCx, aVal, key); 1.1007 + 1.1008 + // If an index's keypath doesn't match an object, we ignore that object. 1.1009 + if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) { 1.1010 + return NS_OK; 1.1011 + } 1.1012 + 1.1013 + if (NS_FAILED(rv)) { 1.1014 + return rv; 1.1015 + } 1.1016 + 1.1017 + IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement(); 1.1018 + updateInfo->indexId = aIndexID; 1.1019 + updateInfo->indexUnique = aUnique; 1.1020 + updateInfo->value = key; 1.1021 + 1.1022 + return NS_OK; 1.1023 + } 1.1024 + 1.1025 + JS::Rooted<JS::Value> val(aCx); 1.1026 + if (NS_FAILED(aKeyPath.ExtractKeyAsJSVal(aCx, aVal, val.address()))) { 1.1027 + return NS_OK; 1.1028 + } 1.1029 + 1.1030 + if (JS_IsArrayObject(aCx, val)) { 1.1031 + JS::Rooted<JSObject*> array(aCx, &val.toObject()); 1.1032 + uint32_t arrayLength; 1.1033 + if (!JS_GetArrayLength(aCx, array, &arrayLength)) { 1.1034 + IDB_REPORT_INTERNAL_ERR(); 1.1035 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.1036 + } 1.1037 + 1.1038 + for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) { 1.1039 + JS::Rooted<JS::Value> arrayItem(aCx); 1.1040 + if (!JS_GetElement(aCx, array, arrayIndex, &arrayItem)) { 1.1041 + IDB_REPORT_INTERNAL_ERR(); 1.1042 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.1043 + } 1.1044 + 1.1045 + Key value; 1.1046 + if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) || 1.1047 + value.IsUnset()) { 1.1048 + // Not a value we can do anything with, ignore it. 1.1049 + continue; 1.1050 + } 1.1051 + 1.1052 + IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement(); 1.1053 + updateInfo->indexId = aIndexID; 1.1054 + updateInfo->indexUnique = aUnique; 1.1055 + updateInfo->value = value; 1.1056 + } 1.1057 + } 1.1058 + else { 1.1059 + Key value; 1.1060 + if (NS_FAILED(value.SetFromJSVal(aCx, val)) || 1.1061 + value.IsUnset()) { 1.1062 + // Not a value we can do anything with, ignore it. 1.1063 + return NS_OK; 1.1064 + } 1.1065 + 1.1066 + IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement(); 1.1067 + updateInfo->indexId = aIndexID; 1.1068 + updateInfo->indexUnique = aUnique; 1.1069 + updateInfo->value = value; 1.1070 + } 1.1071 + 1.1072 + return NS_OK; 1.1073 +} 1.1074 + 1.1075 +// static 1.1076 +nsresult 1.1077 +IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction, 1.1078 + int64_t aObjectStoreId, 1.1079 + const Key& aObjectStoreKey, 1.1080 + bool aOverwrite, 1.1081 + int64_t aObjectDataId, 1.1082 + const nsTArray<IndexUpdateInfo>& aUpdateInfoArray) 1.1083 +{ 1.1084 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.1085 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.1086 + 1.1087 + PROFILER_LABEL("IndexedDB", "IDBObjectStore::UpdateIndexes"); 1.1088 + 1.1089 + nsresult rv; 1.1090 + 1.1091 + NS_ASSERTION(aObjectDataId != INT64_MIN, "Bad objectData id!"); 1.1092 + 1.1093 + NS_NAMED_LITERAL_CSTRING(objectDataId, "object_data_id"); 1.1094 + 1.1095 + if (aOverwrite) { 1.1096 + nsCOMPtr<mozIStorageStatement> deleteStmt = 1.1097 + aTransaction->GetCachedStatement( 1.1098 + "DELETE FROM unique_index_data " 1.1099 + "WHERE object_data_id = :object_data_id; " 1.1100 + "DELETE FROM index_data " 1.1101 + "WHERE object_data_id = :object_data_id"); 1.1102 + NS_ENSURE_TRUE(deleteStmt, NS_ERROR_FAILURE); 1.1103 + 1.1104 + mozStorageStatementScoper scoper(deleteStmt); 1.1105 + 1.1106 + rv = deleteStmt->BindInt64ByName(objectDataId, aObjectDataId); 1.1107 + NS_ENSURE_SUCCESS(rv, rv); 1.1108 + 1.1109 + rv = deleteStmt->Execute(); 1.1110 + NS_ENSURE_SUCCESS(rv, rv); 1.1111 + } 1.1112 + 1.1113 + // Avoid lots of hash lookups for objectStores with lots of indexes by lazily 1.1114 + // holding the necessary statements on the stack outside the loop. 1.1115 + nsCOMPtr<mozIStorageStatement> insertUniqueStmt; 1.1116 + nsCOMPtr<mozIStorageStatement> insertStmt; 1.1117 + 1.1118 + uint32_t infoCount = aUpdateInfoArray.Length(); 1.1119 + for (uint32_t i = 0; i < infoCount; i++) { 1.1120 + const IndexUpdateInfo& updateInfo = aUpdateInfoArray[i]; 1.1121 + 1.1122 + nsCOMPtr<mozIStorageStatement>& stmt = 1.1123 + updateInfo.indexUnique ? insertUniqueStmt : insertStmt; 1.1124 + 1.1125 + if (!stmt) { 1.1126 + stmt = updateInfo.indexUnique ? 1.1127 + aTransaction->GetCachedStatement( 1.1128 + "INSERT INTO unique_index_data " 1.1129 + "(index_id, object_data_id, object_data_key, value) " 1.1130 + "VALUES (:index_id, :object_data_id, :object_data_key, :value)") : 1.1131 + aTransaction->GetCachedStatement( 1.1132 + "INSERT OR IGNORE INTO index_data (" 1.1133 + "index_id, object_data_id, object_data_key, value) " 1.1134 + "VALUES (:index_id, :object_data_id, :object_data_key, :value)"); 1.1135 + } 1.1136 + NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE); 1.1137 + 1.1138 + mozStorageStatementScoper scoper(stmt); 1.1139 + 1.1140 + rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), 1.1141 + updateInfo.indexId); 1.1142 + NS_ENSURE_SUCCESS(rv, rv); 1.1143 + 1.1144 + rv = stmt->BindInt64ByName(objectDataId, aObjectDataId); 1.1145 + NS_ENSURE_SUCCESS(rv, rv); 1.1146 + 1.1147 + rv = aObjectStoreKey.BindToStatement(stmt, 1.1148 + NS_LITERAL_CSTRING("object_data_key")); 1.1149 + NS_ENSURE_SUCCESS(rv, rv); 1.1150 + 1.1151 + rv = updateInfo.value.BindToStatement(stmt, NS_LITERAL_CSTRING("value")); 1.1152 + NS_ENSURE_SUCCESS(rv, rv); 1.1153 + 1.1154 + rv = stmt->Execute(); 1.1155 + if (rv == NS_ERROR_STORAGE_CONSTRAINT && updateInfo.indexUnique) { 1.1156 + // If we're inserting multiple entries for the same unique index, then 1.1157 + // we might have failed to insert due to colliding with another entry for 1.1158 + // the same index in which case we should ignore it. 1.1159 + 1.1160 + for (int32_t j = (int32_t)i - 1; 1.1161 + j >= 0 && aUpdateInfoArray[j].indexId == updateInfo.indexId; 1.1162 + --j) { 1.1163 + if (updateInfo.value == aUpdateInfoArray[j].value) { 1.1164 + // We found a key with the same value for the same index. So we 1.1165 + // must have had a collision with a value we just inserted. 1.1166 + rv = NS_OK; 1.1167 + break; 1.1168 + } 1.1169 + } 1.1170 + } 1.1171 + 1.1172 + if (NS_FAILED(rv)) { 1.1173 + return rv; 1.1174 + } 1.1175 + } 1.1176 + 1.1177 + return NS_OK; 1.1178 +} 1.1179 + 1.1180 +// static 1.1181 +nsresult 1.1182 +IDBObjectStore::GetStructuredCloneReadInfoFromStatement( 1.1183 + mozIStorageStatement* aStatement, 1.1184 + uint32_t aDataIndex, 1.1185 + uint32_t aFileIdsIndex, 1.1186 + IDBDatabase* aDatabase, 1.1187 + StructuredCloneReadInfo& aInfo) 1.1188 +{ 1.1189 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.1190 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.1191 + 1.1192 + PROFILER_LABEL("IndexedDB", 1.1193 + "IDBObjectStore::GetStructuredCloneReadInfoFromStatement"); 1.1194 + 1.1195 +#ifdef DEBUG 1.1196 + { 1.1197 + int32_t type; 1.1198 + NS_ASSERTION(NS_SUCCEEDED(aStatement->GetTypeOfIndex(aDataIndex, &type)) && 1.1199 + type == mozIStorageStatement::VALUE_TYPE_BLOB, 1.1200 + "Bad value type!"); 1.1201 + } 1.1202 +#endif 1.1203 + 1.1204 + const uint8_t* blobData; 1.1205 + uint32_t blobDataLength; 1.1206 + nsresult rv = aStatement->GetSharedBlob(aDataIndex, &blobDataLength, 1.1207 + &blobData); 1.1208 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.1209 + 1.1210 + const char* compressed = reinterpret_cast<const char*>(blobData); 1.1211 + size_t compressedLength = size_t(blobDataLength); 1.1212 + 1.1213 + static const fallible_t fallible = fallible_t(); 1.1214 + 1.1215 + size_t uncompressedLength; 1.1216 + if (!snappy::GetUncompressedLength(compressed, compressedLength, 1.1217 + &uncompressedLength)) { 1.1218 + IDB_WARNING("Snappy can't determine uncompressed length!"); 1.1219 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.1220 + } 1.1221 + 1.1222 + nsAutoArrayPtr<char> uncompressed(new (fallible) char[uncompressedLength]); 1.1223 + NS_ENSURE_TRUE(uncompressed, NS_ERROR_OUT_OF_MEMORY); 1.1224 + 1.1225 + if (!snappy::RawUncompress(compressed, compressedLength, 1.1226 + uncompressed.get())) { 1.1227 + IDB_WARNING("Snappy can't determine uncompressed length!"); 1.1228 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.1229 + } 1.1230 + 1.1231 + JSAutoStructuredCloneBuffer& buffer = aInfo.mCloneBuffer; 1.1232 + if (!buffer.copy(reinterpret_cast<const uint64_t *>(uncompressed.get()), 1.1233 + uncompressedLength)) { 1.1234 + IDB_REPORT_INTERNAL_ERR(); 1.1235 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.1236 + } 1.1237 + 1.1238 + bool isNull; 1.1239 + rv = aStatement->GetIsNull(aFileIdsIndex, &isNull); 1.1240 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.1241 + 1.1242 + if (!isNull) { 1.1243 + nsString ids; 1.1244 + rv = aStatement->GetString(aFileIdsIndex, ids); 1.1245 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.1246 + 1.1247 + nsAutoTArray<int64_t, 10> array; 1.1248 + rv = ConvertFileIdsToArray(ids, array); 1.1249 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.1250 + 1.1251 + FileManager* fileManager = aDatabase->Manager(); 1.1252 + 1.1253 + for (uint32_t i = 0; i < array.Length(); i++) { 1.1254 + const int64_t& id = array[i]; 1.1255 + 1.1256 + nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(id); 1.1257 + NS_ASSERTION(fileInfo, "Null file info!"); 1.1258 + 1.1259 + StructuredCloneFile* file = aInfo.mFiles.AppendElement(); 1.1260 + file->mFileInfo.swap(fileInfo); 1.1261 + } 1.1262 + } 1.1263 + 1.1264 + aInfo.mDatabase = aDatabase; 1.1265 + 1.1266 + return NS_OK; 1.1267 +} 1.1268 + 1.1269 +// static 1.1270 +void 1.1271 +IDBObjectStore::ClearCloneWriteInfo(StructuredCloneWriteInfo& aWriteInfo) 1.1272 +{ 1.1273 + // This is kind of tricky, we only want to release stuff on the main thread, 1.1274 + // but we can end up being called on other threads if we have already been 1.1275 + // cleared on the main thread. 1.1276 + if (!aWriteInfo.mCloneBuffer.data() && !aWriteInfo.mFiles.Length()) { 1.1277 + return; 1.1278 + } 1.1279 + 1.1280 + // If there's something to clear, we should be on the main thread. 1.1281 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.1282 + 1.1283 + ClearStructuredCloneBuffer(aWriteInfo.mCloneBuffer); 1.1284 + aWriteInfo.mFiles.Clear(); 1.1285 +} 1.1286 + 1.1287 +// static 1.1288 +void 1.1289 +IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo) 1.1290 +{ 1.1291 + // This is kind of tricky, we only want to release stuff on the main thread, 1.1292 + // but we can end up being called on other threads if we have already been 1.1293 + // cleared on the main thread. 1.1294 + if (!aReadInfo.mCloneBuffer.data() && !aReadInfo.mFiles.Length()) { 1.1295 + return; 1.1296 + } 1.1297 + 1.1298 + // If there's something to clear, we should be on the main thread. 1.1299 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.1300 + 1.1301 + ClearStructuredCloneBuffer(aReadInfo.mCloneBuffer); 1.1302 + aReadInfo.mFiles.Clear(); 1.1303 +} 1.1304 + 1.1305 +// static 1.1306 +void 1.1307 +IDBObjectStore::ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer) 1.1308 +{ 1.1309 + if (aBuffer.data()) { 1.1310 + aBuffer.clear(); 1.1311 + } 1.1312 +} 1.1313 + 1.1314 +// static 1.1315 +bool 1.1316 +IDBObjectStore::DeserializeValue(JSContext* aCx, 1.1317 + StructuredCloneReadInfo& aCloneReadInfo, 1.1318 + JS::MutableHandle<JS::Value> aValue) 1.1319 +{ 1.1320 + NS_ASSERTION(NS_IsMainThread(), 1.1321 + "Should only be deserializing on the main thread!"); 1.1322 + NS_ASSERTION(aCx, "A JSContext is required!"); 1.1323 + 1.1324 + JSAutoStructuredCloneBuffer& buffer = aCloneReadInfo.mCloneBuffer; 1.1325 + 1.1326 + if (!buffer.data()) { 1.1327 + aValue.setUndefined(); 1.1328 + return true; 1.1329 + } 1.1330 + 1.1331 + JSAutoRequest ar(aCx); 1.1332 + 1.1333 + JSStructuredCloneCallbacks callbacks = { 1.1334 + IDBObjectStore::StructuredCloneReadCallback<MainThreadDeserializationTraits>, 1.1335 + nullptr, 1.1336 + nullptr, 1.1337 + nullptr, 1.1338 + nullptr, 1.1339 + nullptr 1.1340 + }; 1.1341 + 1.1342 + return buffer.read(aCx, aValue, &callbacks, &aCloneReadInfo); 1.1343 +} 1.1344 + 1.1345 +// static 1.1346 +bool 1.1347 +IDBObjectStore::SerializeValue(JSContext* aCx, 1.1348 + StructuredCloneWriteInfo& aCloneWriteInfo, 1.1349 + JS::Handle<JS::Value> aValue) 1.1350 +{ 1.1351 + NS_ASSERTION(NS_IsMainThread(), 1.1352 + "Should only be serializing on the main thread!"); 1.1353 + NS_ASSERTION(aCx, "A JSContext is required!"); 1.1354 + 1.1355 + JSAutoRequest ar(aCx); 1.1356 + 1.1357 + JSStructuredCloneCallbacks callbacks = { 1.1358 + nullptr, 1.1359 + StructuredCloneWriteCallback, 1.1360 + nullptr, 1.1361 + nullptr, 1.1362 + nullptr, 1.1363 + nullptr 1.1364 + }; 1.1365 + 1.1366 + JSAutoStructuredCloneBuffer& buffer = aCloneWriteInfo.mCloneBuffer; 1.1367 + 1.1368 + return buffer.write(aCx, aValue, &callbacks, &aCloneWriteInfo); 1.1369 +} 1.1370 + 1.1371 +static inline bool 1.1372 +StructuredCloneReadString(JSStructuredCloneReader* aReader, 1.1373 + nsCString& aString) 1.1374 +{ 1.1375 + uint32_t length; 1.1376 + if (!JS_ReadBytes(aReader, &length, sizeof(uint32_t))) { 1.1377 + NS_WARNING("Failed to read length!"); 1.1378 + return false; 1.1379 + } 1.1380 + length = NativeEndian::swapFromLittleEndian(length); 1.1381 + 1.1382 + if (!aString.SetLength(length, fallible_t())) { 1.1383 + NS_WARNING("Out of memory?"); 1.1384 + return false; 1.1385 + } 1.1386 + char* buffer = aString.BeginWriting(); 1.1387 + 1.1388 + if (!JS_ReadBytes(aReader, buffer, length)) { 1.1389 + NS_WARNING("Failed to read type!"); 1.1390 + return false; 1.1391 + } 1.1392 + 1.1393 + return true; 1.1394 +} 1.1395 + 1.1396 +// static 1.1397 +bool 1.1398 +IDBObjectStore::ReadFileHandle(JSStructuredCloneReader* aReader, 1.1399 + FileHandleData* aRetval) 1.1400 +{ 1.1401 + static_assert(SCTAG_DOM_FILEHANDLE == 0xFFFF8004, 1.1402 + "Update me!"); 1.1403 + MOZ_ASSERT(aReader && aRetval); 1.1404 + 1.1405 + nsCString type; 1.1406 + if (!StructuredCloneReadString(aReader, type)) { 1.1407 + return false; 1.1408 + } 1.1409 + CopyUTF8toUTF16(type, aRetval->type); 1.1410 + 1.1411 + nsCString name; 1.1412 + if (!StructuredCloneReadString(aReader, name)) { 1.1413 + return false; 1.1414 + } 1.1415 + CopyUTF8toUTF16(name, aRetval->name); 1.1416 + 1.1417 + return true; 1.1418 +} 1.1419 + 1.1420 +// static 1.1421 +bool 1.1422 +IDBObjectStore::ReadBlobOrFile(JSStructuredCloneReader* aReader, 1.1423 + uint32_t aTag, 1.1424 + BlobOrFileData* aRetval) 1.1425 +{ 1.1426 + static_assert(SCTAG_DOM_BLOB == 0xFFFF8001 && 1.1427 + SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xFFFF8002 && 1.1428 + SCTAG_DOM_FILE == 0xFFFF8005, 1.1429 + "Update me!"); 1.1430 + MOZ_ASSERT(aReader && aRetval); 1.1431 + MOZ_ASSERT(aTag == SCTAG_DOM_FILE || 1.1432 + aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE || 1.1433 + aTag == SCTAG_DOM_BLOB); 1.1434 + 1.1435 + aRetval->tag = aTag; 1.1436 + 1.1437 + // If it's not a FileHandle, it's a Blob or a File. 1.1438 + uint64_t size; 1.1439 + if (!JS_ReadBytes(aReader, &size, sizeof(uint64_t))) { 1.1440 + NS_WARNING("Failed to read size!"); 1.1441 + return false; 1.1442 + } 1.1443 + aRetval->size = NativeEndian::swapFromLittleEndian(size); 1.1444 + 1.1445 + nsCString type; 1.1446 + if (!StructuredCloneReadString(aReader, type)) { 1.1447 + return false; 1.1448 + } 1.1449 + CopyUTF8toUTF16(type, aRetval->type); 1.1450 + 1.1451 + // Blobs are done. 1.1452 + if (aTag == SCTAG_DOM_BLOB) { 1.1453 + return true; 1.1454 + } 1.1455 + 1.1456 + NS_ASSERTION(aTag == SCTAG_DOM_FILE || 1.1457 + aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE, "Huh?!"); 1.1458 + 1.1459 + uint64_t lastModifiedDate; 1.1460 + if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE) { 1.1461 + lastModifiedDate = UINT64_MAX; 1.1462 + } 1.1463 + else { 1.1464 + if(!JS_ReadBytes(aReader, &lastModifiedDate, sizeof(lastModifiedDate))) { 1.1465 + NS_WARNING("Failed to read lastModifiedDate"); 1.1466 + return false; 1.1467 + } 1.1468 + lastModifiedDate = NativeEndian::swapFromLittleEndian(lastModifiedDate); 1.1469 + } 1.1470 + aRetval->lastModifiedDate = lastModifiedDate; 1.1471 + 1.1472 + nsCString name; 1.1473 + if (!StructuredCloneReadString(aReader, name)) { 1.1474 + return false; 1.1475 + } 1.1476 + CopyUTF8toUTF16(name, aRetval->name); 1.1477 + 1.1478 + return true; 1.1479 +} 1.1480 + 1.1481 +// static 1.1482 +template <class DeserializationTraits> 1.1483 +JSObject* 1.1484 +IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx, 1.1485 + JSStructuredCloneReader* aReader, 1.1486 + uint32_t aTag, 1.1487 + uint32_t aData, 1.1488 + void* aClosure) 1.1489 +{ 1.1490 + // We need to statically assert that our tag values are what we expect 1.1491 + // so that if people accidentally change them they notice. 1.1492 + static_assert(SCTAG_DOM_BLOB == 0xFFFF8001 && 1.1493 + SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xFFFF8002 && 1.1494 + SCTAG_DOM_FILEHANDLE == 0xFFFF8004 && 1.1495 + SCTAG_DOM_FILE == 0xFFFF8005, 1.1496 + "You changed our structured clone tag values and just ate " 1.1497 + "everyone's IndexedDB data. I hope you are happy."); 1.1498 + 1.1499 + if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE || 1.1500 + aTag == SCTAG_DOM_FILEHANDLE || 1.1501 + aTag == SCTAG_DOM_BLOB || 1.1502 + aTag == SCTAG_DOM_FILE) { 1.1503 + StructuredCloneReadInfo* cloneReadInfo = 1.1504 + reinterpret_cast<StructuredCloneReadInfo*>(aClosure); 1.1505 + 1.1506 + if (aData >= cloneReadInfo->mFiles.Length()) { 1.1507 + NS_ERROR("Bad blob index!"); 1.1508 + return nullptr; 1.1509 + } 1.1510 + 1.1511 + StructuredCloneFile& file = cloneReadInfo->mFiles[aData]; 1.1512 + IDBDatabase* database = cloneReadInfo->mDatabase; 1.1513 + 1.1514 + if (aTag == SCTAG_DOM_FILEHANDLE) { 1.1515 + FileHandleData data; 1.1516 + if (!ReadFileHandle(aReader, &data)) { 1.1517 + return nullptr; 1.1518 + } 1.1519 + 1.1520 + return DeserializationTraits::CreateAndWrapFileHandle(aCx, database, 1.1521 + file, data); 1.1522 + } 1.1523 + 1.1524 + BlobOrFileData data; 1.1525 + if (!ReadBlobOrFile(aReader, aTag, &data)) { 1.1526 + return nullptr; 1.1527 + } 1.1528 + 1.1529 + return DeserializationTraits::CreateAndWrapBlobOrFile(aCx, database, 1.1530 + file, data); 1.1531 + } 1.1532 + 1.1533 + const JSStructuredCloneCallbacks* runtimeCallbacks = 1.1534 + js::GetContextStructuredCloneCallbacks(aCx); 1.1535 + 1.1536 + if (runtimeCallbacks) { 1.1537 + return runtimeCallbacks->read(aCx, aReader, aTag, aData, nullptr); 1.1538 + } 1.1539 + 1.1540 + return nullptr; 1.1541 +} 1.1542 + 1.1543 +// static 1.1544 +bool 1.1545 +IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx, 1.1546 + JSStructuredCloneWriter* aWriter, 1.1547 + JS::Handle<JSObject*> aObj, 1.1548 + void* aClosure) 1.1549 +{ 1.1550 + StructuredCloneWriteInfo* cloneWriteInfo = 1.1551 + reinterpret_cast<StructuredCloneWriteInfo*>(aClosure); 1.1552 + 1.1553 + if (JS_GetClass(aObj) == &sDummyPropJSClass) { 1.1554 + NS_ASSERTION(cloneWriteInfo->mOffsetToKeyProp == 0, 1.1555 + "We should not have been here before!"); 1.1556 + cloneWriteInfo->mOffsetToKeyProp = js_GetSCOffset(aWriter); 1.1557 + 1.1558 + uint64_t value = 0; 1.1559 + // Omit endian swap 1.1560 + return JS_WriteBytes(aWriter, &value, sizeof(value)); 1.1561 + } 1.1562 + 1.1563 + IDBTransaction* transaction = cloneWriteInfo->mTransaction; 1.1564 + FileManager* fileManager = transaction->Database()->Manager(); 1.1565 + 1.1566 + file::FileHandle* fileHandle = nullptr; 1.1567 + if (NS_SUCCEEDED(UNWRAP_OBJECT(FileHandle, aObj, fileHandle))) { 1.1568 + nsRefPtr<FileInfo> fileInfo = fileHandle->GetFileInfo(); 1.1569 + 1.1570 + // Throw when trying to store non IDB file handles or IDB file handles 1.1571 + // across databases. 1.1572 + if (!fileInfo || fileInfo->Manager() != fileManager) { 1.1573 + return false; 1.1574 + } 1.1575 + 1.1576 + NS_ConvertUTF16toUTF8 convType(fileHandle->Type()); 1.1577 + uint32_t convTypeLength = 1.1578 + NativeEndian::swapToLittleEndian(convType.Length()); 1.1579 + 1.1580 + NS_ConvertUTF16toUTF8 convName(fileHandle->Name()); 1.1581 + uint32_t convNameLength = 1.1582 + NativeEndian::swapToLittleEndian(convName.Length()); 1.1583 + 1.1584 + if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILEHANDLE, 1.1585 + cloneWriteInfo->mFiles.Length()) || 1.1586 + !JS_WriteBytes(aWriter, &convTypeLength, sizeof(uint32_t)) || 1.1587 + !JS_WriteBytes(aWriter, convType.get(), convType.Length()) || 1.1588 + !JS_WriteBytes(aWriter, &convNameLength, sizeof(uint32_t)) || 1.1589 + !JS_WriteBytes(aWriter, convName.get(), convName.Length())) { 1.1590 + return false; 1.1591 + } 1.1592 + 1.1593 + StructuredCloneFile* file = cloneWriteInfo->mFiles.AppendElement(); 1.1594 + file->mFileInfo = fileInfo.forget(); 1.1595 + 1.1596 + return true; 1.1597 + } 1.1598 + 1.1599 + nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative; 1.1600 + nsContentUtils::XPConnect()-> 1.1601 + GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative)); 1.1602 + 1.1603 + if (wrappedNative) { 1.1604 + nsISupports* supports = wrappedNative->Native(); 1.1605 + 1.1606 + nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports); 1.1607 + if (blob) { 1.1608 + nsCOMPtr<nsIInputStream> inputStream; 1.1609 + 1.1610 + // Check if it is a blob created from this db or the blob was already 1.1611 + // stored in this db 1.1612 + nsRefPtr<FileInfo> fileInfo = transaction->GetFileInfo(blob); 1.1613 + if (!fileInfo && fileManager) { 1.1614 + fileInfo = blob->GetFileInfo(fileManager); 1.1615 + 1.1616 + if (!fileInfo) { 1.1617 + fileInfo = fileManager->GetNewFileInfo(); 1.1618 + if (!fileInfo) { 1.1619 + NS_WARNING("Failed to get new file info!"); 1.1620 + return false; 1.1621 + } 1.1622 + 1.1623 + if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) { 1.1624 + NS_WARNING("Failed to get internal steam!"); 1.1625 + return false; 1.1626 + } 1.1627 + 1.1628 + transaction->AddFileInfo(blob, fileInfo); 1.1629 + } 1.1630 + } 1.1631 + 1.1632 + uint64_t size; 1.1633 + if (NS_FAILED(blob->GetSize(&size))) { 1.1634 + NS_WARNING("Failed to get size!"); 1.1635 + return false; 1.1636 + } 1.1637 + size = NativeEndian::swapToLittleEndian(size); 1.1638 + 1.1639 + nsString type; 1.1640 + if (NS_FAILED(blob->GetType(type))) { 1.1641 + NS_WARNING("Failed to get type!"); 1.1642 + return false; 1.1643 + } 1.1644 + NS_ConvertUTF16toUTF8 convType(type); 1.1645 + uint32_t convTypeLength = 1.1646 + NativeEndian::swapToLittleEndian(convType.Length()); 1.1647 + 1.1648 + nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob); 1.1649 + 1.1650 + if (!JS_WriteUint32Pair(aWriter, file ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB, 1.1651 + cloneWriteInfo->mFiles.Length()) || 1.1652 + !JS_WriteBytes(aWriter, &size, sizeof(size)) || 1.1653 + !JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) || 1.1654 + !JS_WriteBytes(aWriter, convType.get(), convType.Length())) { 1.1655 + return false; 1.1656 + } 1.1657 + 1.1658 + if (file) { 1.1659 + uint64_t lastModifiedDate = 0; 1.1660 + if (NS_FAILED(file->GetMozLastModifiedDate(&lastModifiedDate))) { 1.1661 + NS_WARNING("Failed to get last modified date!"); 1.1662 + return false; 1.1663 + } 1.1664 + 1.1665 + lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate); 1.1666 + 1.1667 + nsString name; 1.1668 + if (NS_FAILED(file->GetName(name))) { 1.1669 + NS_WARNING("Failed to get name!"); 1.1670 + return false; 1.1671 + } 1.1672 + NS_ConvertUTF16toUTF8 convName(name); 1.1673 + uint32_t convNameLength = 1.1674 + NativeEndian::swapToLittleEndian(convName.Length()); 1.1675 + 1.1676 + if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) || 1.1677 + !JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) || 1.1678 + !JS_WriteBytes(aWriter, convName.get(), convName.Length())) { 1.1679 + return false; 1.1680 + } 1.1681 + } 1.1682 + 1.1683 + StructuredCloneFile* cloneFile = cloneWriteInfo->mFiles.AppendElement(); 1.1684 + cloneFile->mFile = blob.forget(); 1.1685 + cloneFile->mFileInfo = fileInfo.forget(); 1.1686 + cloneFile->mInputStream = inputStream.forget(); 1.1687 + 1.1688 + return true; 1.1689 + } 1.1690 + } 1.1691 + 1.1692 + // try using the runtime callbacks 1.1693 + const JSStructuredCloneCallbacks* runtimeCallbacks = 1.1694 + js::GetContextStructuredCloneCallbacks(aCx); 1.1695 + if (runtimeCallbacks) { 1.1696 + return runtimeCallbacks->write(aCx, aWriter, aObj, nullptr); 1.1697 + } 1.1698 + 1.1699 + return false; 1.1700 +} 1.1701 + 1.1702 +// static 1.1703 +nsresult 1.1704 +IDBObjectStore::ConvertFileIdsToArray(const nsAString& aFileIds, 1.1705 + nsTArray<int64_t>& aResult) 1.1706 +{ 1.1707 + nsCharSeparatedTokenizerTemplate<IgnoreNothing> tokenizer(aFileIds, ' '); 1.1708 + 1.1709 + while (tokenizer.hasMoreTokens()) { 1.1710 + nsString token(tokenizer.nextToken()); 1.1711 + 1.1712 + NS_ASSERTION(!token.IsEmpty(), "Should be a valid id!"); 1.1713 + 1.1714 + nsresult rv; 1.1715 + int32_t id = token.ToInteger(&rv); 1.1716 + NS_ENSURE_SUCCESS(rv, rv); 1.1717 + 1.1718 + int64_t* element = aResult.AppendElement(); 1.1719 + *element = id; 1.1720 + } 1.1721 + 1.1722 + return NS_OK; 1.1723 +} 1.1724 + 1.1725 +// static 1.1726 +void 1.1727 +IDBObjectStore::ConvertActorsToBlobs( 1.1728 + const InfallibleTArray<PBlobChild*>& aActors, 1.1729 + nsTArray<StructuredCloneFile>& aFiles) 1.1730 +{ 1.1731 + NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.1732 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.1733 + NS_ASSERTION(aFiles.IsEmpty(), "Should be empty!"); 1.1734 + 1.1735 + if (!aActors.IsEmpty()) { 1.1736 + NS_ASSERTION(ContentChild::GetSingleton(), "This should never be null!"); 1.1737 + 1.1738 + uint32_t length = aActors.Length(); 1.1739 + aFiles.SetCapacity(length); 1.1740 + 1.1741 + for (uint32_t index = 0; index < length; index++) { 1.1742 + BlobChild* actor = static_cast<BlobChild*>(aActors[index]); 1.1743 + 1.1744 + StructuredCloneFile* file = aFiles.AppendElement(); 1.1745 + file->mFile = actor->GetBlob(); 1.1746 + } 1.1747 + } 1.1748 +} 1.1749 + 1.1750 +// static 1.1751 +nsresult 1.1752 +IDBObjectStore::ConvertBlobsToActors( 1.1753 + ContentParent* aContentParent, 1.1754 + FileManager* aFileManager, 1.1755 + const nsTArray<StructuredCloneFile>& aFiles, 1.1756 + InfallibleTArray<PBlobParent*>& aActors) 1.1757 +{ 1.1758 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.1759 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.1760 + NS_ASSERTION(aContentParent, "Null contentParent!"); 1.1761 + NS_ASSERTION(aFileManager, "Null file manager!"); 1.1762 + 1.1763 + if (!aFiles.IsEmpty()) { 1.1764 + nsCOMPtr<nsIFile> directory = aFileManager->GetDirectory(); 1.1765 + if (!directory) { 1.1766 + IDB_WARNING("Failed to get directory!"); 1.1767 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.1768 + } 1.1769 + 1.1770 + uint32_t fileCount = aFiles.Length(); 1.1771 + aActors.SetCapacity(fileCount); 1.1772 + 1.1773 + for (uint32_t index = 0; index < fileCount; index++) { 1.1774 + const StructuredCloneFile& file = aFiles[index]; 1.1775 + NS_ASSERTION(file.mFileInfo, "This should never be null!"); 1.1776 + 1.1777 + nsCOMPtr<nsIFile> nativeFile = 1.1778 + aFileManager->GetFileForId(directory, file.mFileInfo->Id()); 1.1779 + if (!nativeFile) { 1.1780 + IDB_WARNING("Failed to get file!"); 1.1781 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.1782 + } 1.1783 + 1.1784 + nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(nativeFile, file.mFileInfo); 1.1785 + 1.1786 + BlobParent* actor = 1.1787 + aContentParent->GetOrCreateActorForBlob(blob); 1.1788 + if (!actor) { 1.1789 + // This can only fail if the child has crashed. 1.1790 + IDB_REPORT_INTERNAL_ERR(); 1.1791 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.1792 + } 1.1793 + 1.1794 + aActors.AppendElement(actor); 1.1795 + } 1.1796 + } 1.1797 + 1.1798 + return NS_OK; 1.1799 +} 1.1800 + 1.1801 +IDBObjectStore::IDBObjectStore() 1.1802 +: mId(INT64_MIN), 1.1803 + mKeyPath(0), 1.1804 + mCachedKeyPath(JSVAL_VOID), 1.1805 + mRooted(false), 1.1806 + mAutoIncrement(false), 1.1807 + mActorChild(nullptr), 1.1808 + mActorParent(nullptr) 1.1809 +{ 1.1810 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.1811 + 1.1812 + SetIsDOMBinding(); 1.1813 +} 1.1814 + 1.1815 +IDBObjectStore::~IDBObjectStore() 1.1816 +{ 1.1817 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.1818 + NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!"); 1.1819 + if (mActorChild) { 1.1820 + NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.1821 + mActorChild->Send__delete__(mActorChild); 1.1822 + NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!"); 1.1823 + } 1.1824 + 1.1825 + if (mRooted) { 1.1826 + mCachedKeyPath = JSVAL_VOID; 1.1827 + mozilla::DropJSObjects(this); 1.1828 + } 1.1829 +} 1.1830 + 1.1831 +nsresult 1.1832 +IDBObjectStore::GetAddInfo(JSContext* aCx, 1.1833 + JS::Handle<JS::Value> aValue, 1.1834 + JS::Handle<JS::Value> aKeyVal, 1.1835 + StructuredCloneWriteInfo& aCloneWriteInfo, 1.1836 + Key& aKey, 1.1837 + nsTArray<IndexUpdateInfo>& aUpdateInfoArray) 1.1838 +{ 1.1839 + nsresult rv; 1.1840 + 1.1841 + // Return DATA_ERR if a key was passed in and this objectStore uses inline 1.1842 + // keys. 1.1843 + if (!JSVAL_IS_VOID(aKeyVal) && HasValidKeyPath()) { 1.1844 + return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; 1.1845 + } 1.1846 + 1.1847 + JSAutoRequest ar(aCx); 1.1848 + 1.1849 + if (!HasValidKeyPath()) { 1.1850 + // Out-of-line keys must be passed in. 1.1851 + rv = aKey.SetFromJSVal(aCx, aKeyVal); 1.1852 + if (NS_FAILED(rv)) { 1.1853 + return rv; 1.1854 + } 1.1855 + } 1.1856 + else if (!mAutoIncrement) { 1.1857 + rv = GetKeyPath().ExtractKey(aCx, aValue, aKey); 1.1858 + if (NS_FAILED(rv)) { 1.1859 + return rv; 1.1860 + } 1.1861 + } 1.1862 + 1.1863 + // Return DATA_ERR if no key was specified this isn't an autoIncrement 1.1864 + // objectStore. 1.1865 + if (aKey.IsUnset() && !mAutoIncrement) { 1.1866 + return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; 1.1867 + } 1.1868 + 1.1869 + // Figure out indexes and the index values to update here. 1.1870 + uint32_t count = mInfo->indexes.Length(); 1.1871 + aUpdateInfoArray.SetCapacity(count); // Pretty good estimate 1.1872 + for (uint32_t indexesIndex = 0; indexesIndex < count; indexesIndex++) { 1.1873 + const IndexInfo& indexInfo = mInfo->indexes[indexesIndex]; 1.1874 + 1.1875 + rv = AppendIndexUpdateInfo(indexInfo.id, indexInfo.keyPath, 1.1876 + indexInfo.unique, indexInfo.multiEntry, aCx, 1.1877 + aValue, aUpdateInfoArray); 1.1878 + NS_ENSURE_SUCCESS(rv, rv); 1.1879 + } 1.1880 + 1.1881 + GetAddInfoClosure data = {this, aCloneWriteInfo, aValue}; 1.1882 + 1.1883 + if (mAutoIncrement && HasValidKeyPath()) { 1.1884 + NS_ASSERTION(aKey.IsUnset(), "Shouldn't have gotten the key yet!"); 1.1885 + 1.1886 + rv = GetKeyPath().ExtractOrCreateKey(aCx, aValue, aKey, 1.1887 + &GetAddInfoCallback, &data); 1.1888 + } 1.1889 + else { 1.1890 + rv = GetAddInfoCallback(aCx, &data); 1.1891 + } 1.1892 + 1.1893 + return rv; 1.1894 +} 1.1895 + 1.1896 +already_AddRefed<IDBRequest> 1.1897 +IDBObjectStore::AddOrPut(JSContext* aCx, JS::Handle<JS::Value> aValue, 1.1898 + JS::Handle<JS::Value> aKey, 1.1899 + bool aOverwrite, ErrorResult& aRv) 1.1900 +{ 1.1901 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.1902 + 1.1903 + if (!mTransaction->IsOpen()) { 1.1904 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.1905 + return nullptr; 1.1906 + } 1.1907 + 1.1908 + if (!IsWriteAllowed()) { 1.1909 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); 1.1910 + return nullptr; 1.1911 + } 1.1912 + 1.1913 + StructuredCloneWriteInfo cloneWriteInfo; 1.1914 + Key key; 1.1915 + nsTArray<IndexUpdateInfo> updateInfo; 1.1916 + 1.1917 + JS::Rooted<JS::Value> value(aCx, aValue); 1.1918 + aRv = GetAddInfo(aCx, value, aKey, cloneWriteInfo, key, updateInfo); 1.1919 + if (aRv.Failed()) { 1.1920 + return nullptr; 1.1921 + } 1.1922 + 1.1923 + nsRefPtr<IDBRequest> request = GenerateRequest(this); 1.1924 + if (!request) { 1.1925 + IDB_WARNING("Failed to generate request!"); 1.1926 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.1927 + return nullptr; 1.1928 + } 1.1929 + 1.1930 + nsRefPtr<AddHelper> helper = 1.1931 + new AddHelper(mTransaction, request, this, Move(cloneWriteInfo), key, 1.1932 + aOverwrite, updateInfo); 1.1933 + 1.1934 + nsresult rv = helper->DispatchToTransactionPool(); 1.1935 + if (NS_FAILED(rv)) { 1.1936 + IDB_WARNING("Failed to dispatch!"); 1.1937 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.1938 + return nullptr; 1.1939 + } 1.1940 + 1.1941 +#ifdef IDB_PROFILER_USE_MARKS 1.1942 + if (aOverwrite) { 1.1943 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.1944 + "database(%s).transaction(%s).objectStore(%s).%s(%s)", 1.1945 + "IDBRequest[%llu] MT IDBObjectStore.put()", 1.1946 + request->GetSerialNumber(), 1.1947 + IDB_PROFILER_STRING(Transaction()->Database()), 1.1948 + IDB_PROFILER_STRING(Transaction()), 1.1949 + IDB_PROFILER_STRING(this), 1.1950 + key.IsUnset() ? "" : IDB_PROFILER_STRING(key)); 1.1951 + } 1.1952 + else { 1.1953 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.1954 + "database(%s).transaction(%s).objectStore(%s).add(%s)", 1.1955 + "IDBRequest[%llu] MT IDBObjectStore.add()", 1.1956 + request->GetSerialNumber(), 1.1957 + IDB_PROFILER_STRING(Transaction()->Database()), 1.1958 + IDB_PROFILER_STRING(Transaction()), 1.1959 + IDB_PROFILER_STRING(this), 1.1960 + key.IsUnset() ? "" : IDB_PROFILER_STRING(key)); 1.1961 + } 1.1962 +#endif 1.1963 + 1.1964 + return request.forget(); 1.1965 +} 1.1966 + 1.1967 +nsresult 1.1968 +IDBObjectStore::AddOrPutInternal( 1.1969 + const SerializedStructuredCloneWriteInfo& aCloneWriteInfo, 1.1970 + const Key& aKey, 1.1971 + const InfallibleTArray<IndexUpdateInfo>& aUpdateInfoArray, 1.1972 + const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs, 1.1973 + bool aOverwrite, 1.1974 + IDBRequest** _retval) 1.1975 +{ 1.1976 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.1977 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.1978 + 1.1979 + if (!mTransaction->IsOpen()) { 1.1980 + return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR; 1.1981 + } 1.1982 + 1.1983 + if (!IsWriteAllowed()) { 1.1984 + return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR; 1.1985 + } 1.1986 + 1.1987 + nsRefPtr<IDBRequest> request = GenerateRequest(this); 1.1988 + IDB_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.1989 + 1.1990 + StructuredCloneWriteInfo cloneWriteInfo; 1.1991 + if (!cloneWriteInfo.SetFromSerialized(aCloneWriteInfo)) { 1.1992 + IDB_WARNING("Failed to copy structured clone buffer!"); 1.1993 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.1994 + } 1.1995 + 1.1996 + if (!aBlobs.IsEmpty()) { 1.1997 + FileManager* fileManager = Transaction()->Database()->Manager(); 1.1998 + NS_ASSERTION(fileManager, "Null file manager?!"); 1.1999 + 1.2000 + uint32_t length = aBlobs.Length(); 1.2001 + cloneWriteInfo.mFiles.SetCapacity(length); 1.2002 + 1.2003 + for (uint32_t index = 0; index < length; index++) { 1.2004 + const nsCOMPtr<nsIDOMBlob>& blob = aBlobs[index]; 1.2005 + 1.2006 + nsCOMPtr<nsIInputStream> inputStream; 1.2007 + 1.2008 + nsRefPtr<FileInfo> fileInfo = Transaction()->GetFileInfo(blob); 1.2009 + if (!fileInfo) { 1.2010 + fileInfo = blob->GetFileInfo(fileManager); 1.2011 + 1.2012 + if (!fileInfo) { 1.2013 + fileInfo = fileManager->GetNewFileInfo(); 1.2014 + if (!fileInfo) { 1.2015 + IDB_WARNING("Failed to get new file info!"); 1.2016 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.2017 + } 1.2018 + 1.2019 + if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) { 1.2020 + IDB_WARNING("Failed to get internal steam!"); 1.2021 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.2022 + } 1.2023 + 1.2024 + // XXXbent This is where we should send a message back to the child to 1.2025 + // update the file id. 1.2026 + 1.2027 + Transaction()->AddFileInfo(blob, fileInfo); 1.2028 + } 1.2029 + } 1.2030 + 1.2031 + StructuredCloneFile* file = cloneWriteInfo.mFiles.AppendElement(); 1.2032 + file->mFile = blob; 1.2033 + file->mFileInfo.swap(fileInfo); 1.2034 + file->mInputStream.swap(inputStream); 1.2035 + } 1.2036 + } 1.2037 + 1.2038 + Key key(aKey); 1.2039 + 1.2040 + nsTArray<IndexUpdateInfo> updateInfo(aUpdateInfoArray); 1.2041 + 1.2042 + nsRefPtr<AddHelper> helper = 1.2043 + new AddHelper(mTransaction, request, this, Move(cloneWriteInfo), key, 1.2044 + aOverwrite, updateInfo); 1.2045 + 1.2046 + nsresult rv = helper->DispatchToTransactionPool(); 1.2047 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2048 + 1.2049 +#ifdef IDB_PROFILER_USE_MARKS 1.2050 + if (aOverwrite) { 1.2051 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.2052 + "database(%s).transaction(%s).objectStore(%s).%s(%s)", 1.2053 + "IDBRequest[%llu] MT IDBObjectStore.put()", 1.2054 + request->GetSerialNumber(), 1.2055 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2056 + IDB_PROFILER_STRING(Transaction()), 1.2057 + IDB_PROFILER_STRING(this), 1.2058 + key.IsUnset() ? "" : IDB_PROFILER_STRING(key)); 1.2059 + } 1.2060 + else { 1.2061 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.2062 + "database(%s).transaction(%s).objectStore(%s).add(%s)", 1.2063 + "IDBRequest[%llu] MT IDBObjectStore.add()", 1.2064 + request->GetSerialNumber(), 1.2065 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2066 + IDB_PROFILER_STRING(Transaction()), 1.2067 + IDB_PROFILER_STRING(this), 1.2068 + key.IsUnset() ? "" : IDB_PROFILER_STRING(key)); 1.2069 + } 1.2070 +#endif 1.2071 + 1.2072 + request.forget(_retval); 1.2073 + return NS_OK; 1.2074 +} 1.2075 + 1.2076 +already_AddRefed<IDBRequest> 1.2077 +IDBObjectStore::GetInternal(IDBKeyRange* aKeyRange, ErrorResult& aRv) 1.2078 +{ 1.2079 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2080 + NS_ASSERTION(aKeyRange, "Null pointer!"); 1.2081 + 1.2082 + if (!mTransaction->IsOpen()) { 1.2083 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2084 + return nullptr; 1.2085 + } 1.2086 + 1.2087 + nsRefPtr<IDBRequest> request = GenerateRequest(this); 1.2088 + if (!request) { 1.2089 + IDB_WARNING("Failed to generate request!"); 1.2090 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2091 + return nullptr; 1.2092 + } 1.2093 + 1.2094 + nsRefPtr<GetHelper> helper = 1.2095 + new GetHelper(mTransaction, request, this, aKeyRange); 1.2096 + 1.2097 + nsresult rv = helper->DispatchToTransactionPool(); 1.2098 + if (NS_FAILED(rv)) { 1.2099 + IDB_WARNING("Failed to dispatch!"); 1.2100 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2101 + return nullptr; 1.2102 + } 1.2103 + 1.2104 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.2105 + "database(%s).transaction(%s).objectStore(%s).get(%s)", 1.2106 + "IDBRequest[%llu] MT IDBObjectStore.get()", 1.2107 + request->GetSerialNumber(), 1.2108 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2109 + IDB_PROFILER_STRING(Transaction()), 1.2110 + IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange)); 1.2111 + 1.2112 + return request.forget(); 1.2113 +} 1.2114 + 1.2115 +already_AddRefed<IDBRequest> 1.2116 +IDBObjectStore::GetAllInternal(IDBKeyRange* aKeyRange, 1.2117 + uint32_t aLimit, ErrorResult& aRv) 1.2118 +{ 1.2119 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2120 + 1.2121 + if (!mTransaction->IsOpen()) { 1.2122 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2123 + return nullptr; 1.2124 + } 1.2125 + 1.2126 + nsRefPtr<IDBRequest> request = GenerateRequest(this); 1.2127 + if (!request) { 1.2128 + IDB_WARNING("Failed to generate request!"); 1.2129 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2130 + return nullptr; 1.2131 + } 1.2132 + 1.2133 + nsRefPtr<GetAllHelper> helper = 1.2134 + new GetAllHelper(mTransaction, request, this, aKeyRange, aLimit); 1.2135 + 1.2136 + nsresult rv = helper->DispatchToTransactionPool(); 1.2137 + if (NS_FAILED(rv)) { 1.2138 + IDB_WARNING("Failed to dispatch!"); 1.2139 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2140 + return nullptr; 1.2141 + } 1.2142 + 1.2143 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.2144 + "database(%s).transaction(%s).objectStore(%s)." 1.2145 + "getAll(%s, %lu)", 1.2146 + "IDBRequest[%llu] MT IDBObjectStore.getAll()", 1.2147 + request->GetSerialNumber(), 1.2148 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2149 + IDB_PROFILER_STRING(Transaction()), 1.2150 + IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange), 1.2151 + aLimit); 1.2152 + 1.2153 + return request.forget(); 1.2154 +} 1.2155 + 1.2156 +already_AddRefed<IDBRequest> 1.2157 +IDBObjectStore::GetAllKeysInternal(IDBKeyRange* aKeyRange, uint32_t aLimit, 1.2158 + ErrorResult& aRv) 1.2159 +{ 1.2160 + MOZ_ASSERT(NS_IsMainThread()); 1.2161 + 1.2162 + if (!mTransaction->IsOpen()) { 1.2163 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2164 + return nullptr; 1.2165 + } 1.2166 + 1.2167 + nsRefPtr<IDBRequest> request = GenerateRequest(this); 1.2168 + if (!request) { 1.2169 + IDB_WARNING("Failed to generate request!"); 1.2170 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2171 + return nullptr; 1.2172 + } 1.2173 + 1.2174 + nsRefPtr<GetAllKeysHelper> helper = 1.2175 + new GetAllKeysHelper(mTransaction, request, this, aKeyRange, aLimit); 1.2176 + 1.2177 + nsresult rv = helper->DispatchToTransactionPool(); 1.2178 + if (NS_FAILED(rv)) { 1.2179 + IDB_WARNING("Failed to dispatch!"); 1.2180 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2181 + return nullptr; 1.2182 + } 1.2183 + 1.2184 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.2185 + "database(%s).transaction(%s).objectStore(%s)." 1.2186 + "getAllKeys(%s, %lu)", 1.2187 + "IDBRequest[%llu] MT IDBObjectStore.getAllKeys()", 1.2188 + request->GetSerialNumber(), 1.2189 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2190 + IDB_PROFILER_STRING(Transaction()), 1.2191 + IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange), 1.2192 + aLimit); 1.2193 + 1.2194 + return request.forget(); 1.2195 +} 1.2196 + 1.2197 +already_AddRefed<IDBRequest> 1.2198 +IDBObjectStore::DeleteInternal(IDBKeyRange* aKeyRange, 1.2199 + ErrorResult& aRv) 1.2200 +{ 1.2201 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2202 + NS_ASSERTION(aKeyRange, "Null key range!"); 1.2203 + 1.2204 + if (!mTransaction->IsOpen()) { 1.2205 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2206 + return nullptr; 1.2207 + } 1.2208 + 1.2209 + if (!IsWriteAllowed()) { 1.2210 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); 1.2211 + return nullptr; 1.2212 + } 1.2213 + 1.2214 + nsRefPtr<IDBRequest> request = GenerateRequest(this); 1.2215 + if (!request) { 1.2216 + IDB_WARNING("Failed to generate request!"); 1.2217 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2218 + return nullptr; 1.2219 + } 1.2220 + 1.2221 + nsRefPtr<DeleteHelper> helper = 1.2222 + new DeleteHelper(mTransaction, request, this, aKeyRange); 1.2223 + 1.2224 + nsresult rv = helper->DispatchToTransactionPool(); 1.2225 + if (NS_FAILED(rv)) { 1.2226 + IDB_WARNING("Failed to dispatch!"); 1.2227 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2228 + return nullptr; 1.2229 + } 1.2230 + 1.2231 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.2232 + "database(%s).transaction(%s).objectStore(%s).delete(%s)", 1.2233 + "IDBRequest[%llu] MT IDBObjectStore.delete()", 1.2234 + request->GetSerialNumber(), 1.2235 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2236 + IDB_PROFILER_STRING(Transaction()), 1.2237 + IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange)); 1.2238 + 1.2239 + return request.forget(); 1.2240 +} 1.2241 + 1.2242 +already_AddRefed<IDBRequest> 1.2243 +IDBObjectStore::Clear(ErrorResult& aRv) 1.2244 +{ 1.2245 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2246 + 1.2247 + if (!mTransaction->IsOpen()) { 1.2248 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2249 + return nullptr; 1.2250 + } 1.2251 + 1.2252 + if (!IsWriteAllowed()) { 1.2253 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); 1.2254 + return nullptr; 1.2255 + } 1.2256 + 1.2257 + nsRefPtr<IDBRequest> request = GenerateRequest(this); 1.2258 + if (!request) { 1.2259 + IDB_WARNING("Failed to generate request!"); 1.2260 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2261 + return nullptr; 1.2262 + } 1.2263 + 1.2264 + nsRefPtr<ClearHelper> helper(new ClearHelper(mTransaction, request, this)); 1.2265 + 1.2266 + nsresult rv = helper->DispatchToTransactionPool(); 1.2267 + if (NS_FAILED(rv)) { 1.2268 + IDB_WARNING("Failed to dispatch!"); 1.2269 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2270 + return nullptr; 1.2271 + } 1.2272 + 1.2273 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.2274 + "database(%s).transaction(%s).objectStore(%s).clear()", 1.2275 + "IDBRequest[%llu] MT IDBObjectStore.clear()", 1.2276 + request->GetSerialNumber(), 1.2277 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2278 + IDB_PROFILER_STRING(Transaction()), 1.2279 + IDB_PROFILER_STRING(this)); 1.2280 + 1.2281 + return request.forget(); 1.2282 +} 1.2283 + 1.2284 +already_AddRefed<IDBRequest> 1.2285 +IDBObjectStore::CountInternal(IDBKeyRange* aKeyRange, ErrorResult& aRv) 1.2286 +{ 1.2287 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2288 + 1.2289 + if (!mTransaction->IsOpen()) { 1.2290 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2291 + return nullptr; 1.2292 + } 1.2293 + 1.2294 + nsRefPtr<IDBRequest> request = GenerateRequest(this); 1.2295 + if (!request) { 1.2296 + IDB_WARNING("Failed to generate request!"); 1.2297 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2298 + return nullptr; 1.2299 + } 1.2300 + 1.2301 + nsRefPtr<CountHelper> helper = 1.2302 + new CountHelper(mTransaction, request, this, aKeyRange); 1.2303 + nsresult rv = helper->DispatchToTransactionPool(); 1.2304 + if (NS_FAILED(rv)) { 1.2305 + IDB_WARNING("Failed to dispatch!"); 1.2306 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2307 + return nullptr; 1.2308 + } 1.2309 + 1.2310 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.2311 + "database(%s).transaction(%s).objectStore(%s).count(%s)", 1.2312 + "IDBRequest[%llu] MT IDBObjectStore.count()", 1.2313 + request->GetSerialNumber(), 1.2314 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2315 + IDB_PROFILER_STRING(Transaction()), 1.2316 + IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange)); 1.2317 + 1.2318 + return request.forget(); 1.2319 +} 1.2320 + 1.2321 +already_AddRefed<IDBRequest> 1.2322 +IDBObjectStore::OpenCursorInternal(IDBKeyRange* aKeyRange, 1.2323 + size_t aDirection, ErrorResult& aRv) 1.2324 +{ 1.2325 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2326 + 1.2327 + if (!mTransaction->IsOpen()) { 1.2328 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2329 + return nullptr; 1.2330 + } 1.2331 + 1.2332 + IDBCursor::Direction direction = 1.2333 + static_cast<IDBCursor::Direction>(aDirection); 1.2334 + 1.2335 + nsRefPtr<IDBRequest> request = GenerateRequest(this); 1.2336 + if (!request) { 1.2337 + IDB_WARNING("Failed to generate request!"); 1.2338 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2339 + return nullptr; 1.2340 + } 1.2341 + 1.2342 + nsRefPtr<OpenCursorHelper> helper = 1.2343 + new OpenCursorHelper(mTransaction, request, this, aKeyRange, direction); 1.2344 + 1.2345 + nsresult rv = helper->DispatchToTransactionPool(); 1.2346 + if (NS_FAILED(rv)) { 1.2347 + IDB_WARNING("Failed to dispatch!"); 1.2348 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2349 + return nullptr; 1.2350 + } 1.2351 + 1.2352 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.2353 + "database(%s).transaction(%s).objectStore(%s)." 1.2354 + "openCursor(%s, %s)", 1.2355 + "IDBRequest[%llu] MT IDBObjectStore.openCursor()", 1.2356 + request->GetSerialNumber(), 1.2357 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2358 + IDB_PROFILER_STRING(Transaction()), 1.2359 + IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange), 1.2360 + IDB_PROFILER_STRING(direction)); 1.2361 + 1.2362 + return request.forget(); 1.2363 +} 1.2364 + 1.2365 +nsresult 1.2366 +IDBObjectStore::OpenCursorFromChildProcess( 1.2367 + IDBRequest* aRequest, 1.2368 + size_t aDirection, 1.2369 + const Key& aKey, 1.2370 + const SerializedStructuredCloneReadInfo& aCloneInfo, 1.2371 + nsTArray<StructuredCloneFile>& aBlobs, 1.2372 + IDBCursor** _retval) 1.2373 +{ 1.2374 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2375 + NS_ASSERTION((!aCloneInfo.dataLength && !aCloneInfo.data) || 1.2376 + (aCloneInfo.dataLength && aCloneInfo.data), 1.2377 + "Inconsistent clone info!"); 1.2378 + 1.2379 + IDBCursor::Direction direction = 1.2380 + static_cast<IDBCursor::Direction>(aDirection); 1.2381 + 1.2382 + StructuredCloneReadInfo cloneInfo; 1.2383 + 1.2384 + if (!cloneInfo.SetFromSerialized(aCloneInfo)) { 1.2385 + IDB_WARNING("Failed to copy clone buffer!"); 1.2386 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.2387 + } 1.2388 + 1.2389 + cloneInfo.mFiles.SwapElements(aBlobs); 1.2390 + 1.2391 + nsRefPtr<IDBCursor> cursor = 1.2392 + IDBCursor::Create(aRequest, mTransaction, this, direction, Key(), 1.2393 + EmptyCString(), EmptyCString(), aKey, Move(cloneInfo)); 1.2394 + IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2395 + 1.2396 + NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!"); 1.2397 + 1.2398 + cursor.forget(_retval); 1.2399 + return NS_OK; 1.2400 +} 1.2401 + 1.2402 +nsresult 1.2403 +IDBObjectStore::OpenCursorFromChildProcess(IDBRequest* aRequest, 1.2404 + size_t aDirection, 1.2405 + const Key& aKey, 1.2406 + IDBCursor** _retval) 1.2407 +{ 1.2408 + MOZ_ASSERT(NS_IsMainThread()); 1.2409 + MOZ_ASSERT(aRequest); 1.2410 + 1.2411 + auto direction = static_cast<IDBCursor::Direction>(aDirection); 1.2412 + 1.2413 + nsRefPtr<IDBCursor> cursor = 1.2414 + IDBCursor::Create(aRequest, mTransaction, this, direction, Key(), 1.2415 + EmptyCString(), EmptyCString(), aKey); 1.2416 + IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2417 + 1.2418 + cursor.forget(_retval); 1.2419 + return NS_OK; 1.2420 +} 1.2421 + 1.2422 +already_AddRefed<IDBRequest> 1.2423 +IDBObjectStore::OpenKeyCursorInternal(IDBKeyRange* aKeyRange, size_t aDirection, 1.2424 + ErrorResult& aRv) 1.2425 +{ 1.2426 + MOZ_ASSERT(NS_IsMainThread()); 1.2427 + 1.2428 + if (!mTransaction->IsOpen()) { 1.2429 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2430 + return nullptr; 1.2431 + } 1.2432 + 1.2433 + nsRefPtr<IDBRequest> request = GenerateRequest(this); 1.2434 + if (!request) { 1.2435 + IDB_WARNING("Failed to generate request!"); 1.2436 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2437 + return nullptr; 1.2438 + } 1.2439 + 1.2440 + auto direction = static_cast<IDBCursor::Direction>(aDirection); 1.2441 + 1.2442 + nsRefPtr<OpenKeyCursorHelper> helper = 1.2443 + new OpenKeyCursorHelper(mTransaction, request, this, aKeyRange, direction); 1.2444 + 1.2445 + nsresult rv = helper->DispatchToTransactionPool(); 1.2446 + if (NS_FAILED(rv)) { 1.2447 + IDB_WARNING("Failed to dispatch!"); 1.2448 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2449 + return nullptr; 1.2450 + } 1.2451 + 1.2452 + IDB_PROFILER_MARK("IndexedDB Request %llu: " 1.2453 + "database(%s).transaction(%s).objectStore(%s)." 1.2454 + "openKeyCursor(%s, %s)", 1.2455 + "IDBRequest[%llu] MT IDBObjectStore.openKeyCursor()", 1.2456 + request->GetSerialNumber(), 1.2457 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2458 + IDB_PROFILER_STRING(Transaction()), 1.2459 + IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange), 1.2460 + IDB_PROFILER_STRING(direction)); 1.2461 + 1.2462 + return request.forget(); 1.2463 +} 1.2464 + 1.2465 +void 1.2466 +IDBObjectStore::SetInfo(ObjectStoreInfo* aInfo) 1.2467 +{ 1.2468 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread"); 1.2469 + NS_ASSERTION(aInfo != mInfo, "This is nonsense"); 1.2470 + 1.2471 + mInfo = aInfo; 1.2472 +} 1.2473 + 1.2474 +already_AddRefed<IDBIndex> 1.2475 +IDBObjectStore::CreateIndexInternal(const IndexInfo& aInfo, ErrorResult& aRv) 1.2476 +{ 1.2477 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2478 + 1.2479 + IndexInfo* indexInfo = mInfo->indexes.AppendElement(); 1.2480 + 1.2481 + indexInfo->name = aInfo.name; 1.2482 + indexInfo->id = aInfo.id; 1.2483 + indexInfo->keyPath = aInfo.keyPath; 1.2484 + indexInfo->unique = aInfo.unique; 1.2485 + indexInfo->multiEntry = aInfo.multiEntry; 1.2486 + 1.2487 + // Don't leave this in the list if we fail below! 1.2488 + AutoRemoveIndex autoRemove(mInfo, aInfo.name); 1.2489 + 1.2490 + nsRefPtr<IDBIndex> index = IDBIndex::Create(this, indexInfo, true); 1.2491 + 1.2492 + mCreatedIndexes.AppendElement(index); 1.2493 + 1.2494 + if (IndexedDatabaseManager::IsMainProcess()) { 1.2495 + nsRefPtr<CreateIndexHelper> helper = 1.2496 + new CreateIndexHelper(mTransaction, index); 1.2497 + 1.2498 + nsresult rv = helper->DispatchToTransactionPool(); 1.2499 + if (NS_FAILED(rv)) { 1.2500 + IDB_WARNING("Failed to dispatch!"); 1.2501 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2502 + return nullptr; 1.2503 + } 1.2504 + } 1.2505 + 1.2506 + autoRemove.forget(); 1.2507 + 1.2508 + IDB_PROFILER_MARK("IndexedDB Pseudo-request: " 1.2509 + "database(%s).transaction(%s).objectStore(%s)." 1.2510 + "createIndex(%s)", 1.2511 + "MT IDBObjectStore.createIndex()", 1.2512 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2513 + IDB_PROFILER_STRING(Transaction()), 1.2514 + IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(index)); 1.2515 + 1.2516 + return index.forget(); 1.2517 +} 1.2518 + 1.2519 +already_AddRefed<IDBIndex> 1.2520 +IDBObjectStore::Index(const nsAString& aName, ErrorResult &aRv) 1.2521 +{ 1.2522 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2523 + 1.2524 + if (mTransaction->IsFinished()) { 1.2525 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2526 + return nullptr; 1.2527 + } 1.2528 + 1.2529 + IndexInfo* indexInfo = nullptr; 1.2530 + uint32_t indexCount = mInfo->indexes.Length(); 1.2531 + for (uint32_t index = 0; index < indexCount; index++) { 1.2532 + if (mInfo->indexes[index].name == aName) { 1.2533 + indexInfo = &(mInfo->indexes[index]); 1.2534 + break; 1.2535 + } 1.2536 + } 1.2537 + 1.2538 + if (!indexInfo) { 1.2539 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR); 1.2540 + return nullptr; 1.2541 + } 1.2542 + 1.2543 + nsRefPtr<IDBIndex> retval; 1.2544 + for (uint32_t i = 0; i < mCreatedIndexes.Length(); i++) { 1.2545 + nsRefPtr<IDBIndex>& index = mCreatedIndexes[i]; 1.2546 + if (index->Name() == aName) { 1.2547 + retval = index; 1.2548 + break; 1.2549 + } 1.2550 + } 1.2551 + 1.2552 + if (!retval) { 1.2553 + retval = IDBIndex::Create(this, indexInfo, false); 1.2554 + if (!retval) { 1.2555 + IDB_WARNING("Failed to create index!"); 1.2556 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2557 + return nullptr; 1.2558 + } 1.2559 + 1.2560 + if (!mCreatedIndexes.AppendElement(retval)) { 1.2561 + IDB_WARNING("Out of memory!"); 1.2562 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2563 + return nullptr; 1.2564 + } 1.2565 + } 1.2566 + 1.2567 + return retval.forget(); 1.2568 +} 1.2569 + 1.2570 +NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore) 1.2571 + 1.2572 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore) 1.2573 + NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER 1.2574 + NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKeyPath) 1.2575 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.2576 + 1.2577 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore) 1.2578 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.2579 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction) 1.2580 + 1.2581 + for (uint32_t i = 0; i < tmp->mCreatedIndexes.Length(); i++) { 1.2582 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCreatedIndexes[i]"); 1.2583 + cb.NoteXPCOMChild(static_cast<nsISupports*>(tmp->mCreatedIndexes[i].get())); 1.2584 + } 1.2585 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.2586 + 1.2587 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore) 1.2588 + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 1.2589 + 1.2590 + // Don't unlink mTransaction! 1.2591 + 1.2592 + tmp->mCreatedIndexes.Clear(); 1.2593 + 1.2594 + tmp->mCachedKeyPath = JSVAL_VOID; 1.2595 + 1.2596 + if (tmp->mRooted) { 1.2597 + mozilla::DropJSObjects(tmp); 1.2598 + tmp->mRooted = false; 1.2599 + } 1.2600 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.2601 + 1.2602 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBObjectStore) 1.2603 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.2604 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.2605 +NS_INTERFACE_MAP_END 1.2606 + 1.2607 +NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBObjectStore) 1.2608 +NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBObjectStore) 1.2609 + 1.2610 +JSObject* 1.2611 +IDBObjectStore::WrapObject(JSContext* aCx) 1.2612 +{ 1.2613 + return IDBObjectStoreBinding::Wrap(aCx, this); 1.2614 +} 1.2615 + 1.2616 +void 1.2617 +IDBObjectStore::GetKeyPath(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, 1.2618 + ErrorResult& aRv) 1.2619 +{ 1.2620 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2621 + 1.2622 + if (!JSVAL_IS_VOID(mCachedKeyPath)) { 1.2623 + JS::ExposeValueToActiveJS(mCachedKeyPath); 1.2624 + aResult.set(mCachedKeyPath); 1.2625 + return; 1.2626 + } 1.2627 + 1.2628 + aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath); 1.2629 + if (NS_WARN_IF(aRv.Failed())) { 1.2630 + return; 1.2631 + } 1.2632 + 1.2633 + if (JSVAL_IS_GCTHING(mCachedKeyPath)) { 1.2634 + mozilla::HoldJSObjects(this); 1.2635 + mRooted = true; 1.2636 + } 1.2637 + 1.2638 + JS::ExposeValueToActiveJS(mCachedKeyPath); 1.2639 + aResult.set(mCachedKeyPath); 1.2640 +} 1.2641 + 1.2642 +already_AddRefed<DOMStringList> 1.2643 +IDBObjectStore::GetIndexNames(ErrorResult& aRv) 1.2644 +{ 1.2645 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2646 + 1.2647 + nsRefPtr<DOMStringList> list(new DOMStringList()); 1.2648 + 1.2649 + nsTArray<nsString>& names = list->StringArray(); 1.2650 + uint32_t count = mInfo->indexes.Length(); 1.2651 + names.SetCapacity(count); 1.2652 + 1.2653 + for (uint32_t index = 0; index < count; index++) { 1.2654 + names.InsertElementSorted(mInfo->indexes[index].name); 1.2655 + } 1.2656 + 1.2657 + return list.forget(); 1.2658 +} 1.2659 + 1.2660 +already_AddRefed<IDBRequest> 1.2661 +IDBObjectStore::Get(JSContext* aCx, JS::Handle<JS::Value> aKey, 1.2662 + ErrorResult& aRv) 1.2663 +{ 1.2664 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2665 + 1.2666 + if (!mTransaction->IsOpen()) { 1.2667 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2668 + return nullptr; 1.2669 + } 1.2670 + 1.2671 + nsRefPtr<IDBKeyRange> keyRange; 1.2672 + aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); 1.2673 + ENSURE_SUCCESS(aRv, nullptr); 1.2674 + 1.2675 + if (!keyRange) { 1.2676 + // Must specify a key or keyRange for get(). 1.2677 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); 1.2678 + return nullptr; 1.2679 + } 1.2680 + 1.2681 + return GetInternal(keyRange, aRv); 1.2682 +} 1.2683 + 1.2684 +already_AddRefed<IDBRequest> 1.2685 +IDBObjectStore::GetAll(JSContext* aCx, 1.2686 + JS::Handle<JS::Value> aKey, 1.2687 + const Optional<uint32_t>& aLimit, ErrorResult& aRv) 1.2688 +{ 1.2689 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2690 + 1.2691 + if (!mTransaction->IsOpen()) { 1.2692 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2693 + return nullptr; 1.2694 + } 1.2695 + 1.2696 + nsRefPtr<IDBKeyRange> keyRange; 1.2697 + aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); 1.2698 + ENSURE_SUCCESS(aRv, nullptr); 1.2699 + 1.2700 + uint32_t limit = UINT32_MAX; 1.2701 + if (aLimit.WasPassed() && aLimit.Value() != 0) { 1.2702 + limit = aLimit.Value(); 1.2703 + } 1.2704 + 1.2705 + return GetAllInternal(keyRange, limit, aRv); 1.2706 +} 1.2707 + 1.2708 +already_AddRefed<IDBRequest> 1.2709 +IDBObjectStore::Delete(JSContext* aCx, JS::Handle<JS::Value> aKey, 1.2710 + ErrorResult& aRv) 1.2711 +{ 1.2712 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2713 + 1.2714 + if (!mTransaction->IsOpen()) { 1.2715 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2716 + return nullptr; 1.2717 + } 1.2718 + 1.2719 + if (!IsWriteAllowed()) { 1.2720 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); 1.2721 + return nullptr; 1.2722 + } 1.2723 + 1.2724 + nsRefPtr<IDBKeyRange> keyRange; 1.2725 + aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); 1.2726 + ENSURE_SUCCESS(aRv, nullptr); 1.2727 + 1.2728 + if (!keyRange) { 1.2729 + // Must specify a key or keyRange for delete(). 1.2730 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); 1.2731 + return nullptr; 1.2732 + } 1.2733 + 1.2734 + return DeleteInternal(keyRange, aRv); 1.2735 +} 1.2736 + 1.2737 +already_AddRefed<IDBRequest> 1.2738 +IDBObjectStore::OpenCursor(JSContext* aCx, 1.2739 + JS::Handle<JS::Value> aRange, 1.2740 + IDBCursorDirection aDirection, ErrorResult& aRv) 1.2741 +{ 1.2742 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2743 + 1.2744 + if (!mTransaction->IsOpen()) { 1.2745 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2746 + return nullptr; 1.2747 + } 1.2748 + 1.2749 + nsRefPtr<IDBKeyRange> keyRange; 1.2750 + aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange)); 1.2751 + ENSURE_SUCCESS(aRv, nullptr); 1.2752 + 1.2753 + IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection); 1.2754 + size_t argDirection = static_cast<size_t>(direction); 1.2755 + 1.2756 + return OpenCursorInternal(keyRange, argDirection, aRv); 1.2757 +} 1.2758 + 1.2759 +already_AddRefed<IDBIndex> 1.2760 +IDBObjectStore::CreateIndex(JSContext* aCx, const nsAString& aName, 1.2761 + const nsAString& aKeyPath, 1.2762 + const IDBIndexParameters& aOptionalParameters, 1.2763 + ErrorResult& aRv) 1.2764 +{ 1.2765 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2766 + 1.2767 + KeyPath keyPath(0); 1.2768 + if (NS_FAILED(KeyPath::Parse(aCx, aKeyPath, &keyPath)) || 1.2769 + !keyPath.IsValid()) { 1.2770 + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); 1.2771 + return nullptr; 1.2772 + } 1.2773 + 1.2774 + return CreateIndex(aCx, aName, keyPath, aOptionalParameters, aRv); 1.2775 +} 1.2776 + 1.2777 +already_AddRefed<IDBIndex> 1.2778 +IDBObjectStore::CreateIndex(JSContext* aCx, const nsAString& aName, 1.2779 + const Sequence<nsString >& aKeyPath, 1.2780 + const IDBIndexParameters& aOptionalParameters, 1.2781 + ErrorResult& aRv) 1.2782 +{ 1.2783 + NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!"); 1.2784 + 1.2785 + if (!aKeyPath.Length()) { 1.2786 + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); 1.2787 + return nullptr; 1.2788 + } 1.2789 + 1.2790 + KeyPath keyPath(0); 1.2791 + if (NS_FAILED(KeyPath::Parse(aCx, aKeyPath, &keyPath))) { 1.2792 + aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); 1.2793 + return nullptr; 1.2794 + } 1.2795 + 1.2796 + return CreateIndex(aCx, aName, keyPath, aOptionalParameters, aRv); 1.2797 +} 1.2798 + 1.2799 +already_AddRefed<IDBIndex> 1.2800 +IDBObjectStore::CreateIndex(JSContext* aCx, const nsAString& aName, 1.2801 + KeyPath& aKeyPath, 1.2802 + const IDBIndexParameters& aOptionalParameters, 1.2803 + ErrorResult& aRv) 1.2804 +{ 1.2805 + // Check name and current mode 1.2806 + IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction(); 1.2807 + 1.2808 + if (!transaction || 1.2809 + transaction != mTransaction || 1.2810 + mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) { 1.2811 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 1.2812 + return nullptr; 1.2813 + } 1.2814 + 1.2815 + bool found = false; 1.2816 + uint32_t indexCount = mInfo->indexes.Length(); 1.2817 + for (uint32_t index = 0; index < indexCount; index++) { 1.2818 + if (mInfo->indexes[index].name == aName) { 1.2819 + found = true; 1.2820 + break; 1.2821 + } 1.2822 + } 1.2823 + 1.2824 + if (found) { 1.2825 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR); 1.2826 + return nullptr; 1.2827 + } 1.2828 + 1.2829 + NS_ASSERTION(mTransaction->IsOpen(), "Impossible!"); 1.2830 + 1.2831 +#ifdef DEBUG 1.2832 + for (uint32_t index = 0; index < mCreatedIndexes.Length(); index++) { 1.2833 + if (mCreatedIndexes[index]->Name() == aName) { 1.2834 + NS_ERROR("Already created this one!"); 1.2835 + } 1.2836 + } 1.2837 +#endif 1.2838 + 1.2839 + if (aOptionalParameters.mMultiEntry && aKeyPath.IsArray()) { 1.2840 + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); 1.2841 + return nullptr; 1.2842 + } 1.2843 + 1.2844 + DatabaseInfo* databaseInfo = mTransaction->DBInfo(); 1.2845 + 1.2846 + IndexInfo info; 1.2847 + 1.2848 + info.name = aName; 1.2849 + info.id = databaseInfo->nextIndexId++; 1.2850 + info.keyPath = aKeyPath; 1.2851 + info.unique = aOptionalParameters.mUnique; 1.2852 + info.multiEntry = aOptionalParameters.mMultiEntry; 1.2853 + 1.2854 + return CreateIndexInternal(info, aRv); 1.2855 +} 1.2856 + 1.2857 +void 1.2858 +IDBObjectStore::DeleteIndex(const nsAString& aName, ErrorResult& aRv) 1.2859 +{ 1.2860 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.2861 + 1.2862 + IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction(); 1.2863 + 1.2864 + if (!transaction || 1.2865 + transaction != mTransaction || 1.2866 + mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) { 1.2867 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); 1.2868 + return; 1.2869 + } 1.2870 + 1.2871 + NS_ASSERTION(mTransaction->IsOpen(), "Impossible!"); 1.2872 + 1.2873 + uint32_t index = 0; 1.2874 + for (; index < mInfo->indexes.Length(); index++) { 1.2875 + if (mInfo->indexes[index].name == aName) { 1.2876 + break; 1.2877 + } 1.2878 + } 1.2879 + 1.2880 + if (index == mInfo->indexes.Length()) { 1.2881 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR); 1.2882 + return; 1.2883 + } 1.2884 + 1.2885 + if (IndexedDatabaseManager::IsMainProcess()) { 1.2886 + nsRefPtr<DeleteIndexHelper> helper = 1.2887 + new DeleteIndexHelper(mTransaction, this, aName); 1.2888 + 1.2889 + nsresult rv = helper->DispatchToTransactionPool(); 1.2890 + if (NS_FAILED(rv)) { 1.2891 + IDB_WARNING("Failed to dispatch!"); 1.2892 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.2893 + return; 1.2894 + } 1.2895 + } 1.2896 + else { 1.2897 + NS_ASSERTION(mActorChild, "Must have an actor here!"); 1.2898 + 1.2899 + mActorChild->SendDeleteIndex(nsString(aName)); 1.2900 + } 1.2901 + 1.2902 + mInfo->indexes.RemoveElementAt(index); 1.2903 + 1.2904 + for (uint32_t i = 0; i < mCreatedIndexes.Length(); i++) { 1.2905 + if (mCreatedIndexes[i]->Name() == aName) { 1.2906 + mCreatedIndexes.RemoveElementAt(i); 1.2907 + break; 1.2908 + } 1.2909 + } 1.2910 + 1.2911 + IDB_PROFILER_MARK("IndexedDB Pseudo-request: " 1.2912 + "database(%s).transaction(%s).objectStore(%s)." 1.2913 + "deleteIndex(\"%s\")", 1.2914 + "MT IDBObjectStore.deleteIndex()", 1.2915 + IDB_PROFILER_STRING(Transaction()->Database()), 1.2916 + IDB_PROFILER_STRING(Transaction()), 1.2917 + IDB_PROFILER_STRING(this), 1.2918 + NS_ConvertUTF16toUTF8(aName).get()); 1.2919 +} 1.2920 + 1.2921 +already_AddRefed<IDBRequest> 1.2922 +IDBObjectStore::Count(JSContext* aCx, 1.2923 + JS::Handle<JS::Value> aKey, 1.2924 + ErrorResult& aRv) 1.2925 +{ 1.2926 + if (!mTransaction->IsOpen()) { 1.2927 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2928 + return nullptr; 1.2929 + } 1.2930 + 1.2931 + nsRefPtr<IDBKeyRange> keyRange; 1.2932 + aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); 1.2933 + ENSURE_SUCCESS(aRv, nullptr); 1.2934 + 1.2935 + return CountInternal(keyRange, aRv); 1.2936 +} 1.2937 + 1.2938 +already_AddRefed<IDBRequest> 1.2939 +IDBObjectStore::GetAllKeys(JSContext* aCx, 1.2940 + JS::Handle<JS::Value> aKey, 1.2941 + const Optional<uint32_t>& aLimit, ErrorResult& aRv) 1.2942 +{ 1.2943 + MOZ_ASSERT(NS_IsMainThread()); 1.2944 + 1.2945 + if (!mTransaction->IsOpen()) { 1.2946 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2947 + return nullptr; 1.2948 + } 1.2949 + 1.2950 + nsRefPtr<IDBKeyRange> keyRange; 1.2951 + aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); 1.2952 + ENSURE_SUCCESS(aRv, nullptr); 1.2953 + 1.2954 + uint32_t limit = UINT32_MAX; 1.2955 + if (aLimit.WasPassed() && aLimit.Value() != 0) { 1.2956 + limit = aLimit.Value(); 1.2957 + } 1.2958 + 1.2959 + return GetAllKeysInternal(keyRange, limit, aRv); 1.2960 +} 1.2961 + 1.2962 +already_AddRefed<IDBRequest> 1.2963 +IDBObjectStore::OpenKeyCursor(JSContext* aCx, 1.2964 + JS::Handle<JS::Value> aRange, 1.2965 + IDBCursorDirection aDirection, ErrorResult& aRv) 1.2966 +{ 1.2967 + MOZ_ASSERT(NS_IsMainThread()); 1.2968 + 1.2969 + if (!mTransaction->IsOpen()) { 1.2970 + aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); 1.2971 + return nullptr; 1.2972 + } 1.2973 + 1.2974 + nsRefPtr<IDBKeyRange> keyRange; 1.2975 + aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange)); 1.2976 + ENSURE_SUCCESS(aRv, nullptr); 1.2977 + 1.2978 + IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection); 1.2979 + 1.2980 + return OpenKeyCursorInternal(keyRange, static_cast<size_t>(direction), aRv); 1.2981 +} 1.2982 + 1.2983 +inline nsresult 1.2984 +CopyData(nsIInputStream* aInputStream, nsIOutputStream* aOutputStream) 1.2985 +{ 1.2986 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.2987 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.2988 + 1.2989 + PROFILER_LABEL("IndexedDB", "CopyData"); 1.2990 + 1.2991 + nsresult rv; 1.2992 + 1.2993 + do { 1.2994 + char copyBuffer[FILE_COPY_BUFFER_SIZE]; 1.2995 + 1.2996 + uint32_t numRead; 1.2997 + rv = aInputStream->Read(copyBuffer, sizeof(copyBuffer), &numRead); 1.2998 + NS_ENSURE_SUCCESS(rv, rv); 1.2999 + 1.3000 + if (!numRead) { 1.3001 + break; 1.3002 + } 1.3003 + 1.3004 + uint32_t numWrite; 1.3005 + rv = aOutputStream->Write(copyBuffer, numRead, &numWrite); 1.3006 + if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) { 1.3007 + rv = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; 1.3008 + } 1.3009 + NS_ENSURE_SUCCESS(rv, rv); 1.3010 + 1.3011 + NS_ENSURE_TRUE(numWrite == numRead, NS_ERROR_FAILURE); 1.3012 + } while (true); 1.3013 + 1.3014 + rv = aOutputStream->Flush(); 1.3015 + NS_ENSURE_SUCCESS(rv, rv); 1.3016 + 1.3017 + return NS_OK; 1.3018 +} 1.3019 + 1.3020 +void 1.3021 +ObjectStoreHelper::ReleaseMainThreadObjects() 1.3022 +{ 1.3023 + mObjectStore = nullptr; 1.3024 + AsyncConnectionHelper::ReleaseMainThreadObjects(); 1.3025 +} 1.3026 + 1.3027 +nsresult 1.3028 +ObjectStoreHelper::Dispatch(nsIEventTarget* aDatabaseThread) 1.3029 +{ 1.3030 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3031 + 1.3032 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", "ObjectStoreHelper::Dispatch"); 1.3033 + 1.3034 + if (IndexedDatabaseManager::IsMainProcess()) { 1.3035 + return AsyncConnectionHelper::Dispatch(aDatabaseThread); 1.3036 + } 1.3037 + 1.3038 + // If we've been invalidated then there's no point sending anything to the 1.3039 + // parent process. 1.3040 + if (mObjectStore->Transaction()->Database()->IsInvalidated()) { 1.3041 + IDB_REPORT_INTERNAL_ERR(); 1.3042 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.3043 + } 1.3044 + 1.3045 + IndexedDBObjectStoreChild* objectStoreActor = mObjectStore->GetActorChild(); 1.3046 + NS_ASSERTION(objectStoreActor, "Must have an actor here!"); 1.3047 + 1.3048 + ObjectStoreRequestParams params; 1.3049 + nsresult rv = PackArgumentsForParentProcess(params); 1.3050 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3051 + 1.3052 + NoDispatchEventTarget target; 1.3053 + rv = AsyncConnectionHelper::Dispatch(&target); 1.3054 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3055 + 1.3056 + mActor = 1.3057 + new IndexedDBObjectStoreRequestChild(this, mObjectStore, params.type()); 1.3058 + objectStoreActor->SendPIndexedDBRequestConstructor(mActor, params); 1.3059 + 1.3060 + return NS_OK; 1.3061 +} 1.3062 + 1.3063 +void 1.3064 +NoRequestObjectStoreHelper::ReleaseMainThreadObjects() 1.3065 +{ 1.3066 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3067 + mObjectStore = nullptr; 1.3068 + AsyncConnectionHelper::ReleaseMainThreadObjects(); 1.3069 +} 1.3070 + 1.3071 +nsresult 1.3072 +NoRequestObjectStoreHelper::UnpackResponseFromParentProcess( 1.3073 + const ResponseValue& aResponseValue) 1.3074 +{ 1.3075 + MOZ_CRASH(); 1.3076 +} 1.3077 + 1.3078 +AsyncConnectionHelper::ChildProcessSendResult 1.3079 +NoRequestObjectStoreHelper::SendResponseToChildProcess(nsresult aResultCode) 1.3080 +{ 1.3081 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3082 + return Success_NotSent; 1.3083 +} 1.3084 + 1.3085 +nsresult 1.3086 +NoRequestObjectStoreHelper::OnSuccess() 1.3087 +{ 1.3088 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3089 + return NS_OK; 1.3090 +} 1.3091 + 1.3092 +void 1.3093 +NoRequestObjectStoreHelper::OnError() 1.3094 +{ 1.3095 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3096 + mTransaction->Abort(GetResultCode()); 1.3097 +} 1.3098 + 1.3099 +// This is a duplicate of the js engine's byte munging in StructuredClone.cpp 1.3100 +uint64_t 1.3101 +ReinterpretDoubleAsUInt64(double d) 1.3102 +{ 1.3103 + union { 1.3104 + double d; 1.3105 + uint64_t u; 1.3106 + } pun; 1.3107 + pun.d = d; 1.3108 + return pun.u; 1.3109 +} 1.3110 + 1.3111 +nsresult 1.3112 +AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) 1.3113 +{ 1.3114 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.3115 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3116 + NS_ASSERTION(aConnection, "Passed a null connection!"); 1.3117 + 1.3118 + PROFILER_LABEL("IndexedDB", "AddHelper::DoDatabaseWork"); 1.3119 + 1.3120 + if (IndexedDatabaseManager::InLowDiskSpaceMode()) { 1.3121 + NS_WARNING("Refusing to add more data because disk space is low!"); 1.3122 + return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; 1.3123 + } 1.3124 + 1.3125 + nsresult rv; 1.3126 + bool keyUnset = mKey.IsUnset(); 1.3127 + int64_t osid = mObjectStore->Id(); 1.3128 + const KeyPath& keyPath = mObjectStore->GetKeyPath(); 1.3129 + 1.3130 + // The "|| keyUnset" here is mostly a debugging tool. If a key isn't 1.3131 + // specified we should never have a collision and so it shouldn't matter 1.3132 + // if we allow overwrite or not. By not allowing overwrite we raise 1.3133 + // detectable errors rather than corrupting data 1.3134 + nsCOMPtr<mozIStorageStatement> stmt = !mOverwrite || keyUnset ? 1.3135 + mTransaction->GetCachedStatement( 1.3136 + "INSERT INTO object_data (object_store_id, key_value, data, file_ids) " 1.3137 + "VALUES (:osid, :key_value, :data, :file_ids)") : 1.3138 + mTransaction->GetCachedStatement( 1.3139 + "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data, " 1.3140 + "file_ids) " 1.3141 + "VALUES (:osid, :key_value, :data, :file_ids)"); 1.3142 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3143 + 1.3144 + mozStorageStatementScoper scoper(stmt); 1.3145 + 1.3146 + rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid); 1.3147 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3148 + 1.3149 + NS_ASSERTION(!keyUnset || mObjectStore->IsAutoIncrement(), 1.3150 + "Should have key unless autoincrement"); 1.3151 + 1.3152 + int64_t autoIncrementNum = 0; 1.3153 + 1.3154 + if (mObjectStore->IsAutoIncrement()) { 1.3155 + if (keyUnset) { 1.3156 + autoIncrementNum = mObjectStore->Info()->nextAutoIncrementId; 1.3157 + 1.3158 + MOZ_ASSERT(autoIncrementNum > 0, 1.3159 + "Generated key must always be a positive integer"); 1.3160 + 1.3161 + if (autoIncrementNum > (1LL << 53)) { 1.3162 + IDB_REPORT_INTERNAL_ERR(); 1.3163 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.3164 + } 1.3165 + 1.3166 + mKey.SetFromInteger(autoIncrementNum); 1.3167 + } 1.3168 + else if (mKey.IsFloat() && 1.3169 + mKey.ToFloat() >= mObjectStore->Info()->nextAutoIncrementId) { 1.3170 + autoIncrementNum = floor(mKey.ToFloat()); 1.3171 + } 1.3172 + 1.3173 + if (keyUnset && keyPath.IsValid()) { 1.3174 + // Special case where someone put an object into an autoIncrement'ing 1.3175 + // objectStore with no key in its keyPath set. We needed to figure out 1.3176 + // which row id we would get above before we could set that properly. 1.3177 + 1.3178 + LittleEndian::writeUint64((char*)mCloneWriteInfo.mCloneBuffer.data() + 1.3179 + mCloneWriteInfo.mOffsetToKeyProp, 1.3180 + ReinterpretDoubleAsUInt64(static_cast<double>( 1.3181 + autoIncrementNum))); 1.3182 + } 1.3183 + } 1.3184 + 1.3185 + mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key_value")); 1.3186 + 1.3187 + 1.3188 + // Compress the bytes before adding into the database. 1.3189 + const char* uncompressed = 1.3190 + reinterpret_cast<const char*>(mCloneWriteInfo.mCloneBuffer.data()); 1.3191 + size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes(); 1.3192 + 1.3193 + // We don't have a smart pointer class that calls moz_free, so we need to 1.3194 + // manage | compressed | manually. 1.3195 + { 1.3196 + size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength); 1.3197 + // moz_malloc is equivalent to NS_Alloc, which we use because mozStorage 1.3198 + // expects to be able to free the adopted pointer with NS_Free. 1.3199 + char* compressed = (char*)moz_malloc(compressedLength); 1.3200 + NS_ENSURE_TRUE(compressed, NS_ERROR_OUT_OF_MEMORY); 1.3201 + 1.3202 + snappy::RawCompress(uncompressed, uncompressedLength, compressed, 1.3203 + &compressedLength); 1.3204 + 1.3205 + uint8_t* dataBuffer = reinterpret_cast<uint8_t*>(compressed); 1.3206 + size_t dataBufferLength = compressedLength; 1.3207 + 1.3208 + // If this call succeeds, | compressed | is now owned by the statement, and 1.3209 + // we are no longer responsible for it. 1.3210 + rv = stmt->BindAdoptedBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer, 1.3211 + dataBufferLength); 1.3212 + if (NS_FAILED(rv)) { 1.3213 + moz_free(compressed); 1.3214 + } 1.3215 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3216 + } 1.3217 + 1.3218 + // Handle blobs 1.3219 + uint32_t length = mCloneWriteInfo.mFiles.Length(); 1.3220 + if (length) { 1.3221 + nsRefPtr<FileManager> fileManager = mDatabase->Manager(); 1.3222 + 1.3223 + nsCOMPtr<nsIFile> directory = fileManager->GetDirectory(); 1.3224 + IDB_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3225 + 1.3226 + nsCOMPtr<nsIFile> journalDirectory = fileManager->EnsureJournalDirectory(); 1.3227 + IDB_ENSURE_TRUE(journalDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3228 + 1.3229 + nsAutoString fileIds; 1.3230 + 1.3231 + for (uint32_t index = 0; index < length; index++) { 1.3232 + StructuredCloneFile& cloneFile = mCloneWriteInfo.mFiles[index]; 1.3233 + 1.3234 + FileInfo* fileInfo = cloneFile.mFileInfo; 1.3235 + nsIInputStream* inputStream = cloneFile.mInputStream; 1.3236 + 1.3237 + int64_t id = fileInfo->Id(); 1.3238 + if (inputStream) { 1.3239 + // Create a journal file first 1.3240 + nsCOMPtr<nsIFile> nativeFile = 1.3241 + fileManager->GetFileForId(journalDirectory, id); 1.3242 + IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3243 + 1.3244 + rv = nativeFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644); 1.3245 + IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3246 + 1.3247 + // Now we can copy the blob 1.3248 + nativeFile = fileManager->GetFileForId(directory, id); 1.3249 + IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3250 + 1.3251 + IDBDatabase* database = mObjectStore->Transaction()->Database(); 1.3252 + nsRefPtr<FileOutputStream> outputStream = 1.3253 + FileOutputStream::Create(database->Type(), database->Group(), 1.3254 + database->Origin(), nativeFile); 1.3255 + IDB_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3256 + 1.3257 + rv = CopyData(inputStream, outputStream); 1.3258 + if (NS_FAILED(rv) && 1.3259 + NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) { 1.3260 + IDB_REPORT_INTERNAL_ERR(); 1.3261 + rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.3262 + } 1.3263 + NS_ENSURE_SUCCESS(rv, rv); 1.3264 + 1.3265 + cloneFile.mFile->AddFileInfo(fileInfo); 1.3266 + } 1.3267 + 1.3268 + if (index) { 1.3269 + fileIds.Append(NS_LITERAL_STRING(" ")); 1.3270 + } 1.3271 + fileIds.AppendInt(id); 1.3272 + } 1.3273 + 1.3274 + rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds); 1.3275 + } 1.3276 + else { 1.3277 + rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids")); 1.3278 + } 1.3279 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3280 + 1.3281 + rv = stmt->Execute(); 1.3282 + if (rv == NS_ERROR_STORAGE_CONSTRAINT) { 1.3283 + NS_ASSERTION(!keyUnset, "Generated key had a collision!?"); 1.3284 + return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; 1.3285 + } 1.3286 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3287 + 1.3288 + int64_t objectDataId; 1.3289 + rv = aConnection->GetLastInsertRowID(&objectDataId); 1.3290 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3291 + 1.3292 + // Update our indexes if needed. 1.3293 + if (mOverwrite || !mIndexUpdateInfo.IsEmpty()) { 1.3294 + rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey, mOverwrite, 1.3295 + objectDataId, mIndexUpdateInfo); 1.3296 + if (rv == NS_ERROR_STORAGE_CONSTRAINT) { 1.3297 + return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; 1.3298 + } 1.3299 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3300 + } 1.3301 + 1.3302 + if (autoIncrementNum) { 1.3303 + mObjectStore->Info()->nextAutoIncrementId = autoIncrementNum + 1; 1.3304 + } 1.3305 + 1.3306 + return NS_OK; 1.3307 +} 1.3308 + 1.3309 +nsresult 1.3310 +AddHelper::GetSuccessResult(JSContext* aCx, 1.3311 + JS::MutableHandle<JS::Value> aVal) 1.3312 +{ 1.3313 + NS_ASSERTION(!mKey.IsUnset(), "Badness!"); 1.3314 + 1.3315 + mCloneWriteInfo.mCloneBuffer.clear(); 1.3316 + 1.3317 + return mKey.ToJSVal(aCx, aVal); 1.3318 +} 1.3319 + 1.3320 +void 1.3321 +AddHelper::ReleaseMainThreadObjects() 1.3322 +{ 1.3323 + IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo); 1.3324 + ObjectStoreHelper::ReleaseMainThreadObjects(); 1.3325 +} 1.3326 + 1.3327 +nsresult 1.3328 +AddHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) 1.3329 +{ 1.3330 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3331 + NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3332 + 1.3333 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.3334 + "AddHelper::PackArgumentsForParentProcess"); 1.3335 + 1.3336 + AddPutParams commonParams; 1.3337 + commonParams.cloneInfo() = mCloneWriteInfo; 1.3338 + commonParams.key() = mKey; 1.3339 + commonParams.indexUpdateInfos().AppendElements(mIndexUpdateInfo); 1.3340 + 1.3341 + const nsTArray<StructuredCloneFile>& files = mCloneWriteInfo.mFiles; 1.3342 + 1.3343 + if (!files.IsEmpty()) { 1.3344 + uint32_t fileCount = files.Length(); 1.3345 + 1.3346 + InfallibleTArray<PBlobChild*>& blobsChild = commonParams.blobsChild(); 1.3347 + blobsChild.SetCapacity(fileCount); 1.3348 + 1.3349 + ContentChild* contentChild = ContentChild::GetSingleton(); 1.3350 + NS_ASSERTION(contentChild, "This should never be null!"); 1.3351 + 1.3352 + for (uint32_t index = 0; index < fileCount; index++) { 1.3353 + const StructuredCloneFile& file = files[index]; 1.3354 + 1.3355 + NS_ASSERTION(file.mFile, "This should never be null!"); 1.3356 + NS_ASSERTION(!file.mFileInfo, "This is not yet supported!"); 1.3357 + 1.3358 + BlobChild* actor = 1.3359 + contentChild->GetOrCreateActorForBlob(file.mFile); 1.3360 + if (!actor) { 1.3361 + IDB_REPORT_INTERNAL_ERR(); 1.3362 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.3363 + } 1.3364 + blobsChild.AppendElement(actor); 1.3365 + } 1.3366 + } 1.3367 + 1.3368 + if (mOverwrite) { 1.3369 + PutParams putParams; 1.3370 + putParams.commonParams() = commonParams; 1.3371 + aParams = putParams; 1.3372 + } 1.3373 + else { 1.3374 + AddParams addParams; 1.3375 + addParams.commonParams() = commonParams; 1.3376 + aParams = addParams; 1.3377 + } 1.3378 + 1.3379 + return NS_OK; 1.3380 +} 1.3381 + 1.3382 +AsyncConnectionHelper::ChildProcessSendResult 1.3383 +AddHelper::SendResponseToChildProcess(nsresult aResultCode) 1.3384 +{ 1.3385 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3386 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3387 + 1.3388 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.3389 + "AddHelper::SendResponseToChildProcess"); 1.3390 + 1.3391 + IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); 1.3392 + NS_ASSERTION(actor, "How did we get this far without an actor?"); 1.3393 + 1.3394 + ResponseValue response; 1.3395 + if (NS_FAILED(aResultCode)) { 1.3396 + response = aResultCode; 1.3397 + } 1.3398 + else if (mOverwrite) { 1.3399 + PutResponse putResponse; 1.3400 + putResponse.key() = mKey; 1.3401 + response = putResponse; 1.3402 + } 1.3403 + else { 1.3404 + AddResponse addResponse; 1.3405 + addResponse.key() = mKey; 1.3406 + response = addResponse; 1.3407 + } 1.3408 + 1.3409 + if (!actor->SendResponse(response)) { 1.3410 + return Error; 1.3411 + } 1.3412 + 1.3413 + return Success_Sent; 1.3414 +} 1.3415 + 1.3416 +nsresult 1.3417 +AddHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.3418 +{ 1.3419 + NS_ASSERTION(aResponseValue.type() == ResponseValue::TAddResponse || 1.3420 + aResponseValue.type() == ResponseValue::TPutResponse, 1.3421 + "Bad response type!"); 1.3422 + 1.3423 + mKey = mOverwrite ? 1.3424 + aResponseValue.get_PutResponse().key() : 1.3425 + aResponseValue.get_AddResponse().key(); 1.3426 + 1.3427 + return NS_OK; 1.3428 +} 1.3429 + 1.3430 +nsresult 1.3431 +GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) 1.3432 +{ 1.3433 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.3434 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3435 + NS_ASSERTION(mKeyRange, "Must have a key range here!"); 1.3436 + 1.3437 + PROFILER_LABEL("IndexedDB", "GetHelper::DoDatabaseWork [IDBObjectStore.cpp]"); 1.3438 + 1.3439 + nsCString keyRangeClause; 1.3440 + mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause); 1.3441 + 1.3442 + NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!"); 1.3443 + 1.3444 + nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data " 1.3445 + "WHERE object_store_id = :osid") + 1.3446 + keyRangeClause + NS_LITERAL_CSTRING(" LIMIT 1"); 1.3447 + 1.3448 + nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); 1.3449 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3450 + 1.3451 + mozStorageStatementScoper scoper(stmt); 1.3452 + 1.3453 + nsresult rv = 1.3454 + stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore->Id()); 1.3455 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3456 + 1.3457 + rv = mKeyRange->BindToStatement(stmt); 1.3458 + NS_ENSURE_SUCCESS(rv, rv); 1.3459 + 1.3460 + bool hasResult; 1.3461 + rv = stmt->ExecuteStep(&hasResult); 1.3462 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3463 + 1.3464 + if (hasResult) { 1.3465 + rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1, 1.3466 + mDatabase, mCloneReadInfo); 1.3467 + NS_ENSURE_SUCCESS(rv, rv); 1.3468 + } 1.3469 + 1.3470 + return NS_OK; 1.3471 +} 1.3472 + 1.3473 +nsresult 1.3474 +GetHelper::GetSuccessResult(JSContext* aCx, 1.3475 + JS::MutableHandle<JS::Value> aVal) 1.3476 +{ 1.3477 + bool result = IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, aVal); 1.3478 + 1.3479 + mCloneReadInfo.mCloneBuffer.clear(); 1.3480 + 1.3481 + NS_ENSURE_TRUE(result, NS_ERROR_DOM_DATA_CLONE_ERR); 1.3482 + return NS_OK; 1.3483 +} 1.3484 + 1.3485 +void 1.3486 +GetHelper::ReleaseMainThreadObjects() 1.3487 +{ 1.3488 + mKeyRange = nullptr; 1.3489 + IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo); 1.3490 + ObjectStoreHelper::ReleaseMainThreadObjects(); 1.3491 +} 1.3492 + 1.3493 +nsresult 1.3494 +GetHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) 1.3495 +{ 1.3496 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3497 + NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3498 + NS_ASSERTION(mKeyRange, "This should never be null!"); 1.3499 + 1.3500 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.3501 + "GetHelper::PackArgumentsForParentProcess " 1.3502 + "[IDBObjectStore.cpp]"); 1.3503 + 1.3504 + GetParams params; 1.3505 + 1.3506 + mKeyRange->ToSerializedKeyRange(params.keyRange()); 1.3507 + 1.3508 + aParams = params; 1.3509 + return NS_OK; 1.3510 +} 1.3511 + 1.3512 +AsyncConnectionHelper::ChildProcessSendResult 1.3513 +GetHelper::SendResponseToChildProcess(nsresult aResultCode) 1.3514 +{ 1.3515 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3516 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3517 + 1.3518 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.3519 + "GetHelper::SendResponseToChildProcess " 1.3520 + "[IDBObjectStore.cpp]"); 1.3521 + 1.3522 + IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); 1.3523 + NS_ASSERTION(actor, "How did we get this far without an actor?"); 1.3524 + 1.3525 + InfallibleTArray<PBlobParent*> blobsParent; 1.3526 + 1.3527 + if (NS_SUCCEEDED(aResultCode)) { 1.3528 + IDBDatabase* database = mObjectStore->Transaction()->Database(); 1.3529 + NS_ASSERTION(database, "This should never be null!"); 1.3530 + 1.3531 + ContentParent* contentParent = database->GetContentParent(); 1.3532 + NS_ASSERTION(contentParent, "This should never be null!"); 1.3533 + 1.3534 + FileManager* fileManager = database->Manager(); 1.3535 + NS_ASSERTION(fileManager, "This should never be null!"); 1.3536 + 1.3537 + const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles; 1.3538 + 1.3539 + aResultCode = 1.3540 + IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files, 1.3541 + blobsParent); 1.3542 + if (NS_FAILED(aResultCode)) { 1.3543 + NS_WARNING("ConvertBlobsToActors failed!"); 1.3544 + } 1.3545 + } 1.3546 + 1.3547 + ResponseValue response; 1.3548 + if (NS_FAILED(aResultCode)) { 1.3549 + response = aResultCode; 1.3550 + } 1.3551 + else { 1.3552 + GetResponse getResponse; 1.3553 + getResponse.cloneInfo() = mCloneReadInfo; 1.3554 + getResponse.blobsParent().SwapElements(blobsParent); 1.3555 + response = getResponse; 1.3556 + } 1.3557 + 1.3558 + if (!actor->SendResponse(response)) { 1.3559 + return Error; 1.3560 + } 1.3561 + 1.3562 + return Success_Sent; 1.3563 +} 1.3564 + 1.3565 +nsresult 1.3566 +GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) 1.3567 +{ 1.3568 + NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse, 1.3569 + "Bad response type!"); 1.3570 + 1.3571 + const GetResponse& getResponse = aResponseValue.get_GetResponse(); 1.3572 + const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo(); 1.3573 + 1.3574 + NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) || 1.3575 + (cloneInfo.dataLength && cloneInfo.data), 1.3576 + "Inconsistent clone info!"); 1.3577 + 1.3578 + if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) { 1.3579 + IDB_WARNING("Failed to copy clone buffer!"); 1.3580 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.3581 + } 1.3582 + 1.3583 + IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(), 1.3584 + mCloneReadInfo.mFiles); 1.3585 + return NS_OK; 1.3586 +} 1.3587 + 1.3588 +nsresult 1.3589 +DeleteHelper::DoDatabaseWork(mozIStorageConnection* /*aConnection */) 1.3590 +{ 1.3591 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.3592 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3593 + NS_ASSERTION(mKeyRange, "Must have a key range here!"); 1.3594 + 1.3595 + PROFILER_LABEL("IndexedDB", "DeleteHelper::DoDatabaseWork"); 1.3596 + 1.3597 + nsCString keyRangeClause; 1.3598 + mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause); 1.3599 + 1.3600 + NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!"); 1.3601 + 1.3602 + nsCString query = NS_LITERAL_CSTRING("DELETE FROM object_data " 1.3603 + "WHERE object_store_id = :osid") + 1.3604 + keyRangeClause; 1.3605 + 1.3606 + nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); 1.3607 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3608 + 1.3609 + mozStorageStatementScoper scoper(stmt); 1.3610 + 1.3611 + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), 1.3612 + mObjectStore->Id()); 1.3613 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3614 + 1.3615 + rv = mKeyRange->BindToStatement(stmt); 1.3616 + NS_ENSURE_SUCCESS(rv, rv); 1.3617 + 1.3618 + rv = stmt->Execute(); 1.3619 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3620 + 1.3621 + return NS_OK; 1.3622 +} 1.3623 + 1.3624 +nsresult 1.3625 +DeleteHelper::GetSuccessResult(JSContext* aCx, 1.3626 + JS::MutableHandle<JS::Value> aVal) 1.3627 +{ 1.3628 + aVal.setUndefined(); 1.3629 + return NS_OK; 1.3630 +} 1.3631 + 1.3632 +nsresult 1.3633 +DeleteHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) 1.3634 +{ 1.3635 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3636 + NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3637 + NS_ASSERTION(mKeyRange, "This should never be null!"); 1.3638 + 1.3639 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.3640 + "DeleteHelper::PackArgumentsForParentProcess"); 1.3641 + 1.3642 + DeleteParams params; 1.3643 + 1.3644 + mKeyRange->ToSerializedKeyRange(params.keyRange()); 1.3645 + 1.3646 + aParams = params; 1.3647 + return NS_OK; 1.3648 +} 1.3649 + 1.3650 +AsyncConnectionHelper::ChildProcessSendResult 1.3651 +DeleteHelper::SendResponseToChildProcess(nsresult aResultCode) 1.3652 +{ 1.3653 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3654 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3655 + 1.3656 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.3657 + "DeleteHelper::SendResponseToChildProcess"); 1.3658 + 1.3659 + IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); 1.3660 + NS_ASSERTION(actor, "How did we get this far without an actor?"); 1.3661 + 1.3662 + ResponseValue response; 1.3663 + if (NS_FAILED(aResultCode)) { 1.3664 + response = aResultCode; 1.3665 + } 1.3666 + else { 1.3667 + response = DeleteResponse(); 1.3668 + } 1.3669 + 1.3670 + if (!actor->SendResponse(response)) { 1.3671 + return Error; 1.3672 + } 1.3673 + 1.3674 + return Success_Sent; 1.3675 +} 1.3676 + 1.3677 +nsresult 1.3678 +DeleteHelper::UnpackResponseFromParentProcess( 1.3679 + const ResponseValue& aResponseValue) 1.3680 +{ 1.3681 + NS_ASSERTION(aResponseValue.type() == ResponseValue::TDeleteResponse, 1.3682 + "Bad response type!"); 1.3683 + 1.3684 + return NS_OK; 1.3685 +} 1.3686 + 1.3687 +nsresult 1.3688 +ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection) 1.3689 +{ 1.3690 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.3691 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3692 + NS_ASSERTION(aConnection, "Passed a null connection!"); 1.3693 + 1.3694 + PROFILER_LABEL("IndexedDB", "ClearHelper::DoDatabaseWork"); 1.3695 + 1.3696 + nsCOMPtr<mozIStorageStatement> stmt = 1.3697 + mTransaction->GetCachedStatement( 1.3698 + NS_LITERAL_CSTRING("DELETE FROM object_data " 1.3699 + "WHERE object_store_id = :osid")); 1.3700 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3701 + 1.3702 + mozStorageStatementScoper scoper(stmt); 1.3703 + 1.3704 + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), 1.3705 + mObjectStore->Id()); 1.3706 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3707 + 1.3708 + rv = stmt->Execute(); 1.3709 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3710 + 1.3711 + return NS_OK; 1.3712 +} 1.3713 + 1.3714 +nsresult 1.3715 +ClearHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) 1.3716 +{ 1.3717 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3718 + NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3719 + 1.3720 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.3721 + "ClearHelper::PackArgumentsForParentProcess"); 1.3722 + 1.3723 + aParams = ClearParams(); 1.3724 + return NS_OK; 1.3725 +} 1.3726 + 1.3727 +AsyncConnectionHelper::ChildProcessSendResult 1.3728 +ClearHelper::SendResponseToChildProcess(nsresult aResultCode) 1.3729 +{ 1.3730 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3731 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3732 + 1.3733 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.3734 + "ClearHelper::SendResponseToChildProcess"); 1.3735 + 1.3736 + IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); 1.3737 + NS_ASSERTION(actor, "How did we get this far without an actor?"); 1.3738 + 1.3739 + ResponseValue response; 1.3740 + if (NS_FAILED(aResultCode)) { 1.3741 + response = aResultCode; 1.3742 + } 1.3743 + else { 1.3744 + response = ClearResponse(); 1.3745 + } 1.3746 + 1.3747 + if (!actor->SendResponse(response)) { 1.3748 + return Error; 1.3749 + } 1.3750 + 1.3751 + return Success_Sent; 1.3752 +} 1.3753 + 1.3754 +nsresult 1.3755 +ClearHelper::UnpackResponseFromParentProcess( 1.3756 + const ResponseValue& aResponseValue) 1.3757 +{ 1.3758 + NS_ASSERTION(aResponseValue.type() == ResponseValue::TClearResponse, 1.3759 + "Bad response type!"); 1.3760 + 1.3761 + return NS_OK; 1.3762 +} 1.3763 + 1.3764 +nsresult 1.3765 +OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) 1.3766 +{ 1.3767 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.3768 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3769 + 1.3770 + PROFILER_LABEL("IndexedDB", 1.3771 + "OpenCursorHelper::DoDatabaseWork [IDBObjectStore.cpp]"); 1.3772 + 1.3773 + NS_NAMED_LITERAL_CSTRING(keyValue, "key_value"); 1.3774 + 1.3775 + nsCString keyRangeClause; 1.3776 + if (mKeyRange) { 1.3777 + mKeyRange->GetBindingClause(keyValue, keyRangeClause); 1.3778 + } 1.3779 + 1.3780 + nsAutoCString directionClause; 1.3781 + switch (mDirection) { 1.3782 + case IDBCursor::NEXT: 1.3783 + case IDBCursor::NEXT_UNIQUE: 1.3784 + directionClause.AssignLiteral(" ORDER BY key_value ASC"); 1.3785 + break; 1.3786 + 1.3787 + case IDBCursor::PREV: 1.3788 + case IDBCursor::PREV_UNIQUE: 1.3789 + directionClause.AssignLiteral(" ORDER BY key_value DESC"); 1.3790 + break; 1.3791 + 1.3792 + default: 1.3793 + NS_NOTREACHED("Unknown direction type!"); 1.3794 + } 1.3795 + 1.3796 + nsCString firstQuery = NS_LITERAL_CSTRING("SELECT key_value, data, file_ids " 1.3797 + "FROM object_data " 1.3798 + "WHERE object_store_id = :id") + 1.3799 + keyRangeClause + directionClause + 1.3800 + NS_LITERAL_CSTRING(" LIMIT 1"); 1.3801 + 1.3802 + nsCOMPtr<mozIStorageStatement> stmt = 1.3803 + mTransaction->GetCachedStatement(firstQuery); 1.3804 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3805 + 1.3806 + mozStorageStatementScoper scoper(stmt); 1.3807 + 1.3808 + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), 1.3809 + mObjectStore->Id()); 1.3810 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3811 + 1.3812 + if (mKeyRange) { 1.3813 + rv = mKeyRange->BindToStatement(stmt); 1.3814 + NS_ENSURE_SUCCESS(rv, rv); 1.3815 + } 1.3816 + 1.3817 + bool hasResult; 1.3818 + rv = stmt->ExecuteStep(&hasResult); 1.3819 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3820 + 1.3821 + if (!hasResult) { 1.3822 + mKey.Unset(); 1.3823 + return NS_OK; 1.3824 + } 1.3825 + 1.3826 + rv = mKey.SetFromStatement(stmt, 0); 1.3827 + NS_ENSURE_SUCCESS(rv, rv); 1.3828 + 1.3829 + rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 1, 2, 1.3830 + mDatabase, mCloneReadInfo); 1.3831 + NS_ENSURE_SUCCESS(rv, rv); 1.3832 + 1.3833 + // Now we need to make the query to get the next match. 1.3834 + keyRangeClause.Truncate(); 1.3835 + nsAutoCString continueToKeyRangeClause; 1.3836 + 1.3837 + NS_NAMED_LITERAL_CSTRING(currentKey, "current_key"); 1.3838 + NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key"); 1.3839 + 1.3840 + switch (mDirection) { 1.3841 + case IDBCursor::NEXT: 1.3842 + case IDBCursor::NEXT_UNIQUE: 1.3843 + AppendConditionClause(keyValue, currentKey, false, false, 1.3844 + keyRangeClause); 1.3845 + AppendConditionClause(keyValue, currentKey, false, true, 1.3846 + continueToKeyRangeClause); 1.3847 + if (mKeyRange && !mKeyRange->Upper().IsUnset()) { 1.3848 + AppendConditionClause(keyValue, rangeKey, true, 1.3849 + !mKeyRange->IsUpperOpen(), keyRangeClause); 1.3850 + AppendConditionClause(keyValue, rangeKey, true, 1.3851 + !mKeyRange->IsUpperOpen(), 1.3852 + continueToKeyRangeClause); 1.3853 + mRangeKey = mKeyRange->Upper(); 1.3854 + } 1.3855 + break; 1.3856 + 1.3857 + case IDBCursor::PREV: 1.3858 + case IDBCursor::PREV_UNIQUE: 1.3859 + AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause); 1.3860 + AppendConditionClause(keyValue, currentKey, true, true, 1.3861 + continueToKeyRangeClause); 1.3862 + if (mKeyRange && !mKeyRange->Lower().IsUnset()) { 1.3863 + AppendConditionClause(keyValue, rangeKey, false, 1.3864 + !mKeyRange->IsLowerOpen(), keyRangeClause); 1.3865 + AppendConditionClause(keyValue, rangeKey, false, 1.3866 + !mKeyRange->IsLowerOpen(), 1.3867 + continueToKeyRangeClause); 1.3868 + mRangeKey = mKeyRange->Lower(); 1.3869 + } 1.3870 + break; 1.3871 + 1.3872 + default: 1.3873 + NS_NOTREACHED("Unknown direction type!"); 1.3874 + } 1.3875 + 1.3876 + NS_NAMED_LITERAL_CSTRING(queryStart, "SELECT key_value, data, file_ids " 1.3877 + "FROM object_data " 1.3878 + "WHERE object_store_id = :id"); 1.3879 + 1.3880 + mContinueQuery = queryStart + keyRangeClause + directionClause + 1.3881 + NS_LITERAL_CSTRING(" LIMIT "); 1.3882 + 1.3883 + mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause + 1.3884 + NS_LITERAL_CSTRING(" LIMIT "); 1.3885 + 1.3886 + return NS_OK; 1.3887 +} 1.3888 + 1.3889 +nsresult 1.3890 +OpenCursorHelper::EnsureCursor() 1.3891 +{ 1.3892 + if (mCursor || mKey.IsUnset()) { 1.3893 + return NS_OK; 1.3894 + } 1.3895 + 1.3896 + mSerializedCloneReadInfo = mCloneReadInfo; 1.3897 + 1.3898 + NS_ASSERTION(mSerializedCloneReadInfo.data && 1.3899 + mSerializedCloneReadInfo.dataLength, 1.3900 + "Shouldn't be possible!"); 1.3901 + 1.3902 + nsRefPtr<IDBCursor> cursor = 1.3903 + IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection, 1.3904 + mRangeKey, mContinueQuery, mContinueToQuery, mKey, 1.3905 + Move(mCloneReadInfo)); 1.3906 + IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3907 + 1.3908 + NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!"); 1.3909 + 1.3910 + mCursor.swap(cursor); 1.3911 + return NS_OK; 1.3912 +} 1.3913 + 1.3914 +nsresult 1.3915 +OpenCursorHelper::GetSuccessResult(JSContext* aCx, 1.3916 + JS::MutableHandle<JS::Value> aVal) 1.3917 +{ 1.3918 + nsresult rv = EnsureCursor(); 1.3919 + NS_ENSURE_SUCCESS(rv, rv); 1.3920 + 1.3921 + if (mCursor) { 1.3922 + rv = WrapNative(aCx, mCursor, aVal); 1.3923 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.3924 + } 1.3925 + else { 1.3926 + aVal.setUndefined(); 1.3927 + } 1.3928 + 1.3929 + return NS_OK; 1.3930 +} 1.3931 + 1.3932 +void 1.3933 +OpenCursorHelper::ReleaseMainThreadObjects() 1.3934 +{ 1.3935 + mKeyRange = nullptr; 1.3936 + IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo); 1.3937 + 1.3938 + mCursor = nullptr; 1.3939 + 1.3940 + // These don't need to be released on the main thread but they're only valid 1.3941 + // as long as mCursor is set. 1.3942 + mSerializedCloneReadInfo.data = nullptr; 1.3943 + mSerializedCloneReadInfo.dataLength = 0; 1.3944 + 1.3945 + ObjectStoreHelper::ReleaseMainThreadObjects(); 1.3946 +} 1.3947 + 1.3948 +nsresult 1.3949 +OpenCursorHelper::PackArgumentsForParentProcess( 1.3950 + ObjectStoreRequestParams& aParams) 1.3951 +{ 1.3952 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3953 + NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3954 + 1.3955 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.3956 + "OpenCursorHelper::PackArgumentsForParentProcess " 1.3957 + "[IDBObjectStore.cpp]"); 1.3958 + 1.3959 + OpenCursorParams params; 1.3960 + 1.3961 + if (mKeyRange) { 1.3962 + KeyRange keyRange; 1.3963 + mKeyRange->ToSerializedKeyRange(keyRange); 1.3964 + params.optionalKeyRange() = keyRange; 1.3965 + } 1.3966 + else { 1.3967 + params.optionalKeyRange() = mozilla::void_t(); 1.3968 + } 1.3969 + 1.3970 + params.direction() = mDirection; 1.3971 + 1.3972 + aParams = params; 1.3973 + return NS_OK; 1.3974 +} 1.3975 + 1.3976 +AsyncConnectionHelper::ChildProcessSendResult 1.3977 +OpenCursorHelper::SendResponseToChildProcess(nsresult aResultCode) 1.3978 +{ 1.3979 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.3980 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.3981 + NS_ASSERTION(!mCursor, "Shouldn't have this yet!"); 1.3982 + 1.3983 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.3984 + "OpenCursorHelper::SendResponseToChildProcess " 1.3985 + "[IDBObjectStore.cpp]"); 1.3986 + 1.3987 + IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); 1.3988 + NS_ASSERTION(actor, "How did we get this far without an actor?"); 1.3989 + 1.3990 + InfallibleTArray<PBlobParent*> blobsParent; 1.3991 + 1.3992 + if (NS_SUCCEEDED(aResultCode)) { 1.3993 + IDBDatabase* database = mObjectStore->Transaction()->Database(); 1.3994 + NS_ASSERTION(database, "This should never be null!"); 1.3995 + 1.3996 + ContentParent* contentParent = database->GetContentParent(); 1.3997 + NS_ASSERTION(contentParent, "This should never be null!"); 1.3998 + 1.3999 + FileManager* fileManager = database->Manager(); 1.4000 + NS_ASSERTION(fileManager, "This should never be null!"); 1.4001 + 1.4002 + const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles; 1.4003 + 1.4004 + aResultCode = 1.4005 + IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files, 1.4006 + blobsParent); 1.4007 + if (NS_FAILED(aResultCode)) { 1.4008 + NS_WARNING("ConvertBlobsToActors failed!"); 1.4009 + } 1.4010 + } 1.4011 + 1.4012 + if (NS_SUCCEEDED(aResultCode)) { 1.4013 + nsresult rv = EnsureCursor(); 1.4014 + if (NS_FAILED(rv)) { 1.4015 + NS_WARNING("EnsureCursor failed!"); 1.4016 + aResultCode = rv; 1.4017 + } 1.4018 + } 1.4019 + 1.4020 + ResponseValue response; 1.4021 + if (NS_FAILED(aResultCode)) { 1.4022 + response = aResultCode; 1.4023 + } 1.4024 + else { 1.4025 + OpenCursorResponse openCursorResponse; 1.4026 + 1.4027 + if (!mCursor) { 1.4028 + openCursorResponse = mozilla::void_t(); 1.4029 + } 1.4030 + else { 1.4031 + IndexedDBObjectStoreParent* objectStoreActor = 1.4032 + mObjectStore->GetActorParent(); 1.4033 + NS_ASSERTION(objectStoreActor, "Must have an actor here!"); 1.4034 + 1.4035 + IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent(); 1.4036 + NS_ASSERTION(requestActor, "Must have an actor here!"); 1.4037 + 1.4038 + NS_ASSERTION(mSerializedCloneReadInfo.data && 1.4039 + mSerializedCloneReadInfo.dataLength, 1.4040 + "Shouldn't be possible!"); 1.4041 + 1.4042 + ObjectStoreCursorConstructorParams params; 1.4043 + params.requestParent() = requestActor; 1.4044 + params.direction() = mDirection; 1.4045 + params.key() = mKey; 1.4046 + params.optionalCloneInfo() = mSerializedCloneReadInfo; 1.4047 + params.blobsParent().SwapElements(blobsParent); 1.4048 + 1.4049 + if (!objectStoreActor->OpenCursor(mCursor, params, openCursorResponse)) { 1.4050 + return Error; 1.4051 + } 1.4052 + } 1.4053 + 1.4054 + response = openCursorResponse; 1.4055 + } 1.4056 + 1.4057 + if (!actor->SendResponse(response)) { 1.4058 + return Error; 1.4059 + } 1.4060 + 1.4061 + return Success_Sent; 1.4062 +} 1.4063 + 1.4064 +nsresult 1.4065 +OpenCursorHelper::UnpackResponseFromParentProcess( 1.4066 + const ResponseValue& aResponseValue) 1.4067 +{ 1.4068 + NS_ASSERTION(aResponseValue.type() == ResponseValue::TOpenCursorResponse, 1.4069 + "Bad response type!"); 1.4070 + NS_ASSERTION(aResponseValue.get_OpenCursorResponse().type() == 1.4071 + OpenCursorResponse::Tvoid_t || 1.4072 + aResponseValue.get_OpenCursorResponse().type() == 1.4073 + OpenCursorResponse::TPIndexedDBCursorChild, 1.4074 + "Bad response union type!"); 1.4075 + NS_ASSERTION(!mCursor, "Shouldn't have this yet!"); 1.4076 + 1.4077 + const OpenCursorResponse& response = 1.4078 + aResponseValue.get_OpenCursorResponse(); 1.4079 + 1.4080 + switch (response.type()) { 1.4081 + case OpenCursorResponse::Tvoid_t: 1.4082 + break; 1.4083 + 1.4084 + case OpenCursorResponse::TPIndexedDBCursorChild: { 1.4085 + IndexedDBCursorChild* actor = 1.4086 + static_cast<IndexedDBCursorChild*>( 1.4087 + response.get_PIndexedDBCursorChild()); 1.4088 + 1.4089 + mCursor = actor->ForgetStrongCursor(); 1.4090 + NS_ASSERTION(mCursor, "This should never be null!"); 1.4091 + 1.4092 + } break; 1.4093 + 1.4094 + default: 1.4095 + MOZ_CRASH(); 1.4096 + } 1.4097 + 1.4098 + return NS_OK; 1.4099 +} 1.4100 + 1.4101 +nsresult 1.4102 +OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) 1.4103 +{ 1.4104 + MOZ_ASSERT(!NS_IsMainThread()); 1.4105 + MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess()); 1.4106 + 1.4107 + PROFILER_LABEL("IndexedDB", 1.4108 + "OpenKeyCursorHelper::DoDatabaseWork [IDBObjectStore.cpp]"); 1.4109 + 1.4110 + NS_NAMED_LITERAL_CSTRING(keyValue, "key_value"); 1.4111 + NS_NAMED_LITERAL_CSTRING(id, "id"); 1.4112 + NS_NAMED_LITERAL_CSTRING(openLimit, " LIMIT "); 1.4113 + 1.4114 + nsAutoCString queryStart = NS_LITERAL_CSTRING("SELECT ") + keyValue + 1.4115 + NS_LITERAL_CSTRING(" FROM object_data WHERE " 1.4116 + "object_store_id = :") + 1.4117 + id; 1.4118 + 1.4119 + nsAutoCString keyRangeClause; 1.4120 + if (mKeyRange) { 1.4121 + mKeyRange->GetBindingClause(keyValue, keyRangeClause); 1.4122 + } 1.4123 + 1.4124 + nsAutoCString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + keyValue; 1.4125 + switch (mDirection) { 1.4126 + case IDBCursor::NEXT: 1.4127 + case IDBCursor::NEXT_UNIQUE: 1.4128 + directionClause.AppendLiteral(" ASC"); 1.4129 + break; 1.4130 + 1.4131 + case IDBCursor::PREV: 1.4132 + case IDBCursor::PREV_UNIQUE: 1.4133 + directionClause.AppendLiteral(" DESC"); 1.4134 + break; 1.4135 + 1.4136 + default: 1.4137 + MOZ_ASSUME_UNREACHABLE("Unknown direction type!"); 1.4138 + } 1.4139 + 1.4140 + nsCString firstQuery = queryStart + keyRangeClause + directionClause + 1.4141 + openLimit + NS_LITERAL_CSTRING("1"); 1.4142 + 1.4143 + nsCOMPtr<mozIStorageStatement> stmt = 1.4144 + mTransaction->GetCachedStatement(firstQuery); 1.4145 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4146 + 1.4147 + mozStorageStatementScoper scoper(stmt); 1.4148 + 1.4149 + nsresult rv = stmt->BindInt64ByName(id, mObjectStore->Id()); 1.4150 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4151 + 1.4152 + if (mKeyRange) { 1.4153 + rv = mKeyRange->BindToStatement(stmt); 1.4154 + NS_ENSURE_SUCCESS(rv, rv); 1.4155 + } 1.4156 + 1.4157 + bool hasResult; 1.4158 + rv = stmt->ExecuteStep(&hasResult); 1.4159 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4160 + 1.4161 + if (!hasResult) { 1.4162 + mKey.Unset(); 1.4163 + return NS_OK; 1.4164 + } 1.4165 + 1.4166 + rv = mKey.SetFromStatement(stmt, 0); 1.4167 + NS_ENSURE_SUCCESS(rv, rv); 1.4168 + 1.4169 + // Now we need to make the query to get the next match. 1.4170 + keyRangeClause.Truncate(); 1.4171 + nsAutoCString continueToKeyRangeClause; 1.4172 + 1.4173 + NS_NAMED_LITERAL_CSTRING(currentKey, "current_key"); 1.4174 + NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key"); 1.4175 + 1.4176 + switch (mDirection) { 1.4177 + case IDBCursor::NEXT: 1.4178 + case IDBCursor::NEXT_UNIQUE: 1.4179 + AppendConditionClause(keyValue, currentKey, false, false, 1.4180 + keyRangeClause); 1.4181 + AppendConditionClause(keyValue, currentKey, false, true, 1.4182 + continueToKeyRangeClause); 1.4183 + if (mKeyRange && !mKeyRange->Upper().IsUnset()) { 1.4184 + AppendConditionClause(keyValue, rangeKey, true, 1.4185 + !mKeyRange->IsUpperOpen(), keyRangeClause); 1.4186 + AppendConditionClause(keyValue, rangeKey, true, 1.4187 + !mKeyRange->IsUpperOpen(), 1.4188 + continueToKeyRangeClause); 1.4189 + mRangeKey = mKeyRange->Upper(); 1.4190 + } 1.4191 + break; 1.4192 + 1.4193 + case IDBCursor::PREV: 1.4194 + case IDBCursor::PREV_UNIQUE: 1.4195 + AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause); 1.4196 + AppendConditionClause(keyValue, currentKey, true, true, 1.4197 + continueToKeyRangeClause); 1.4198 + if (mKeyRange && !mKeyRange->Lower().IsUnset()) { 1.4199 + AppendConditionClause(keyValue, rangeKey, false, 1.4200 + !mKeyRange->IsLowerOpen(), keyRangeClause); 1.4201 + AppendConditionClause(keyValue, rangeKey, false, 1.4202 + !mKeyRange->IsLowerOpen(), 1.4203 + continueToKeyRangeClause); 1.4204 + mRangeKey = mKeyRange->Lower(); 1.4205 + } 1.4206 + break; 1.4207 + 1.4208 + default: 1.4209 + MOZ_ASSUME_UNREACHABLE("Unknown direction type!"); 1.4210 + } 1.4211 + 1.4212 + mContinueQuery = queryStart + keyRangeClause + directionClause + openLimit; 1.4213 + mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause + 1.4214 + openLimit; 1.4215 + 1.4216 + return NS_OK; 1.4217 +} 1.4218 + 1.4219 +nsresult 1.4220 +OpenKeyCursorHelper::EnsureCursor() 1.4221 +{ 1.4222 + MOZ_ASSERT(NS_IsMainThread()); 1.4223 + 1.4224 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.4225 + "OpenKeyCursorHelper::EnsureCursor " 1.4226 + "[IDBObjectStore.cpp]"); 1.4227 + 1.4228 + if (mCursor || mKey.IsUnset()) { 1.4229 + return NS_OK; 1.4230 + } 1.4231 + 1.4232 + mCursor = IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection, 1.4233 + mRangeKey, mContinueQuery, mContinueToQuery, 1.4234 + mKey); 1.4235 + IDB_ENSURE_TRUE(mCursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4236 + 1.4237 + return NS_OK; 1.4238 +} 1.4239 + 1.4240 +nsresult 1.4241 +OpenKeyCursorHelper::GetSuccessResult(JSContext* aCx, 1.4242 + JS::MutableHandle<JS::Value> aVal) 1.4243 +{ 1.4244 + MOZ_ASSERT(NS_IsMainThread()); 1.4245 + 1.4246 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.4247 + "OpenKeyCursorHelper::GetSuccessResult " 1.4248 + "[IDBObjectStore.cpp]"); 1.4249 + 1.4250 + nsresult rv = EnsureCursor(); 1.4251 + NS_ENSURE_SUCCESS(rv, rv); 1.4252 + 1.4253 + if (mCursor) { 1.4254 + rv = WrapNative(aCx, mCursor, aVal); 1.4255 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4256 + } 1.4257 + else { 1.4258 + aVal.setUndefined(); 1.4259 + } 1.4260 + 1.4261 + return NS_OK; 1.4262 +} 1.4263 + 1.4264 +void 1.4265 +OpenKeyCursorHelper::ReleaseMainThreadObjects() 1.4266 +{ 1.4267 + MOZ_ASSERT(NS_IsMainThread()); 1.4268 + 1.4269 + mKeyRange = nullptr; 1.4270 + mCursor = nullptr; 1.4271 + 1.4272 + ObjectStoreHelper::ReleaseMainThreadObjects(); 1.4273 +} 1.4274 + 1.4275 +nsresult 1.4276 +OpenKeyCursorHelper::PackArgumentsForParentProcess( 1.4277 + ObjectStoreRequestParams& aParams) 1.4278 +{ 1.4279 + MOZ_ASSERT(NS_IsMainThread()); 1.4280 + MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess()); 1.4281 + 1.4282 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.4283 + "OpenKeyCursorHelper::" 1.4284 + "PackArgumentsForParentProcess " 1.4285 + "[IDBObjectStore.cpp]"); 1.4286 + 1.4287 + OpenKeyCursorParams params; 1.4288 + 1.4289 + if (mKeyRange) { 1.4290 + KeyRange keyRange; 1.4291 + mKeyRange->ToSerializedKeyRange(keyRange); 1.4292 + params.optionalKeyRange() = keyRange; 1.4293 + } 1.4294 + else { 1.4295 + params.optionalKeyRange() = mozilla::void_t(); 1.4296 + } 1.4297 + 1.4298 + params.direction() = mDirection; 1.4299 + 1.4300 + aParams = params; 1.4301 + return NS_OK; 1.4302 +} 1.4303 + 1.4304 +AsyncConnectionHelper::ChildProcessSendResult 1.4305 +OpenKeyCursorHelper::SendResponseToChildProcess(nsresult aResultCode) 1.4306 +{ 1.4307 + MOZ_ASSERT(NS_IsMainThread()); 1.4308 + MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess()); 1.4309 + MOZ_ASSERT(!mCursor); 1.4310 + 1.4311 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.4312 + "OpenKeyCursorHelper::SendResponseToChildProcess " 1.4313 + "[IDBObjectStore.cpp]"); 1.4314 + 1.4315 + IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); 1.4316 + MOZ_ASSERT(actor); 1.4317 + 1.4318 + if (NS_SUCCEEDED(aResultCode)) { 1.4319 + nsresult rv = EnsureCursor(); 1.4320 + if (NS_FAILED(rv)) { 1.4321 + NS_WARNING("EnsureCursor failed!"); 1.4322 + aResultCode = rv; 1.4323 + } 1.4324 + } 1.4325 + 1.4326 + ResponseValue response; 1.4327 + if (NS_FAILED(aResultCode)) { 1.4328 + response = aResultCode; 1.4329 + } else { 1.4330 + OpenCursorResponse openCursorResponse; 1.4331 + 1.4332 + if (!mCursor) { 1.4333 + openCursorResponse = mozilla::void_t(); 1.4334 + } 1.4335 + else { 1.4336 + IndexedDBObjectStoreParent* objectStoreActor = 1.4337 + mObjectStore->GetActorParent(); 1.4338 + MOZ_ASSERT(objectStoreActor); 1.4339 + 1.4340 + IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent(); 1.4341 + MOZ_ASSERT(requestActor); 1.4342 + 1.4343 + ObjectStoreCursorConstructorParams params; 1.4344 + params.requestParent() = requestActor; 1.4345 + params.direction() = mDirection; 1.4346 + params.key() = mKey; 1.4347 + params.optionalCloneInfo() = mozilla::void_t(); 1.4348 + 1.4349 + if (!objectStoreActor->OpenCursor(mCursor, params, openCursorResponse)) { 1.4350 + return Error; 1.4351 + } 1.4352 + } 1.4353 + 1.4354 + response = openCursorResponse; 1.4355 + } 1.4356 + 1.4357 + if (!actor->SendResponse(response)) { 1.4358 + return Error; 1.4359 + } 1.4360 + 1.4361 + return Success_Sent; 1.4362 +} 1.4363 + 1.4364 +nsresult 1.4365 +OpenKeyCursorHelper::UnpackResponseFromParentProcess( 1.4366 + const ResponseValue& aResponseValue) 1.4367 +{ 1.4368 + MOZ_ASSERT(NS_IsMainThread()); 1.4369 + MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess()); 1.4370 + MOZ_ASSERT(aResponseValue.type() == ResponseValue::TOpenCursorResponse); 1.4371 + MOZ_ASSERT(aResponseValue.get_OpenCursorResponse().type() == 1.4372 + OpenCursorResponse::Tvoid_t || 1.4373 + aResponseValue.get_OpenCursorResponse().type() == 1.4374 + OpenCursorResponse::TPIndexedDBCursorChild); 1.4375 + MOZ_ASSERT(!mCursor); 1.4376 + 1.4377 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.4378 + "OpenKeyCursorHelper::" 1.4379 + "UnpackResponseFromParentProcess " 1.4380 + "[IDBObjectStore.cpp]"); 1.4381 + 1.4382 + const OpenCursorResponse& response = 1.4383 + aResponseValue.get_OpenCursorResponse(); 1.4384 + 1.4385 + switch (response.type()) { 1.4386 + case OpenCursorResponse::Tvoid_t: 1.4387 + break; 1.4388 + 1.4389 + case OpenCursorResponse::TPIndexedDBCursorChild: { 1.4390 + IndexedDBCursorChild* actor = 1.4391 + static_cast<IndexedDBCursorChild*>( 1.4392 + response.get_PIndexedDBCursorChild()); 1.4393 + 1.4394 + mCursor = actor->ForgetStrongCursor(); 1.4395 + NS_ASSERTION(mCursor, "This should never be null!"); 1.4396 + 1.4397 + } break; 1.4398 + 1.4399 + default: 1.4400 + MOZ_CRASH("Unknown response union type!"); 1.4401 + } 1.4402 + 1.4403 + return NS_OK; 1.4404 +} 1.4405 + 1.4406 +nsresult 1.4407 +CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection) 1.4408 +{ 1.4409 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.4410 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.4411 + 1.4412 + PROFILER_LABEL("IndexedDB", "CreateIndexHelper::DoDatabaseWork"); 1.4413 + 1.4414 + if (IndexedDatabaseManager::InLowDiskSpaceMode()) { 1.4415 + NS_WARNING("Refusing to create index because disk space is low!"); 1.4416 + return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; 1.4417 + } 1.4418 + 1.4419 + // Insert the data into the database. 1.4420 + nsCOMPtr<mozIStorageStatement> stmt = 1.4421 + mTransaction->GetCachedStatement( 1.4422 + "INSERT INTO object_store_index (id, name, key_path, unique_index, " 1.4423 + "multientry, object_store_id) " 1.4424 + "VALUES (:id, :name, :key_path, :unique, :multientry, :osid)" 1.4425 + ); 1.4426 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4427 + 1.4428 + mozStorageStatementScoper scoper(stmt); 1.4429 + 1.4430 + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), 1.4431 + mIndex->Id()); 1.4432 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4433 + 1.4434 + rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mIndex->Name()); 1.4435 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4436 + 1.4437 + nsAutoString keyPathSerialization; 1.4438 + mIndex->GetKeyPath().SerializeToString(keyPathSerialization); 1.4439 + rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"), 1.4440 + keyPathSerialization); 1.4441 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4442 + 1.4443 + rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("unique"), 1.4444 + mIndex->IsUnique() ? 1 : 0); 1.4445 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4446 + 1.4447 + rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("multientry"), 1.4448 + mIndex->IsMultiEntry() ? 1 : 0); 1.4449 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4450 + 1.4451 + rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), 1.4452 + mIndex->ObjectStore()->Id()); 1.4453 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4454 + 1.4455 + if (NS_FAILED(stmt->Execute())) { 1.4456 + return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; 1.4457 + } 1.4458 + 1.4459 +#ifdef DEBUG 1.4460 + { 1.4461 + int64_t id; 1.4462 + aConnection->GetLastInsertRowID(&id); 1.4463 + NS_ASSERTION(mIndex->Id() == id, "Bad index id!"); 1.4464 + } 1.4465 +#endif 1.4466 + 1.4467 + // Now we need to populate the index with data from the object store. 1.4468 + rv = InsertDataFromObjectStore(aConnection); 1.4469 + if (NS_FAILED(rv)) { 1.4470 + return rv; 1.4471 + } 1.4472 + 1.4473 + return NS_OK; 1.4474 +} 1.4475 + 1.4476 +void 1.4477 +CreateIndexHelper::ReleaseMainThreadObjects() 1.4478 +{ 1.4479 + mIndex = nullptr; 1.4480 + NoRequestObjectStoreHelper::ReleaseMainThreadObjects(); 1.4481 +} 1.4482 + 1.4483 +nsresult 1.4484 +CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection) 1.4485 +{ 1.4486 + nsCOMPtr<mozIStorageStatement> stmt = 1.4487 + mTransaction->GetCachedStatement( 1.4488 + NS_LITERAL_CSTRING("SELECT id, data, file_ids, key_value FROM " 1.4489 + "object_data WHERE object_store_id = :osid")); 1.4490 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4491 + 1.4492 + mozStorageStatementScoper scoper(stmt); 1.4493 + 1.4494 + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), 1.4495 + mIndex->ObjectStore()->Id()); 1.4496 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4497 + 1.4498 + IDB_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, 1.4499 + NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4500 + 1.4501 + bool hasResult; 1.4502 + rv = stmt->ExecuteStep(&hasResult); 1.4503 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4504 + if (!hasResult) { 1.4505 + // Bail early if we have no data to avoid creating the below runtime 1.4506 + return NS_OK; 1.4507 + } 1.4508 + 1.4509 + ThreadLocalJSRuntime* tlsEntry = 1.4510 + reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex)); 1.4511 + 1.4512 + if (!tlsEntry) { 1.4513 + tlsEntry = ThreadLocalJSRuntime::Create(); 1.4514 + IDB_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4515 + 1.4516 + PR_SetThreadPrivate(sTLSIndex, tlsEntry); 1.4517 + } 1.4518 + 1.4519 + JSContext* cx = tlsEntry->Context(); 1.4520 + JSAutoRequest ar(cx); 1.4521 + JSAutoCompartment ac(cx, tlsEntry->Global()); 1.4522 + 1.4523 + do { 1.4524 + StructuredCloneReadInfo cloneReadInfo; 1.4525 + rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 1, 2, 1.4526 + mDatabase, cloneReadInfo); 1.4527 + NS_ENSURE_SUCCESS(rv, rv); 1.4528 + 1.4529 + JSAutoStructuredCloneBuffer& buffer = cloneReadInfo.mCloneBuffer; 1.4530 + 1.4531 + JSStructuredCloneCallbacks callbacks = { 1.4532 + IDBObjectStore::StructuredCloneReadCallback<CreateIndexDeserializationTraits>, 1.4533 + nullptr, 1.4534 + nullptr, 1.4535 + nullptr, 1.4536 + nullptr, 1.4537 + nullptr 1.4538 + }; 1.4539 + 1.4540 + JS::Rooted<JS::Value> clone(cx); 1.4541 + if (!buffer.read(cx, &clone, &callbacks, &cloneReadInfo)) { 1.4542 + NS_WARNING("Failed to deserialize structured clone data!"); 1.4543 + return NS_ERROR_DOM_DATA_CLONE_ERR; 1.4544 + } 1.4545 + 1.4546 + nsTArray<IndexUpdateInfo> updateInfo; 1.4547 + rv = IDBObjectStore::AppendIndexUpdateInfo(mIndex->Id(), 1.4548 + mIndex->GetKeyPath(), 1.4549 + mIndex->IsUnique(), 1.4550 + mIndex->IsMultiEntry(), 1.4551 + tlsEntry->Context(), 1.4552 + clone, updateInfo); 1.4553 + NS_ENSURE_SUCCESS(rv, rv); 1.4554 + 1.4555 + int64_t objectDataID = stmt->AsInt64(0); 1.4556 + 1.4557 + Key key; 1.4558 + rv = key.SetFromStatement(stmt, 3); 1.4559 + NS_ENSURE_SUCCESS(rv, rv); 1.4560 + 1.4561 + rv = IDBObjectStore::UpdateIndexes(mTransaction, mIndex->Id(), 1.4562 + key, false, objectDataID, updateInfo); 1.4563 + NS_ENSURE_SUCCESS(rv, rv); 1.4564 + 1.4565 + } while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult); 1.4566 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4567 + 1.4568 + return NS_OK; 1.4569 +} 1.4570 + 1.4571 +void 1.4572 +CreateIndexHelper::DestroyTLSEntry(void* aPtr) 1.4573 +{ 1.4574 + delete reinterpret_cast<ThreadLocalJSRuntime *>(aPtr); 1.4575 +} 1.4576 + 1.4577 +nsresult 1.4578 +DeleteIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection) 1.4579 +{ 1.4580 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.4581 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.4582 + 1.4583 + PROFILER_LABEL("IndexedDB", "DeleteIndexHelper::DoDatabaseWork"); 1.4584 + 1.4585 + nsCOMPtr<mozIStorageStatement> stmt = 1.4586 + mTransaction->GetCachedStatement( 1.4587 + "DELETE FROM object_store_index " 1.4588 + "WHERE name = :name " 1.4589 + ); 1.4590 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4591 + 1.4592 + mozStorageStatementScoper scoper(stmt); 1.4593 + 1.4594 + nsresult rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mName); 1.4595 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4596 + 1.4597 + if (NS_FAILED(stmt->Execute())) { 1.4598 + return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR; 1.4599 + } 1.4600 + 1.4601 + return NS_OK; 1.4602 +} 1.4603 + 1.4604 +nsresult 1.4605 +GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection) 1.4606 +{ 1.4607 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.4608 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.4609 + 1.4610 + PROFILER_LABEL("IndexedDB", 1.4611 + "GetAllHelper::DoDatabaseWork [IDBObjectStore.cpp]"); 1.4612 + 1.4613 + NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key"); 1.4614 + NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key"); 1.4615 + 1.4616 + nsAutoCString keyRangeClause; 1.4617 + if (mKeyRange) { 1.4618 + if (!mKeyRange->Lower().IsUnset()) { 1.4619 + keyRangeClause = NS_LITERAL_CSTRING(" AND key_value"); 1.4620 + if (mKeyRange->IsLowerOpen()) { 1.4621 + keyRangeClause.AppendLiteral(" > :"); 1.4622 + } 1.4623 + else { 1.4624 + keyRangeClause.AppendLiteral(" >= :"); 1.4625 + } 1.4626 + keyRangeClause.Append(lowerKeyName); 1.4627 + } 1.4628 + 1.4629 + if (!mKeyRange->Upper().IsUnset()) { 1.4630 + keyRangeClause += NS_LITERAL_CSTRING(" AND key_value"); 1.4631 + if (mKeyRange->IsUpperOpen()) { 1.4632 + keyRangeClause.AppendLiteral(" < :"); 1.4633 + } 1.4634 + else { 1.4635 + keyRangeClause.AppendLiteral(" <= :"); 1.4636 + } 1.4637 + keyRangeClause.Append(upperKeyName); 1.4638 + } 1.4639 + } 1.4640 + 1.4641 + nsAutoCString limitClause; 1.4642 + if (mLimit != UINT32_MAX) { 1.4643 + limitClause.AssignLiteral(" LIMIT "); 1.4644 + limitClause.AppendInt(mLimit); 1.4645 + } 1.4646 + 1.4647 + nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data " 1.4648 + "WHERE object_store_id = :osid") + 1.4649 + keyRangeClause + 1.4650 + NS_LITERAL_CSTRING(" ORDER BY key_value ASC") + 1.4651 + limitClause; 1.4652 + 1.4653 + mCloneReadInfos.SetCapacity(50); 1.4654 + 1.4655 + nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); 1.4656 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4657 + 1.4658 + mozStorageStatementScoper scoper(stmt); 1.4659 + 1.4660 + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), 1.4661 + mObjectStore->Id()); 1.4662 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4663 + 1.4664 + if (mKeyRange) { 1.4665 + if (!mKeyRange->Lower().IsUnset()) { 1.4666 + rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName); 1.4667 + NS_ENSURE_SUCCESS(rv, rv); 1.4668 + } 1.4669 + if (!mKeyRange->Upper().IsUnset()) { 1.4670 + rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName); 1.4671 + NS_ENSURE_SUCCESS(rv, rv); 1.4672 + } 1.4673 + } 1.4674 + 1.4675 + bool hasResult; 1.4676 + while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) { 1.4677 + if (mCloneReadInfos.Capacity() == mCloneReadInfos.Length()) { 1.4678 + mCloneReadInfos.SetCapacity(mCloneReadInfos.Capacity() * 2); 1.4679 + } 1.4680 + 1.4681 + StructuredCloneReadInfo* readInfo = mCloneReadInfos.AppendElement(); 1.4682 + NS_ASSERTION(readInfo, "Shouldn't fail since SetCapacity succeeded!"); 1.4683 + 1.4684 + rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1, 1.4685 + mDatabase, *readInfo); 1.4686 + NS_ENSURE_SUCCESS(rv, rv); 1.4687 + } 1.4688 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4689 + 1.4690 + return NS_OK; 1.4691 +} 1.4692 + 1.4693 +nsresult 1.4694 +GetAllHelper::GetSuccessResult(JSContext* aCx, 1.4695 + JS::MutableHandle<JS::Value> aVal) 1.4696 +{ 1.4697 + NS_ASSERTION(mCloneReadInfos.Length() <= mLimit, "Too many results!"); 1.4698 + 1.4699 + nsresult rv = ConvertToArrayAndCleanup(aCx, mCloneReadInfos, aVal); 1.4700 + 1.4701 + NS_ASSERTION(mCloneReadInfos.IsEmpty(), 1.4702 + "Should have cleared in ConvertToArrayAndCleanup"); 1.4703 + NS_ENSURE_SUCCESS(rv, rv); 1.4704 + 1.4705 + return NS_OK; 1.4706 +} 1.4707 + 1.4708 +void 1.4709 +GetAllHelper::ReleaseMainThreadObjects() 1.4710 +{ 1.4711 + mKeyRange = nullptr; 1.4712 + for (uint32_t index = 0; index < mCloneReadInfos.Length(); index++) { 1.4713 + IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos[index]); 1.4714 + } 1.4715 + ObjectStoreHelper::ReleaseMainThreadObjects(); 1.4716 +} 1.4717 + 1.4718 +nsresult 1.4719 +GetAllHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) 1.4720 +{ 1.4721 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.4722 + NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.4723 + 1.4724 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.4725 + "GetAllHelper::PackArgumentsForParentProcess " 1.4726 + "[IDBObjectStore.cpp]"); 1.4727 + 1.4728 + GetAllParams params; 1.4729 + 1.4730 + if (mKeyRange) { 1.4731 + KeyRange keyRange; 1.4732 + mKeyRange->ToSerializedKeyRange(keyRange); 1.4733 + params.optionalKeyRange() = keyRange; 1.4734 + } 1.4735 + else { 1.4736 + params.optionalKeyRange() = mozilla::void_t(); 1.4737 + } 1.4738 + 1.4739 + params.limit() = mLimit; 1.4740 + 1.4741 + aParams = params; 1.4742 + return NS_OK; 1.4743 +} 1.4744 + 1.4745 +AsyncConnectionHelper::ChildProcessSendResult 1.4746 +GetAllHelper::SendResponseToChildProcess(nsresult aResultCode) 1.4747 +{ 1.4748 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.4749 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.4750 + 1.4751 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.4752 + "GetAllHelper::SendResponseToChildProcess " 1.4753 + "[IDBObjectStore.cpp]"); 1.4754 + 1.4755 + IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); 1.4756 + NS_ASSERTION(actor, "How did we get this far without an actor?"); 1.4757 + 1.4758 + GetAllResponse getAllResponse; 1.4759 + if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) { 1.4760 + IDBDatabase* database = mObjectStore->Transaction()->Database(); 1.4761 + NS_ASSERTION(database, "This should never be null!"); 1.4762 + 1.4763 + ContentParent* contentParent = database->GetContentParent(); 1.4764 + NS_ASSERTION(contentParent, "This should never be null!"); 1.4765 + 1.4766 + FileManager* fileManager = database->Manager(); 1.4767 + NS_ASSERTION(fileManager, "This should never be null!"); 1.4768 + 1.4769 + uint32_t length = mCloneReadInfos.Length(); 1.4770 + 1.4771 + InfallibleTArray<SerializedStructuredCloneReadInfo>& infos = 1.4772 + getAllResponse.cloneInfos(); 1.4773 + infos.SetCapacity(length); 1.4774 + 1.4775 + InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs(); 1.4776 + blobArrays.SetCapacity(length); 1.4777 + 1.4778 + for (uint32_t index = 0; 1.4779 + NS_SUCCEEDED(aResultCode) && index < length; 1.4780 + index++) { 1.4781 + // Append the structured clone data. 1.4782 + const StructuredCloneReadInfo& clone = mCloneReadInfos[index]; 1.4783 + SerializedStructuredCloneReadInfo* info = infos.AppendElement(); 1.4784 + *info = clone; 1.4785 + 1.4786 + // Now take care of the files. 1.4787 + const nsTArray<StructuredCloneFile>& files = clone.mFiles; 1.4788 + BlobArray* blobArray = blobArrays.AppendElement(); 1.4789 + InfallibleTArray<PBlobParent*>& blobs = blobArray->blobsParent(); 1.4790 + 1.4791 + aResultCode = 1.4792 + IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files, 1.4793 + blobs); 1.4794 + if (NS_FAILED(aResultCode)) { 1.4795 + NS_WARNING("ConvertBlobsToActors failed!"); 1.4796 + break; 1.4797 + } 1.4798 + } 1.4799 + } 1.4800 + 1.4801 + ResponseValue response; 1.4802 + if (NS_FAILED(aResultCode)) { 1.4803 + response = aResultCode; 1.4804 + } 1.4805 + else { 1.4806 + response = getAllResponse; 1.4807 + } 1.4808 + 1.4809 + if (!actor->SendResponse(response)) { 1.4810 + return Error; 1.4811 + } 1.4812 + 1.4813 + return Success_Sent; 1.4814 +} 1.4815 + 1.4816 +nsresult 1.4817 +GetAllHelper::UnpackResponseFromParentProcess( 1.4818 + const ResponseValue& aResponseValue) 1.4819 +{ 1.4820 + NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse, 1.4821 + "Bad response type!"); 1.4822 + 1.4823 + const GetAllResponse& getAllResponse = aResponseValue.get_GetAllResponse(); 1.4824 + const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos = 1.4825 + getAllResponse.cloneInfos(); 1.4826 + const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs(); 1.4827 + 1.4828 + mCloneReadInfos.SetCapacity(cloneInfos.Length()); 1.4829 + 1.4830 + for (uint32_t index = 0; index < cloneInfos.Length(); index++) { 1.4831 + const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index]; 1.4832 + const InfallibleTArray<PBlobChild*>& blobs = blobArrays[index].blobsChild(); 1.4833 + 1.4834 + StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement(); 1.4835 + if (!destInfo->SetFromSerialized(srcInfo)) { 1.4836 + IDB_WARNING("Failed to copy clone buffer!"); 1.4837 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.4838 + } 1.4839 + 1.4840 + IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles); 1.4841 + } 1.4842 + 1.4843 + return NS_OK; 1.4844 +} 1.4845 + 1.4846 +nsresult 1.4847 +GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) 1.4848 +{ 1.4849 + MOZ_ASSERT(!NS_IsMainThread()); 1.4850 + MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess()); 1.4851 + 1.4852 + PROFILER_LABEL("IndexedDB", 1.4853 + "GetAllKeysHelper::DoDatabaseWork [IDObjectStore.cpp]"); 1.4854 + 1.4855 + NS_NAMED_LITERAL_CSTRING(keyValue, "key_value"); 1.4856 + 1.4857 + nsAutoCString keyRangeClause; 1.4858 + if (mKeyRange) { 1.4859 + mKeyRange->GetBindingClause(keyValue, keyRangeClause); 1.4860 + } 1.4861 + 1.4862 + nsAutoCString limitClause; 1.4863 + if (mLimit != UINT32_MAX) { 1.4864 + limitClause = NS_LITERAL_CSTRING(" LIMIT "); 1.4865 + limitClause.AppendInt(mLimit); 1.4866 + } 1.4867 + 1.4868 + NS_NAMED_LITERAL_CSTRING(osid, "osid"); 1.4869 + 1.4870 + nsCString query = NS_LITERAL_CSTRING("SELECT ") + keyValue + 1.4871 + NS_LITERAL_CSTRING(" FROM object_data WHERE " 1.4872 + "object_store_id = :") + 1.4873 + osid + keyRangeClause + 1.4874 + NS_LITERAL_CSTRING(" ORDER BY key_value ASC") + 1.4875 + limitClause; 1.4876 + 1.4877 + nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); 1.4878 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4879 + 1.4880 + mozStorageStatementScoper scoper(stmt); 1.4881 + 1.4882 + nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id()); 1.4883 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4884 + 1.4885 + if (mKeyRange) { 1.4886 + rv = mKeyRange->BindToStatement(stmt); 1.4887 + NS_ENSURE_SUCCESS(rv, rv); 1.4888 + } 1.4889 + 1.4890 + mKeys.SetCapacity(std::min<uint32_t>(50, mLimit)); 1.4891 + 1.4892 + bool hasResult; 1.4893 + while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) { 1.4894 + if (mKeys.Capacity() == mKeys.Length()) { 1.4895 + mKeys.SetCapacity(mKeys.Capacity() * 2); 1.4896 + } 1.4897 + 1.4898 + Key* key = mKeys.AppendElement(); 1.4899 + NS_ASSERTION(key, "This shouldn't fail!"); 1.4900 + 1.4901 + rv = key->SetFromStatement(stmt, 0); 1.4902 + NS_ENSURE_SUCCESS(rv, rv); 1.4903 + } 1.4904 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.4905 + 1.4906 + return NS_OK; 1.4907 +} 1.4908 + 1.4909 +nsresult 1.4910 +GetAllKeysHelper::GetSuccessResult(JSContext* aCx, 1.4911 + JS::MutableHandle<JS::Value> aVal) 1.4912 +{ 1.4913 + MOZ_ASSERT(NS_IsMainThread()); 1.4914 + MOZ_ASSERT(mKeys.Length() <= mLimit); 1.4915 + 1.4916 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.4917 + "GetAllKeysHelper::GetSuccessResult " 1.4918 + "[IDBObjectStore.cpp]"); 1.4919 + 1.4920 + nsTArray<Key> keys; 1.4921 + mKeys.SwapElements(keys); 1.4922 + 1.4923 + JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0)); 1.4924 + if (!array) { 1.4925 + IDB_WARNING("Failed to make array!"); 1.4926 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.4927 + } 1.4928 + 1.4929 + if (!keys.IsEmpty()) { 1.4930 + if (!JS_SetArrayLength(aCx, array, keys.Length())) { 1.4931 + IDB_WARNING("Failed to set array length!"); 1.4932 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.4933 + } 1.4934 + 1.4935 + for (uint32_t index = 0, count = keys.Length(); index < count; index++) { 1.4936 + const Key& key = keys[index]; 1.4937 + MOZ_ASSERT(!key.IsUnset()); 1.4938 + 1.4939 + JS::Rooted<JS::Value> value(aCx); 1.4940 + nsresult rv = key.ToJSVal(aCx, &value); 1.4941 + if (NS_FAILED(rv)) { 1.4942 + NS_WARNING("Failed to get jsval for key!"); 1.4943 + return rv; 1.4944 + } 1.4945 + 1.4946 + if (!JS_SetElement(aCx, array, index, value)) { 1.4947 + IDB_WARNING("Failed to set array element!"); 1.4948 + return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; 1.4949 + } 1.4950 + } 1.4951 + } 1.4952 + 1.4953 + aVal.setObject(*array); 1.4954 + return NS_OK; 1.4955 +} 1.4956 + 1.4957 +void 1.4958 +GetAllKeysHelper::ReleaseMainThreadObjects() 1.4959 +{ 1.4960 + MOZ_ASSERT(NS_IsMainThread()); 1.4961 + 1.4962 + mKeyRange = nullptr; 1.4963 + 1.4964 + ObjectStoreHelper::ReleaseMainThreadObjects(); 1.4965 +} 1.4966 + 1.4967 +nsresult 1.4968 +GetAllKeysHelper::PackArgumentsForParentProcess( 1.4969 + ObjectStoreRequestParams& aParams) 1.4970 +{ 1.4971 + MOZ_ASSERT(NS_IsMainThread()); 1.4972 + MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess()); 1.4973 + 1.4974 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.4975 + "GetAllKeysHelper::PackArgumentsForParentProcess " 1.4976 + "[IDBObjectStore.cpp]"); 1.4977 + 1.4978 + GetAllKeysParams params; 1.4979 + 1.4980 + if (mKeyRange) { 1.4981 + KeyRange keyRange; 1.4982 + mKeyRange->ToSerializedKeyRange(keyRange); 1.4983 + params.optionalKeyRange() = keyRange; 1.4984 + } else { 1.4985 + params.optionalKeyRange() = mozilla::void_t(); 1.4986 + } 1.4987 + 1.4988 + params.limit() = mLimit; 1.4989 + 1.4990 + aParams = params; 1.4991 + return NS_OK; 1.4992 +} 1.4993 + 1.4994 +AsyncConnectionHelper::ChildProcessSendResult 1.4995 +GetAllKeysHelper::SendResponseToChildProcess(nsresult aResultCode) 1.4996 +{ 1.4997 + MOZ_ASSERT(NS_IsMainThread()); 1.4998 + MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess()); 1.4999 + 1.5000 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.5001 + "GetAllKeysHelper::SendResponseToChildProcess " 1.5002 + "[IDBObjectStore.cpp]"); 1.5003 + 1.5004 + IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); 1.5005 + MOZ_ASSERT(actor); 1.5006 + 1.5007 + ResponseValue response; 1.5008 + if (NS_FAILED(aResultCode)) { 1.5009 + response = aResultCode; 1.5010 + } 1.5011 + else { 1.5012 + GetAllKeysResponse getAllKeysResponse; 1.5013 + getAllKeysResponse.keys().AppendElements(mKeys); 1.5014 + response = getAllKeysResponse; 1.5015 + } 1.5016 + 1.5017 + if (!actor->SendResponse(response)) { 1.5018 + return Error; 1.5019 + } 1.5020 + 1.5021 + return Success_Sent; 1.5022 +} 1.5023 + 1.5024 +nsresult 1.5025 +GetAllKeysHelper::UnpackResponseFromParentProcess( 1.5026 + const ResponseValue& aResponseValue) 1.5027 +{ 1.5028 + MOZ_ASSERT(NS_IsMainThread()); 1.5029 + MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess()); 1.5030 + MOZ_ASSERT(aResponseValue.type() == ResponseValue::TGetAllKeysResponse); 1.5031 + 1.5032 + mKeys.AppendElements(aResponseValue.get_GetAllKeysResponse().keys()); 1.5033 + return NS_OK; 1.5034 +} 1.5035 + 1.5036 +nsresult 1.5037 +CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection) 1.5038 +{ 1.5039 + NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); 1.5040 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.5041 + 1.5042 + PROFILER_LABEL("IndexedDB", 1.5043 + "CountHelper::DoDatabaseWork [IDBObjectStore.cpp]"); 1.5044 + 1.5045 + NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key"); 1.5046 + NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key"); 1.5047 + 1.5048 + nsAutoCString keyRangeClause; 1.5049 + if (mKeyRange) { 1.5050 + if (!mKeyRange->Lower().IsUnset()) { 1.5051 + keyRangeClause = NS_LITERAL_CSTRING(" AND key_value"); 1.5052 + if (mKeyRange->IsLowerOpen()) { 1.5053 + keyRangeClause.AppendLiteral(" > :"); 1.5054 + } 1.5055 + else { 1.5056 + keyRangeClause.AppendLiteral(" >= :"); 1.5057 + } 1.5058 + keyRangeClause.Append(lowerKeyName); 1.5059 + } 1.5060 + 1.5061 + if (!mKeyRange->Upper().IsUnset()) { 1.5062 + keyRangeClause += NS_LITERAL_CSTRING(" AND key_value"); 1.5063 + if (mKeyRange->IsUpperOpen()) { 1.5064 + keyRangeClause.AppendLiteral(" < :"); 1.5065 + } 1.5066 + else { 1.5067 + keyRangeClause.AppendLiteral(" <= :"); 1.5068 + } 1.5069 + keyRangeClause.Append(upperKeyName); 1.5070 + } 1.5071 + } 1.5072 + 1.5073 + nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM object_data " 1.5074 + "WHERE object_store_id = :osid") + 1.5075 + keyRangeClause; 1.5076 + 1.5077 + nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); 1.5078 + IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.5079 + 1.5080 + mozStorageStatementScoper scoper(stmt); 1.5081 + 1.5082 + nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), 1.5083 + mObjectStore->Id()); 1.5084 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.5085 + 1.5086 + if (mKeyRange) { 1.5087 + if (!mKeyRange->Lower().IsUnset()) { 1.5088 + rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName); 1.5089 + NS_ENSURE_SUCCESS(rv, rv); 1.5090 + } 1.5091 + if (!mKeyRange->Upper().IsUnset()) { 1.5092 + rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName); 1.5093 + NS_ENSURE_SUCCESS(rv, rv); 1.5094 + } 1.5095 + } 1.5096 + 1.5097 + bool hasResult; 1.5098 + rv = stmt->ExecuteStep(&hasResult); 1.5099 + IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.5100 + IDB_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); 1.5101 + 1.5102 + mCount = stmt->AsInt64(0); 1.5103 + return NS_OK; 1.5104 +} 1.5105 + 1.5106 +nsresult 1.5107 +CountHelper::GetSuccessResult(JSContext* aCx, 1.5108 + JS::MutableHandle<JS::Value> aVal) 1.5109 +{ 1.5110 + aVal.setNumber(static_cast<double>(mCount)); 1.5111 + return NS_OK; 1.5112 +} 1.5113 + 1.5114 +void 1.5115 +CountHelper::ReleaseMainThreadObjects() 1.5116 +{ 1.5117 + mKeyRange = nullptr; 1.5118 + ObjectStoreHelper::ReleaseMainThreadObjects(); 1.5119 +} 1.5120 + 1.5121 +nsresult 1.5122 +CountHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) 1.5123 +{ 1.5124 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.5125 + NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.5126 + 1.5127 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.5128 + "CountHelper::PackArgumentsForParentProcess " 1.5129 + "[IDBObjectStore.cpp]"); 1.5130 + 1.5131 + CountParams params; 1.5132 + 1.5133 + if (mKeyRange) { 1.5134 + KeyRange keyRange; 1.5135 + mKeyRange->ToSerializedKeyRange(keyRange); 1.5136 + params.optionalKeyRange() = keyRange; 1.5137 + } 1.5138 + else { 1.5139 + params.optionalKeyRange() = mozilla::void_t(); 1.5140 + } 1.5141 + 1.5142 + aParams = params; 1.5143 + return NS_OK; 1.5144 +} 1.5145 + 1.5146 +AsyncConnectionHelper::ChildProcessSendResult 1.5147 +CountHelper::SendResponseToChildProcess(nsresult aResultCode) 1.5148 +{ 1.5149 + NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); 1.5150 + NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); 1.5151 + 1.5152 + PROFILER_MAIN_THREAD_LABEL("IndexedDB", 1.5153 + "CountHelper::SendResponseToChildProcess " 1.5154 + "[IDBObjectStore.cpp]"); 1.5155 + 1.5156 + IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); 1.5157 + NS_ASSERTION(actor, "How did we get this far without an actor?"); 1.5158 + 1.5159 + ResponseValue response; 1.5160 + if (NS_FAILED(aResultCode)) { 1.5161 + response = aResultCode; 1.5162 + } 1.5163 + else { 1.5164 + CountResponse countResponse = mCount; 1.5165 + response = countResponse; 1.5166 + } 1.5167 + 1.5168 + if (!actor->SendResponse(response)) { 1.5169 + return Error; 1.5170 + } 1.5171 + 1.5172 + return Success_Sent; 1.5173 +} 1.5174 + 1.5175 +nsresult 1.5176 +CountHelper::UnpackResponseFromParentProcess( 1.5177 + const ResponseValue& aResponseValue) 1.5178 +{ 1.5179 + NS_ASSERTION(aResponseValue.type() == ResponseValue::TCountResponse, 1.5180 + "Bad response type!"); 1.5181 + 1.5182 + mCount = aResponseValue.get_CountResponse().count(); 1.5183 + return NS_OK; 1.5184 +}