Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
michael@0 | 1 | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
michael@0 | 2 | /* vim: set ts=2 et sw=2 tw=80: */ |
michael@0 | 3 | /* This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 4 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 5 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 6 | |
michael@0 | 7 | #include "base/basictypes.h" |
michael@0 | 8 | |
michael@0 | 9 | #include "IDBObjectStore.h" |
michael@0 | 10 | |
michael@0 | 11 | #include "mozilla/dom/ipc/nsIRemoteBlob.h" |
michael@0 | 12 | #include "nsIOutputStream.h" |
michael@0 | 13 | |
michael@0 | 14 | #include <algorithm> |
michael@0 | 15 | #include "jsfriendapi.h" |
michael@0 | 16 | #include "mozilla/dom/ContentChild.h" |
michael@0 | 17 | #include "mozilla/dom/ContentParent.h" |
michael@0 | 18 | #include "mozilla/dom/FileHandleBinding.h" |
michael@0 | 19 | #include "mozilla/dom/StructuredCloneTags.h" |
michael@0 | 20 | #include "mozilla/dom/ipc/Blob.h" |
michael@0 | 21 | #include "mozilla/dom/quota/FileStreams.h" |
michael@0 | 22 | #include "mozilla/Endian.h" |
michael@0 | 23 | #include "mozilla/storage.h" |
michael@0 | 24 | #include "nsContentUtils.h" |
michael@0 | 25 | #include "nsDOMClassInfo.h" |
michael@0 | 26 | #include "nsDOMFile.h" |
michael@0 | 27 | #include "mozilla/dom/DOMStringList.h" |
michael@0 | 28 | #include "nsJSUtils.h" |
michael@0 | 29 | #include "nsServiceManagerUtils.h" |
michael@0 | 30 | #include "nsThreadUtils.h" |
michael@0 | 31 | #include "snappy/snappy.h" |
michael@0 | 32 | |
michael@0 | 33 | #include "AsyncConnectionHelper.h" |
michael@0 | 34 | #include "IDBCursor.h" |
michael@0 | 35 | #include "IDBEvents.h" |
michael@0 | 36 | #include "IDBFileHandle.h" |
michael@0 | 37 | #include "IDBIndex.h" |
michael@0 | 38 | #include "IDBKeyRange.h" |
michael@0 | 39 | #include "IDBTransaction.h" |
michael@0 | 40 | #include "DatabaseInfo.h" |
michael@0 | 41 | #include "KeyPath.h" |
michael@0 | 42 | #include "ProfilerHelpers.h" |
michael@0 | 43 | #include "ReportInternalError.h" |
michael@0 | 44 | |
michael@0 | 45 | #include "ipc/IndexedDBChild.h" |
michael@0 | 46 | #include "ipc/IndexedDBParent.h" |
michael@0 | 47 | |
michael@0 | 48 | #include "IndexedDatabaseInlines.h" |
michael@0 | 49 | #include "nsCharSeparatedTokenizer.h" |
michael@0 | 50 | |
michael@0 | 51 | #define FILE_COPY_BUFFER_SIZE 32768 |
michael@0 | 52 | |
michael@0 | 53 | USING_INDEXEDDB_NAMESPACE |
michael@0 | 54 | using namespace mozilla::dom; |
michael@0 | 55 | using namespace mozilla::dom::indexedDB::ipc; |
michael@0 | 56 | using mozilla::dom::quota::FileOutputStream; |
michael@0 | 57 | using mozilla::ErrorResult; |
michael@0 | 58 | using mozilla::fallible_t; |
michael@0 | 59 | using mozilla::LittleEndian; |
michael@0 | 60 | using mozilla::Move; |
michael@0 | 61 | using mozilla::NativeEndian; |
michael@0 | 62 | |
michael@0 | 63 | BEGIN_INDEXEDDB_NAMESPACE |
michael@0 | 64 | |
michael@0 | 65 | struct FileHandleData |
michael@0 | 66 | { |
michael@0 | 67 | nsString type; |
michael@0 | 68 | nsString name; |
michael@0 | 69 | }; |
michael@0 | 70 | |
michael@0 | 71 | struct BlobOrFileData |
michael@0 | 72 | { |
michael@0 | 73 | BlobOrFileData() |
michael@0 | 74 | : tag(0), size(0), lastModifiedDate(UINT64_MAX) |
michael@0 | 75 | { } |
michael@0 | 76 | |
michael@0 | 77 | uint32_t tag; |
michael@0 | 78 | uint64_t size; |
michael@0 | 79 | nsString type; |
michael@0 | 80 | nsString name; |
michael@0 | 81 | uint64_t lastModifiedDate; |
michael@0 | 82 | }; |
michael@0 | 83 | |
michael@0 | 84 | END_INDEXEDDB_NAMESPACE |
michael@0 | 85 | |
michael@0 | 86 | namespace { |
michael@0 | 87 | |
michael@0 | 88 | inline |
michael@0 | 89 | bool |
michael@0 | 90 | IgnoreNothing(char16_t c) |
michael@0 | 91 | { |
michael@0 | 92 | return false; |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | class ObjectStoreHelper : public AsyncConnectionHelper |
michael@0 | 96 | { |
michael@0 | 97 | public: |
michael@0 | 98 | ObjectStoreHelper(IDBTransaction* aTransaction, |
michael@0 | 99 | IDBRequest* aRequest, |
michael@0 | 100 | IDBObjectStore* aObjectStore) |
michael@0 | 101 | : AsyncConnectionHelper(aTransaction, aRequest), mObjectStore(aObjectStore), |
michael@0 | 102 | mActor(nullptr) |
michael@0 | 103 | { |
michael@0 | 104 | NS_ASSERTION(aTransaction, "Null transaction!"); |
michael@0 | 105 | NS_ASSERTION(aRequest, "Null request!"); |
michael@0 | 106 | NS_ASSERTION(aObjectStore, "Null object store!"); |
michael@0 | 107 | } |
michael@0 | 108 | |
michael@0 | 109 | virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; |
michael@0 | 110 | |
michael@0 | 111 | virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread) MOZ_OVERRIDE; |
michael@0 | 112 | |
michael@0 | 113 | virtual nsresult |
michael@0 | 114 | PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) = 0; |
michael@0 | 115 | |
michael@0 | 116 | virtual nsresult |
michael@0 | 117 | UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0; |
michael@0 | 118 | |
michael@0 | 119 | protected: |
michael@0 | 120 | nsRefPtr<IDBObjectStore> mObjectStore; |
michael@0 | 121 | |
michael@0 | 122 | private: |
michael@0 | 123 | IndexedDBObjectStoreRequestChild* mActor; |
michael@0 | 124 | }; |
michael@0 | 125 | |
michael@0 | 126 | class NoRequestObjectStoreHelper : public AsyncConnectionHelper |
michael@0 | 127 | { |
michael@0 | 128 | public: |
michael@0 | 129 | NoRequestObjectStoreHelper(IDBTransaction* aTransaction, |
michael@0 | 130 | IDBObjectStore* aObjectStore) |
michael@0 | 131 | : AsyncConnectionHelper(aTransaction, nullptr), mObjectStore(aObjectStore) |
michael@0 | 132 | { |
michael@0 | 133 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 134 | NS_ASSERTION(aTransaction, "Null transaction!"); |
michael@0 | 135 | NS_ASSERTION(aObjectStore, "Null object store!"); |
michael@0 | 136 | } |
michael@0 | 137 | |
michael@0 | 138 | virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; |
michael@0 | 139 | |
michael@0 | 140 | virtual nsresult UnpackResponseFromParentProcess( |
michael@0 | 141 | const ResponseValue& aResponseValue) |
michael@0 | 142 | MOZ_OVERRIDE; |
michael@0 | 143 | |
michael@0 | 144 | virtual ChildProcessSendResult |
michael@0 | 145 | SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; |
michael@0 | 146 | |
michael@0 | 147 | virtual nsresult OnSuccess() MOZ_OVERRIDE; |
michael@0 | 148 | |
michael@0 | 149 | virtual void OnError() MOZ_OVERRIDE; |
michael@0 | 150 | |
michael@0 | 151 | protected: |
michael@0 | 152 | nsRefPtr<IDBObjectStore> mObjectStore; |
michael@0 | 153 | }; |
michael@0 | 154 | |
michael@0 | 155 | class AddHelper : public ObjectStoreHelper |
michael@0 | 156 | { |
michael@0 | 157 | public: |
michael@0 | 158 | AddHelper(IDBTransaction* aTransaction, |
michael@0 | 159 | IDBRequest* aRequest, |
michael@0 | 160 | IDBObjectStore* aObjectStore, |
michael@0 | 161 | StructuredCloneWriteInfo&& aCloneWriteInfo, |
michael@0 | 162 | const Key& aKey, |
michael@0 | 163 | bool aOverwrite, |
michael@0 | 164 | nsTArray<IndexUpdateInfo>& aIndexUpdateInfo) |
michael@0 | 165 | : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), |
michael@0 | 166 | mCloneWriteInfo(Move(aCloneWriteInfo)), |
michael@0 | 167 | mKey(aKey), |
michael@0 | 168 | mOverwrite(aOverwrite) |
michael@0 | 169 | { |
michael@0 | 170 | mIndexUpdateInfo.SwapElements(aIndexUpdateInfo); |
michael@0 | 171 | } |
michael@0 | 172 | |
michael@0 | 173 | ~AddHelper() |
michael@0 | 174 | { |
michael@0 | 175 | IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo); |
michael@0 | 176 | } |
michael@0 | 177 | |
michael@0 | 178 | virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 179 | MOZ_OVERRIDE; |
michael@0 | 180 | |
michael@0 | 181 | virtual nsresult GetSuccessResult(JSContext* aCx, |
michael@0 | 182 | JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; |
michael@0 | 183 | |
michael@0 | 184 | virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; |
michael@0 | 185 | |
michael@0 | 186 | virtual nsresult |
michael@0 | 187 | PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; |
michael@0 | 188 | |
michael@0 | 189 | virtual ChildProcessSendResult |
michael@0 | 190 | SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; |
michael@0 | 191 | |
michael@0 | 192 | virtual nsresult |
michael@0 | 193 | UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 194 | MOZ_OVERRIDE; |
michael@0 | 195 | |
michael@0 | 196 | private: |
michael@0 | 197 | // These may change in the autoincrement case. |
michael@0 | 198 | StructuredCloneWriteInfo mCloneWriteInfo; |
michael@0 | 199 | Key mKey; |
michael@0 | 200 | nsTArray<IndexUpdateInfo> mIndexUpdateInfo; |
michael@0 | 201 | const bool mOverwrite; |
michael@0 | 202 | }; |
michael@0 | 203 | |
michael@0 | 204 | class GetHelper : public ObjectStoreHelper |
michael@0 | 205 | { |
michael@0 | 206 | public: |
michael@0 | 207 | GetHelper(IDBTransaction* aTransaction, |
michael@0 | 208 | IDBRequest* aRequest, |
michael@0 | 209 | IDBObjectStore* aObjectStore, |
michael@0 | 210 | IDBKeyRange* aKeyRange) |
michael@0 | 211 | : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), |
michael@0 | 212 | mKeyRange(aKeyRange) |
michael@0 | 213 | { |
michael@0 | 214 | NS_ASSERTION(aKeyRange, "Null key range!"); |
michael@0 | 215 | } |
michael@0 | 216 | |
michael@0 | 217 | ~GetHelper() |
michael@0 | 218 | { |
michael@0 | 219 | IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo); |
michael@0 | 220 | } |
michael@0 | 221 | |
michael@0 | 222 | virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 223 | MOZ_OVERRIDE; |
michael@0 | 224 | |
michael@0 | 225 | virtual nsresult GetSuccessResult(JSContext* aCx, |
michael@0 | 226 | JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; |
michael@0 | 227 | |
michael@0 | 228 | virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; |
michael@0 | 229 | |
michael@0 | 230 | virtual nsresult |
michael@0 | 231 | PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; |
michael@0 | 232 | |
michael@0 | 233 | virtual ChildProcessSendResult |
michael@0 | 234 | SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; |
michael@0 | 235 | |
michael@0 | 236 | virtual nsresult |
michael@0 | 237 | UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 238 | MOZ_OVERRIDE; |
michael@0 | 239 | |
michael@0 | 240 | protected: |
michael@0 | 241 | // In-params. |
michael@0 | 242 | nsRefPtr<IDBKeyRange> mKeyRange; |
michael@0 | 243 | |
michael@0 | 244 | private: |
michael@0 | 245 | // Out-params. |
michael@0 | 246 | StructuredCloneReadInfo mCloneReadInfo; |
michael@0 | 247 | }; |
michael@0 | 248 | |
michael@0 | 249 | class DeleteHelper : public GetHelper |
michael@0 | 250 | { |
michael@0 | 251 | public: |
michael@0 | 252 | DeleteHelper(IDBTransaction* aTransaction, |
michael@0 | 253 | IDBRequest* aRequest, |
michael@0 | 254 | IDBObjectStore* aObjectStore, |
michael@0 | 255 | IDBKeyRange* aKeyRange) |
michael@0 | 256 | : GetHelper(aTransaction, aRequest, aObjectStore, aKeyRange) |
michael@0 | 257 | { } |
michael@0 | 258 | |
michael@0 | 259 | virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 260 | MOZ_OVERRIDE; |
michael@0 | 261 | |
michael@0 | 262 | virtual nsresult GetSuccessResult(JSContext* aCx, |
michael@0 | 263 | JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; |
michael@0 | 264 | |
michael@0 | 265 | virtual nsresult |
michael@0 | 266 | PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; |
michael@0 | 267 | |
michael@0 | 268 | virtual ChildProcessSendResult |
michael@0 | 269 | SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; |
michael@0 | 270 | |
michael@0 | 271 | virtual nsresult |
michael@0 | 272 | UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 273 | MOZ_OVERRIDE; |
michael@0 | 274 | }; |
michael@0 | 275 | |
michael@0 | 276 | class ClearHelper : public ObjectStoreHelper |
michael@0 | 277 | { |
michael@0 | 278 | public: |
michael@0 | 279 | ClearHelper(IDBTransaction* aTransaction, |
michael@0 | 280 | IDBRequest* aRequest, |
michael@0 | 281 | IDBObjectStore* aObjectStore) |
michael@0 | 282 | : ObjectStoreHelper(aTransaction, aRequest, aObjectStore) |
michael@0 | 283 | { } |
michael@0 | 284 | |
michael@0 | 285 | virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 286 | MOZ_OVERRIDE; |
michael@0 | 287 | |
michael@0 | 288 | virtual nsresult |
michael@0 | 289 | PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; |
michael@0 | 290 | |
michael@0 | 291 | virtual ChildProcessSendResult |
michael@0 | 292 | SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; |
michael@0 | 293 | |
michael@0 | 294 | virtual nsresult |
michael@0 | 295 | UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 296 | MOZ_OVERRIDE; |
michael@0 | 297 | }; |
michael@0 | 298 | |
michael@0 | 299 | class OpenCursorHelper : public ObjectStoreHelper |
michael@0 | 300 | { |
michael@0 | 301 | public: |
michael@0 | 302 | OpenCursorHelper(IDBTransaction* aTransaction, |
michael@0 | 303 | IDBRequest* aRequest, |
michael@0 | 304 | IDBObjectStore* aObjectStore, |
michael@0 | 305 | IDBKeyRange* aKeyRange, |
michael@0 | 306 | IDBCursor::Direction aDirection) |
michael@0 | 307 | : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), |
michael@0 | 308 | mKeyRange(aKeyRange), mDirection(aDirection) |
michael@0 | 309 | { } |
michael@0 | 310 | |
michael@0 | 311 | ~OpenCursorHelper() |
michael@0 | 312 | { |
michael@0 | 313 | IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo); |
michael@0 | 314 | } |
michael@0 | 315 | |
michael@0 | 316 | virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 317 | MOZ_OVERRIDE; |
michael@0 | 318 | |
michael@0 | 319 | virtual nsresult GetSuccessResult(JSContext* aCx, |
michael@0 | 320 | JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; |
michael@0 | 321 | |
michael@0 | 322 | virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; |
michael@0 | 323 | |
michael@0 | 324 | virtual nsresult |
michael@0 | 325 | PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; |
michael@0 | 326 | |
michael@0 | 327 | virtual ChildProcessSendResult |
michael@0 | 328 | SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; |
michael@0 | 329 | |
michael@0 | 330 | virtual nsresult |
michael@0 | 331 | UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 332 | MOZ_OVERRIDE; |
michael@0 | 333 | |
michael@0 | 334 | private: |
michael@0 | 335 | nsresult EnsureCursor(); |
michael@0 | 336 | |
michael@0 | 337 | // In-params. |
michael@0 | 338 | nsRefPtr<IDBKeyRange> mKeyRange; |
michael@0 | 339 | const IDBCursor::Direction mDirection; |
michael@0 | 340 | |
michael@0 | 341 | // Out-params. |
michael@0 | 342 | Key mKey; |
michael@0 | 343 | StructuredCloneReadInfo mCloneReadInfo; |
michael@0 | 344 | nsCString mContinueQuery; |
michael@0 | 345 | nsCString mContinueToQuery; |
michael@0 | 346 | Key mRangeKey; |
michael@0 | 347 | |
michael@0 | 348 | // Only used in the parent process. |
michael@0 | 349 | nsRefPtr<IDBCursor> mCursor; |
michael@0 | 350 | SerializedStructuredCloneReadInfo mSerializedCloneReadInfo; |
michael@0 | 351 | }; |
michael@0 | 352 | |
michael@0 | 353 | class OpenKeyCursorHelper MOZ_FINAL : public ObjectStoreHelper |
michael@0 | 354 | { |
michael@0 | 355 | public: |
michael@0 | 356 | OpenKeyCursorHelper(IDBTransaction* aTransaction, |
michael@0 | 357 | IDBRequest* aRequest, |
michael@0 | 358 | IDBObjectStore* aObjectStore, |
michael@0 | 359 | IDBKeyRange* aKeyRange, |
michael@0 | 360 | IDBCursor::Direction aDirection) |
michael@0 | 361 | : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), |
michael@0 | 362 | mKeyRange(aKeyRange), mDirection(aDirection) |
michael@0 | 363 | { } |
michael@0 | 364 | |
michael@0 | 365 | virtual nsresult |
michael@0 | 366 | DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE; |
michael@0 | 367 | |
michael@0 | 368 | virtual nsresult |
michael@0 | 369 | GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) |
michael@0 | 370 | MOZ_OVERRIDE; |
michael@0 | 371 | |
michael@0 | 372 | virtual void |
michael@0 | 373 | ReleaseMainThreadObjects() MOZ_OVERRIDE; |
michael@0 | 374 | |
michael@0 | 375 | virtual nsresult |
michael@0 | 376 | PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; |
michael@0 | 377 | |
michael@0 | 378 | virtual ChildProcessSendResult |
michael@0 | 379 | SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; |
michael@0 | 380 | |
michael@0 | 381 | virtual nsresult |
michael@0 | 382 | UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 383 | MOZ_OVERRIDE; |
michael@0 | 384 | |
michael@0 | 385 | private: |
michael@0 | 386 | ~OpenKeyCursorHelper() |
michael@0 | 387 | { } |
michael@0 | 388 | |
michael@0 | 389 | nsresult EnsureCursor(); |
michael@0 | 390 | |
michael@0 | 391 | // In-params. |
michael@0 | 392 | nsRefPtr<IDBKeyRange> mKeyRange; |
michael@0 | 393 | const IDBCursor::Direction mDirection; |
michael@0 | 394 | |
michael@0 | 395 | // Out-params. |
michael@0 | 396 | Key mKey; |
michael@0 | 397 | nsCString mContinueQuery; |
michael@0 | 398 | nsCString mContinueToQuery; |
michael@0 | 399 | Key mRangeKey; |
michael@0 | 400 | |
michael@0 | 401 | // Only used in the parent process. |
michael@0 | 402 | nsRefPtr<IDBCursor> mCursor; |
michael@0 | 403 | }; |
michael@0 | 404 | |
michael@0 | 405 | class CreateIndexHelper : public NoRequestObjectStoreHelper |
michael@0 | 406 | { |
michael@0 | 407 | public: |
michael@0 | 408 | CreateIndexHelper(IDBTransaction* aTransaction, IDBIndex* aIndex) |
michael@0 | 409 | : NoRequestObjectStoreHelper(aTransaction, aIndex->ObjectStore()), |
michael@0 | 410 | mIndex(aIndex) |
michael@0 | 411 | { |
michael@0 | 412 | if (sTLSIndex == BAD_TLS_INDEX) { |
michael@0 | 413 | PR_NewThreadPrivateIndex(&sTLSIndex, DestroyTLSEntry); |
michael@0 | 414 | } |
michael@0 | 415 | |
michael@0 | 416 | NS_ASSERTION(sTLSIndex != BAD_TLS_INDEX, |
michael@0 | 417 | "PR_NewThreadPrivateIndex failed!"); |
michael@0 | 418 | } |
michael@0 | 419 | |
michael@0 | 420 | virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 421 | MOZ_OVERRIDE; |
michael@0 | 422 | |
michael@0 | 423 | virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; |
michael@0 | 424 | |
michael@0 | 425 | private: |
michael@0 | 426 | nsresult InsertDataFromObjectStore(mozIStorageConnection* aConnection); |
michael@0 | 427 | |
michael@0 | 428 | static void DestroyTLSEntry(void* aPtr); |
michael@0 | 429 | |
michael@0 | 430 | static unsigned sTLSIndex; |
michael@0 | 431 | |
michael@0 | 432 | // In-params. |
michael@0 | 433 | nsRefPtr<IDBIndex> mIndex; |
michael@0 | 434 | }; |
michael@0 | 435 | |
michael@0 | 436 | unsigned CreateIndexHelper::sTLSIndex = unsigned(BAD_TLS_INDEX); |
michael@0 | 437 | |
michael@0 | 438 | class DeleteIndexHelper : public NoRequestObjectStoreHelper |
michael@0 | 439 | { |
michael@0 | 440 | public: |
michael@0 | 441 | DeleteIndexHelper(IDBTransaction* aTransaction, |
michael@0 | 442 | IDBObjectStore* aObjectStore, |
michael@0 | 443 | const nsAString& aName) |
michael@0 | 444 | : NoRequestObjectStoreHelper(aTransaction, aObjectStore), mName(aName) |
michael@0 | 445 | { } |
michael@0 | 446 | |
michael@0 | 447 | virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 448 | MOZ_OVERRIDE; |
michael@0 | 449 | |
michael@0 | 450 | private: |
michael@0 | 451 | // In-params |
michael@0 | 452 | nsString mName; |
michael@0 | 453 | }; |
michael@0 | 454 | |
michael@0 | 455 | class GetAllHelper : public ObjectStoreHelper |
michael@0 | 456 | { |
michael@0 | 457 | public: |
michael@0 | 458 | GetAllHelper(IDBTransaction* aTransaction, |
michael@0 | 459 | IDBRequest* aRequest, |
michael@0 | 460 | IDBObjectStore* aObjectStore, |
michael@0 | 461 | IDBKeyRange* aKeyRange, |
michael@0 | 462 | const uint32_t aLimit) |
michael@0 | 463 | : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), |
michael@0 | 464 | mKeyRange(aKeyRange), mLimit(aLimit) |
michael@0 | 465 | { } |
michael@0 | 466 | |
michael@0 | 467 | ~GetAllHelper() |
michael@0 | 468 | { |
michael@0 | 469 | for (uint32_t index = 0; index < mCloneReadInfos.Length(); index++) { |
michael@0 | 470 | IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos[index]); |
michael@0 | 471 | } |
michael@0 | 472 | } |
michael@0 | 473 | |
michael@0 | 474 | virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 475 | MOZ_OVERRIDE; |
michael@0 | 476 | |
michael@0 | 477 | virtual nsresult GetSuccessResult(JSContext* aCx, |
michael@0 | 478 | JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; |
michael@0 | 479 | |
michael@0 | 480 | virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; |
michael@0 | 481 | |
michael@0 | 482 | virtual nsresult |
michael@0 | 483 | PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; |
michael@0 | 484 | |
michael@0 | 485 | virtual ChildProcessSendResult |
michael@0 | 486 | SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; |
michael@0 | 487 | |
michael@0 | 488 | virtual nsresult |
michael@0 | 489 | UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 490 | MOZ_OVERRIDE; |
michael@0 | 491 | |
michael@0 | 492 | protected: |
michael@0 | 493 | // In-params. |
michael@0 | 494 | nsRefPtr<IDBKeyRange> mKeyRange; |
michael@0 | 495 | const uint32_t mLimit; |
michael@0 | 496 | |
michael@0 | 497 | private: |
michael@0 | 498 | // Out-params. |
michael@0 | 499 | nsTArray<StructuredCloneReadInfo> mCloneReadInfos; |
michael@0 | 500 | }; |
michael@0 | 501 | |
michael@0 | 502 | class GetAllKeysHelper MOZ_FINAL : public ObjectStoreHelper |
michael@0 | 503 | { |
michael@0 | 504 | public: |
michael@0 | 505 | GetAllKeysHelper(IDBTransaction* aTransaction, |
michael@0 | 506 | IDBRequest* aRequest, |
michael@0 | 507 | IDBObjectStore* aObjectStore, |
michael@0 | 508 | IDBKeyRange* aKeyRange, |
michael@0 | 509 | const uint32_t aLimit) |
michael@0 | 510 | : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), |
michael@0 | 511 | mKeyRange(aKeyRange), mLimit(aLimit) |
michael@0 | 512 | { } |
michael@0 | 513 | |
michael@0 | 514 | virtual nsresult |
michael@0 | 515 | DoDatabaseWork(mozIStorageConnection* aConnection) MOZ_OVERRIDE; |
michael@0 | 516 | |
michael@0 | 517 | virtual nsresult |
michael@0 | 518 | GetSuccessResult(JSContext* aCx, JS::MutableHandle<JS::Value> aVal) |
michael@0 | 519 | MOZ_OVERRIDE; |
michael@0 | 520 | |
michael@0 | 521 | virtual void |
michael@0 | 522 | ReleaseMainThreadObjects() MOZ_OVERRIDE; |
michael@0 | 523 | |
michael@0 | 524 | virtual nsresult |
michael@0 | 525 | PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; |
michael@0 | 526 | |
michael@0 | 527 | virtual ChildProcessSendResult |
michael@0 | 528 | SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; |
michael@0 | 529 | |
michael@0 | 530 | virtual nsresult |
michael@0 | 531 | UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 532 | MOZ_OVERRIDE; |
michael@0 | 533 | |
michael@0 | 534 | private: |
michael@0 | 535 | ~GetAllKeysHelper() |
michael@0 | 536 | { } |
michael@0 | 537 | |
michael@0 | 538 | nsRefPtr<IDBKeyRange> mKeyRange; |
michael@0 | 539 | const uint32_t mLimit; |
michael@0 | 540 | nsTArray<Key> mKeys; |
michael@0 | 541 | }; |
michael@0 | 542 | |
michael@0 | 543 | class CountHelper : public ObjectStoreHelper |
michael@0 | 544 | { |
michael@0 | 545 | public: |
michael@0 | 546 | CountHelper(IDBTransaction* aTransaction, |
michael@0 | 547 | IDBRequest* aRequest, |
michael@0 | 548 | IDBObjectStore* aObjectStore, |
michael@0 | 549 | IDBKeyRange* aKeyRange) |
michael@0 | 550 | : ObjectStoreHelper(aTransaction, aRequest, aObjectStore), |
michael@0 | 551 | mKeyRange(aKeyRange), mCount(0) |
michael@0 | 552 | { } |
michael@0 | 553 | |
michael@0 | 554 | virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 555 | MOZ_OVERRIDE; |
michael@0 | 556 | |
michael@0 | 557 | virtual nsresult GetSuccessResult(JSContext* aCx, |
michael@0 | 558 | JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE; |
michael@0 | 559 | |
michael@0 | 560 | virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE; |
michael@0 | 561 | |
michael@0 | 562 | virtual nsresult |
michael@0 | 563 | PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) MOZ_OVERRIDE; |
michael@0 | 564 | |
michael@0 | 565 | virtual ChildProcessSendResult |
michael@0 | 566 | SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE; |
michael@0 | 567 | |
michael@0 | 568 | virtual nsresult |
michael@0 | 569 | UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 570 | MOZ_OVERRIDE; |
michael@0 | 571 | |
michael@0 | 572 | private: |
michael@0 | 573 | nsRefPtr<IDBKeyRange> mKeyRange; |
michael@0 | 574 | uint64_t mCount; |
michael@0 | 575 | }; |
michael@0 | 576 | |
michael@0 | 577 | class MOZ_STACK_CLASS AutoRemoveIndex |
michael@0 | 578 | { |
michael@0 | 579 | public: |
michael@0 | 580 | AutoRemoveIndex(ObjectStoreInfo* aObjectStoreInfo, |
michael@0 | 581 | const nsAString& aIndexName) |
michael@0 | 582 | : mObjectStoreInfo(aObjectStoreInfo), mIndexName(aIndexName) |
michael@0 | 583 | { } |
michael@0 | 584 | |
michael@0 | 585 | ~AutoRemoveIndex() |
michael@0 | 586 | { |
michael@0 | 587 | if (mObjectStoreInfo) { |
michael@0 | 588 | for (uint32_t i = 0; i < mObjectStoreInfo->indexes.Length(); i++) { |
michael@0 | 589 | if (mObjectStoreInfo->indexes[i].name == mIndexName) { |
michael@0 | 590 | mObjectStoreInfo->indexes.RemoveElementAt(i); |
michael@0 | 591 | break; |
michael@0 | 592 | } |
michael@0 | 593 | } |
michael@0 | 594 | } |
michael@0 | 595 | } |
michael@0 | 596 | |
michael@0 | 597 | void forget() |
michael@0 | 598 | { |
michael@0 | 599 | mObjectStoreInfo = nullptr; |
michael@0 | 600 | } |
michael@0 | 601 | |
michael@0 | 602 | private: |
michael@0 | 603 | ObjectStoreInfo* mObjectStoreInfo; |
michael@0 | 604 | nsString mIndexName; |
michael@0 | 605 | }; |
michael@0 | 606 | |
michael@0 | 607 | class ThreadLocalJSRuntime |
michael@0 | 608 | { |
michael@0 | 609 | JSRuntime* mRuntime; |
michael@0 | 610 | JSContext* mContext; |
michael@0 | 611 | JSObject* mGlobal; |
michael@0 | 612 | |
michael@0 | 613 | static const JSClass sGlobalClass; |
michael@0 | 614 | static const unsigned sRuntimeHeapSize = 768 * 1024; |
michael@0 | 615 | |
michael@0 | 616 | ThreadLocalJSRuntime() |
michael@0 | 617 | : mRuntime(nullptr), mContext(nullptr), mGlobal(nullptr) |
michael@0 | 618 | { |
michael@0 | 619 | MOZ_COUNT_CTOR(ThreadLocalJSRuntime); |
michael@0 | 620 | } |
michael@0 | 621 | |
michael@0 | 622 | nsresult Init() |
michael@0 | 623 | { |
michael@0 | 624 | mRuntime = JS_NewRuntime(sRuntimeHeapSize, JS_NO_HELPER_THREADS); |
michael@0 | 625 | NS_ENSURE_TRUE(mRuntime, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 626 | |
michael@0 | 627 | /* |
michael@0 | 628 | * Not setting this will cause JS_CHECK_RECURSION to report false |
michael@0 | 629 | * positives |
michael@0 | 630 | */ |
michael@0 | 631 | JS_SetNativeStackQuota(mRuntime, 128 * sizeof(size_t) * 1024); |
michael@0 | 632 | |
michael@0 | 633 | mContext = JS_NewContext(mRuntime, 0); |
michael@0 | 634 | NS_ENSURE_TRUE(mContext, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 635 | |
michael@0 | 636 | JSAutoRequest ar(mContext); |
michael@0 | 637 | |
michael@0 | 638 | mGlobal = JS_NewGlobalObject(mContext, &sGlobalClass, nullptr, |
michael@0 | 639 | JS::FireOnNewGlobalHook); |
michael@0 | 640 | NS_ENSURE_TRUE(mGlobal, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 641 | |
michael@0 | 642 | js::SetDefaultObjectForContext(mContext, mGlobal); |
michael@0 | 643 | return NS_OK; |
michael@0 | 644 | } |
michael@0 | 645 | |
michael@0 | 646 | public: |
michael@0 | 647 | static ThreadLocalJSRuntime *Create() |
michael@0 | 648 | { |
michael@0 | 649 | ThreadLocalJSRuntime *entry = new ThreadLocalJSRuntime(); |
michael@0 | 650 | NS_ENSURE_TRUE(entry, nullptr); |
michael@0 | 651 | |
michael@0 | 652 | if (NS_FAILED(entry->Init())) { |
michael@0 | 653 | delete entry; |
michael@0 | 654 | return nullptr; |
michael@0 | 655 | } |
michael@0 | 656 | |
michael@0 | 657 | return entry; |
michael@0 | 658 | } |
michael@0 | 659 | |
michael@0 | 660 | JSContext *Context() const |
michael@0 | 661 | { |
michael@0 | 662 | return mContext; |
michael@0 | 663 | } |
michael@0 | 664 | |
michael@0 | 665 | JSObject *Global() const |
michael@0 | 666 | { |
michael@0 | 667 | return mGlobal; |
michael@0 | 668 | } |
michael@0 | 669 | |
michael@0 | 670 | ~ThreadLocalJSRuntime() |
michael@0 | 671 | { |
michael@0 | 672 | MOZ_COUNT_DTOR(ThreadLocalJSRuntime); |
michael@0 | 673 | |
michael@0 | 674 | if (mContext) { |
michael@0 | 675 | JS_DestroyContext(mContext); |
michael@0 | 676 | } |
michael@0 | 677 | |
michael@0 | 678 | if (mRuntime) { |
michael@0 | 679 | JS_DestroyRuntime(mRuntime); |
michael@0 | 680 | } |
michael@0 | 681 | } |
michael@0 | 682 | }; |
michael@0 | 683 | |
michael@0 | 684 | const JSClass ThreadLocalJSRuntime::sGlobalClass = { |
michael@0 | 685 | "IndexedDBTransactionThreadGlobal", |
michael@0 | 686 | JSCLASS_GLOBAL_FLAGS, |
michael@0 | 687 | JS_PropertyStub, JS_DeletePropertyStub, JS_PropertyStub, JS_StrictPropertyStub, |
michael@0 | 688 | JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, |
michael@0 | 689 | nullptr, nullptr, nullptr, nullptr, |
michael@0 | 690 | JS_GlobalObjectTraceHook |
michael@0 | 691 | }; |
michael@0 | 692 | |
michael@0 | 693 | inline |
michael@0 | 694 | already_AddRefed<IDBRequest> |
michael@0 | 695 | GenerateRequest(IDBObjectStore* aObjectStore) |
michael@0 | 696 | { |
michael@0 | 697 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 698 | IDBDatabase* database = aObjectStore->Transaction()->Database(); |
michael@0 | 699 | return IDBRequest::Create(aObjectStore, database, |
michael@0 | 700 | aObjectStore->Transaction()); |
michael@0 | 701 | } |
michael@0 | 702 | |
michael@0 | 703 | struct MOZ_STACK_CLASS GetAddInfoClosure |
michael@0 | 704 | { |
michael@0 | 705 | IDBObjectStore* mThis; |
michael@0 | 706 | StructuredCloneWriteInfo& mCloneWriteInfo; |
michael@0 | 707 | JS::Handle<JS::Value> mValue; |
michael@0 | 708 | }; |
michael@0 | 709 | |
michael@0 | 710 | nsresult |
michael@0 | 711 | GetAddInfoCallback(JSContext* aCx, void* aClosure) |
michael@0 | 712 | { |
michael@0 | 713 | GetAddInfoClosure* data = static_cast<GetAddInfoClosure*>(aClosure); |
michael@0 | 714 | |
michael@0 | 715 | data->mCloneWriteInfo.mOffsetToKeyProp = 0; |
michael@0 | 716 | data->mCloneWriteInfo.mTransaction = data->mThis->Transaction(); |
michael@0 | 717 | |
michael@0 | 718 | if (!IDBObjectStore::SerializeValue(aCx, data->mCloneWriteInfo, data->mValue)) { |
michael@0 | 719 | return NS_ERROR_DOM_DATA_CLONE_ERR; |
michael@0 | 720 | } |
michael@0 | 721 | |
michael@0 | 722 | return NS_OK; |
michael@0 | 723 | } |
michael@0 | 724 | |
michael@0 | 725 | inline |
michael@0 | 726 | BlobChild* |
michael@0 | 727 | ActorFromRemoteBlob(nsIDOMBlob* aBlob) |
michael@0 | 728 | { |
michael@0 | 729 | NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 730 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 731 | |
michael@0 | 732 | nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(aBlob); |
michael@0 | 733 | if (remoteBlob) { |
michael@0 | 734 | BlobChild* actor = |
michael@0 | 735 | static_cast<BlobChild*>(static_cast<PBlobChild*>(remoteBlob->GetPBlob())); |
michael@0 | 736 | NS_ASSERTION(actor, "Null actor?!"); |
michael@0 | 737 | return actor; |
michael@0 | 738 | } |
michael@0 | 739 | return nullptr; |
michael@0 | 740 | } |
michael@0 | 741 | |
michael@0 | 742 | inline |
michael@0 | 743 | bool |
michael@0 | 744 | ResolveMysteryFile(nsIDOMBlob* aBlob, const nsString& aName, |
michael@0 | 745 | const nsString& aContentType, uint64_t aSize, |
michael@0 | 746 | uint64_t aLastModifiedDate) |
michael@0 | 747 | { |
michael@0 | 748 | BlobChild* actor = ActorFromRemoteBlob(aBlob); |
michael@0 | 749 | if (actor) { |
michael@0 | 750 | return actor->SetMysteryBlobInfo(aName, aContentType, |
michael@0 | 751 | aSize, aLastModifiedDate); |
michael@0 | 752 | } |
michael@0 | 753 | return true; |
michael@0 | 754 | } |
michael@0 | 755 | |
michael@0 | 756 | inline |
michael@0 | 757 | bool |
michael@0 | 758 | ResolveMysteryBlob(nsIDOMBlob* aBlob, const nsString& aContentType, |
michael@0 | 759 | uint64_t aSize) |
michael@0 | 760 | { |
michael@0 | 761 | BlobChild* actor = ActorFromRemoteBlob(aBlob); |
michael@0 | 762 | if (actor) { |
michael@0 | 763 | return actor->SetMysteryBlobInfo(aContentType, aSize); |
michael@0 | 764 | } |
michael@0 | 765 | return true; |
michael@0 | 766 | } |
michael@0 | 767 | |
michael@0 | 768 | class MainThreadDeserializationTraits |
michael@0 | 769 | { |
michael@0 | 770 | public: |
michael@0 | 771 | static JSObject* CreateAndWrapFileHandle(JSContext* aCx, |
michael@0 | 772 | IDBDatabase* aDatabase, |
michael@0 | 773 | StructuredCloneFile& aFile, |
michael@0 | 774 | const FileHandleData& aData) |
michael@0 | 775 | { |
michael@0 | 776 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 777 | |
michael@0 | 778 | nsRefPtr<FileInfo>& fileInfo = aFile.mFileInfo; |
michael@0 | 779 | |
michael@0 | 780 | nsRefPtr<IDBFileHandle> fileHandle = IDBFileHandle::Create(aDatabase, |
michael@0 | 781 | aData.name, aData.type, fileInfo.forget()); |
michael@0 | 782 | |
michael@0 | 783 | return fileHandle->WrapObject(aCx); |
michael@0 | 784 | } |
michael@0 | 785 | |
michael@0 | 786 | static JSObject* CreateAndWrapBlobOrFile(JSContext* aCx, |
michael@0 | 787 | IDBDatabase* aDatabase, |
michael@0 | 788 | StructuredCloneFile& aFile, |
michael@0 | 789 | const BlobOrFileData& aData) |
michael@0 | 790 | { |
michael@0 | 791 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 792 | |
michael@0 | 793 | MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE || |
michael@0 | 794 | aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE || |
michael@0 | 795 | aData.tag == SCTAG_DOM_BLOB); |
michael@0 | 796 | |
michael@0 | 797 | nsresult rv = NS_OK; |
michael@0 | 798 | |
michael@0 | 799 | nsRefPtr<FileInfo>& fileInfo = aFile.mFileInfo; |
michael@0 | 800 | |
michael@0 | 801 | nsCOMPtr<nsIFile> nativeFile; |
michael@0 | 802 | if (!aFile.mFile) { |
michael@0 | 803 | FileManager* fileManager = aDatabase->Manager(); |
michael@0 | 804 | NS_ASSERTION(fileManager, "This should never be null!"); |
michael@0 | 805 | |
michael@0 | 806 | nsCOMPtr<nsIFile> directory = fileManager->GetDirectory(); |
michael@0 | 807 | if (!directory) { |
michael@0 | 808 | NS_WARNING("Failed to get directory!"); |
michael@0 | 809 | return nullptr; |
michael@0 | 810 | } |
michael@0 | 811 | |
michael@0 | 812 | nativeFile = fileManager->GetFileForId(directory, fileInfo->Id()); |
michael@0 | 813 | if (!nativeFile) { |
michael@0 | 814 | NS_WARNING("Failed to get file!"); |
michael@0 | 815 | return nullptr; |
michael@0 | 816 | } |
michael@0 | 817 | } |
michael@0 | 818 | |
michael@0 | 819 | if (aData.tag == SCTAG_DOM_BLOB) { |
michael@0 | 820 | nsCOMPtr<nsIDOMBlob> domBlob; |
michael@0 | 821 | if (aFile.mFile) { |
michael@0 | 822 | if (!ResolveMysteryBlob(aFile.mFile, aData.type, aData.size)) { |
michael@0 | 823 | return nullptr; |
michael@0 | 824 | } |
michael@0 | 825 | domBlob = aFile.mFile; |
michael@0 | 826 | } |
michael@0 | 827 | else { |
michael@0 | 828 | domBlob = new nsDOMFileFile(aData.type, aData.size, nativeFile, |
michael@0 | 829 | fileInfo); |
michael@0 | 830 | } |
michael@0 | 831 | |
michael@0 | 832 | JS::Rooted<JS::Value> wrappedBlob(aCx); |
michael@0 | 833 | rv = nsContentUtils::WrapNative(aCx, domBlob, &NS_GET_IID(nsIDOMBlob), |
michael@0 | 834 | &wrappedBlob); |
michael@0 | 835 | if (NS_FAILED(rv)) { |
michael@0 | 836 | NS_WARNING("Failed to wrap native!"); |
michael@0 | 837 | return nullptr; |
michael@0 | 838 | } |
michael@0 | 839 | |
michael@0 | 840 | return JSVAL_TO_OBJECT(wrappedBlob); |
michael@0 | 841 | } |
michael@0 | 842 | |
michael@0 | 843 | nsCOMPtr<nsIDOMFile> domFile; |
michael@0 | 844 | if (aFile.mFile) { |
michael@0 | 845 | if (!ResolveMysteryFile(aFile.mFile, aData.name, aData.type, aData.size, |
michael@0 | 846 | aData.lastModifiedDate)) { |
michael@0 | 847 | return nullptr; |
michael@0 | 848 | } |
michael@0 | 849 | domFile = do_QueryInterface(aFile.mFile); |
michael@0 | 850 | NS_ASSERTION(domFile, "This should never fail!"); |
michael@0 | 851 | } |
michael@0 | 852 | else { |
michael@0 | 853 | domFile = new nsDOMFileFile(aData.name, aData.type, aData.size, |
michael@0 | 854 | nativeFile, fileInfo); |
michael@0 | 855 | } |
michael@0 | 856 | |
michael@0 | 857 | JS::Rooted<JS::Value> wrappedFile(aCx); |
michael@0 | 858 | rv = nsContentUtils::WrapNative(aCx, domFile, &NS_GET_IID(nsIDOMFile), |
michael@0 | 859 | &wrappedFile); |
michael@0 | 860 | if (NS_FAILED(rv)) { |
michael@0 | 861 | NS_WARNING("Failed to wrap native!"); |
michael@0 | 862 | return nullptr; |
michael@0 | 863 | } |
michael@0 | 864 | |
michael@0 | 865 | return JSVAL_TO_OBJECT(wrappedFile); |
michael@0 | 866 | } |
michael@0 | 867 | }; |
michael@0 | 868 | |
michael@0 | 869 | |
michael@0 | 870 | class CreateIndexDeserializationTraits |
michael@0 | 871 | { |
michael@0 | 872 | public: |
michael@0 | 873 | static JSObject* CreateAndWrapFileHandle(JSContext* aCx, |
michael@0 | 874 | IDBDatabase* aDatabase, |
michael@0 | 875 | StructuredCloneFile& aFile, |
michael@0 | 876 | const FileHandleData& aData) |
michael@0 | 877 | { |
michael@0 | 878 | // FileHandle can't be used in index creation, so just make a dummy object. |
michael@0 | 879 | return JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr()); |
michael@0 | 880 | } |
michael@0 | 881 | |
michael@0 | 882 | static JSObject* CreateAndWrapBlobOrFile(JSContext* aCx, |
michael@0 | 883 | IDBDatabase* aDatabase, |
michael@0 | 884 | StructuredCloneFile& aFile, |
michael@0 | 885 | const BlobOrFileData& aData) |
michael@0 | 886 | { |
michael@0 | 887 | MOZ_ASSERT(aData.tag == SCTAG_DOM_FILE || |
michael@0 | 888 | aData.tag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE || |
michael@0 | 889 | aData.tag == SCTAG_DOM_BLOB); |
michael@0 | 890 | |
michael@0 | 891 | // The following properties are available for use in index creation |
michael@0 | 892 | // Blob.size |
michael@0 | 893 | // Blob.type |
michael@0 | 894 | // File.name |
michael@0 | 895 | // File.lastModifiedDate |
michael@0 | 896 | |
michael@0 | 897 | JS::Rooted<JSObject*> obj(aCx, |
michael@0 | 898 | JS_NewObject(aCx, nullptr, JS::NullPtr(), JS::NullPtr())); |
michael@0 | 899 | if (!obj) { |
michael@0 | 900 | NS_WARNING("Failed to create object!"); |
michael@0 | 901 | return nullptr; |
michael@0 | 902 | } |
michael@0 | 903 | |
michael@0 | 904 | // Technically these props go on the proto, but this detail won't change |
michael@0 | 905 | // the results of index creation. |
michael@0 | 906 | |
michael@0 | 907 | JS::Rooted<JSString*> type(aCx, |
michael@0 | 908 | JS_NewUCStringCopyN(aCx, aData.type.get(), aData.type.Length())); |
michael@0 | 909 | if (!type || |
michael@0 | 910 | !JS_DefineProperty(aCx, obj, "size", double(aData.size), 0) || |
michael@0 | 911 | !JS_DefineProperty(aCx, obj, "type", type, 0)) { |
michael@0 | 912 | return nullptr; |
michael@0 | 913 | } |
michael@0 | 914 | |
michael@0 | 915 | if (aData.tag == SCTAG_DOM_BLOB) { |
michael@0 | 916 | return obj; |
michael@0 | 917 | } |
michael@0 | 918 | |
michael@0 | 919 | JS::Rooted<JSString*> name(aCx, |
michael@0 | 920 | JS_NewUCStringCopyN(aCx, aData.name.get(), aData.name.Length())); |
michael@0 | 921 | JS::Rooted<JSObject*> date(aCx, |
michael@0 | 922 | JS_NewDateObjectMsec(aCx, aData.lastModifiedDate)); |
michael@0 | 923 | if (!name || !date || |
michael@0 | 924 | !JS_DefineProperty(aCx, obj, "name", name, 0) || |
michael@0 | 925 | !JS_DefineProperty(aCx, obj, "lastModifiedDate", date, 0)) { |
michael@0 | 926 | return nullptr; |
michael@0 | 927 | } |
michael@0 | 928 | |
michael@0 | 929 | return obj; |
michael@0 | 930 | } |
michael@0 | 931 | }; |
michael@0 | 932 | |
michael@0 | 933 | } // anonymous namespace |
michael@0 | 934 | |
michael@0 | 935 | const JSClass IDBObjectStore::sDummyPropJSClass = { |
michael@0 | 936 | "dummy", 0, |
michael@0 | 937 | JS_PropertyStub, JS_DeletePropertyStub, |
michael@0 | 938 | JS_PropertyStub, JS_StrictPropertyStub, |
michael@0 | 939 | JS_EnumerateStub, JS_ResolveStub, |
michael@0 | 940 | JS_ConvertStub |
michael@0 | 941 | }; |
michael@0 | 942 | |
michael@0 | 943 | // static |
michael@0 | 944 | already_AddRefed<IDBObjectStore> |
michael@0 | 945 | IDBObjectStore::Create(IDBTransaction* aTransaction, |
michael@0 | 946 | ObjectStoreInfo* aStoreInfo, |
michael@0 | 947 | const nsACString& aDatabaseId, |
michael@0 | 948 | bool aCreating) |
michael@0 | 949 | { |
michael@0 | 950 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 951 | |
michael@0 | 952 | nsRefPtr<IDBObjectStore> objectStore = new IDBObjectStore(); |
michael@0 | 953 | |
michael@0 | 954 | objectStore->mTransaction = aTransaction; |
michael@0 | 955 | objectStore->mName = aStoreInfo->name; |
michael@0 | 956 | objectStore->mId = aStoreInfo->id; |
michael@0 | 957 | objectStore->mKeyPath = aStoreInfo->keyPath; |
michael@0 | 958 | objectStore->mAutoIncrement = aStoreInfo->autoIncrement; |
michael@0 | 959 | objectStore->mDatabaseId = aDatabaseId; |
michael@0 | 960 | objectStore->mInfo = aStoreInfo; |
michael@0 | 961 | |
michael@0 | 962 | if (!IndexedDatabaseManager::IsMainProcess()) { |
michael@0 | 963 | IndexedDBTransactionChild* transactionActor = aTransaction->GetActorChild(); |
michael@0 | 964 | NS_ASSERTION(transactionActor, "Must have an actor here!"); |
michael@0 | 965 | |
michael@0 | 966 | ObjectStoreConstructorParams params; |
michael@0 | 967 | |
michael@0 | 968 | if (aCreating) { |
michael@0 | 969 | CreateObjectStoreParams createParams; |
michael@0 | 970 | createParams.info() = *aStoreInfo; |
michael@0 | 971 | params = createParams; |
michael@0 | 972 | } |
michael@0 | 973 | else { |
michael@0 | 974 | GetObjectStoreParams getParams; |
michael@0 | 975 | getParams.name() = aStoreInfo->name; |
michael@0 | 976 | params = getParams; |
michael@0 | 977 | } |
michael@0 | 978 | |
michael@0 | 979 | IndexedDBObjectStoreChild* actor = |
michael@0 | 980 | new IndexedDBObjectStoreChild(objectStore); |
michael@0 | 981 | |
michael@0 | 982 | transactionActor->SendPIndexedDBObjectStoreConstructor(actor, params); |
michael@0 | 983 | } |
michael@0 | 984 | |
michael@0 | 985 | return objectStore.forget(); |
michael@0 | 986 | } |
michael@0 | 987 | |
michael@0 | 988 | // static |
michael@0 | 989 | nsresult |
michael@0 | 990 | IDBObjectStore::AppendIndexUpdateInfo( |
michael@0 | 991 | int64_t aIndexID, |
michael@0 | 992 | const KeyPath& aKeyPath, |
michael@0 | 993 | bool aUnique, |
michael@0 | 994 | bool aMultiEntry, |
michael@0 | 995 | JSContext* aCx, |
michael@0 | 996 | JS::Handle<JS::Value> aVal, |
michael@0 | 997 | nsTArray<IndexUpdateInfo>& aUpdateInfoArray) |
michael@0 | 998 | { |
michael@0 | 999 | nsresult rv; |
michael@0 | 1000 | |
michael@0 | 1001 | if (!aMultiEntry) { |
michael@0 | 1002 | Key key; |
michael@0 | 1003 | rv = aKeyPath.ExtractKey(aCx, aVal, key); |
michael@0 | 1004 | |
michael@0 | 1005 | // If an index's keypath doesn't match an object, we ignore that object. |
michael@0 | 1006 | if (rv == NS_ERROR_DOM_INDEXEDDB_DATA_ERR || key.IsUnset()) { |
michael@0 | 1007 | return NS_OK; |
michael@0 | 1008 | } |
michael@0 | 1009 | |
michael@0 | 1010 | if (NS_FAILED(rv)) { |
michael@0 | 1011 | return rv; |
michael@0 | 1012 | } |
michael@0 | 1013 | |
michael@0 | 1014 | IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement(); |
michael@0 | 1015 | updateInfo->indexId = aIndexID; |
michael@0 | 1016 | updateInfo->indexUnique = aUnique; |
michael@0 | 1017 | updateInfo->value = key; |
michael@0 | 1018 | |
michael@0 | 1019 | return NS_OK; |
michael@0 | 1020 | } |
michael@0 | 1021 | |
michael@0 | 1022 | JS::Rooted<JS::Value> val(aCx); |
michael@0 | 1023 | if (NS_FAILED(aKeyPath.ExtractKeyAsJSVal(aCx, aVal, val.address()))) { |
michael@0 | 1024 | return NS_OK; |
michael@0 | 1025 | } |
michael@0 | 1026 | |
michael@0 | 1027 | if (JS_IsArrayObject(aCx, val)) { |
michael@0 | 1028 | JS::Rooted<JSObject*> array(aCx, &val.toObject()); |
michael@0 | 1029 | uint32_t arrayLength; |
michael@0 | 1030 | if (!JS_GetArrayLength(aCx, array, &arrayLength)) { |
michael@0 | 1031 | IDB_REPORT_INTERNAL_ERR(); |
michael@0 | 1032 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 1033 | } |
michael@0 | 1034 | |
michael@0 | 1035 | for (uint32_t arrayIndex = 0; arrayIndex < arrayLength; arrayIndex++) { |
michael@0 | 1036 | JS::Rooted<JS::Value> arrayItem(aCx); |
michael@0 | 1037 | if (!JS_GetElement(aCx, array, arrayIndex, &arrayItem)) { |
michael@0 | 1038 | IDB_REPORT_INTERNAL_ERR(); |
michael@0 | 1039 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 1040 | } |
michael@0 | 1041 | |
michael@0 | 1042 | Key value; |
michael@0 | 1043 | if (NS_FAILED(value.SetFromJSVal(aCx, arrayItem)) || |
michael@0 | 1044 | value.IsUnset()) { |
michael@0 | 1045 | // Not a value we can do anything with, ignore it. |
michael@0 | 1046 | continue; |
michael@0 | 1047 | } |
michael@0 | 1048 | |
michael@0 | 1049 | IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement(); |
michael@0 | 1050 | updateInfo->indexId = aIndexID; |
michael@0 | 1051 | updateInfo->indexUnique = aUnique; |
michael@0 | 1052 | updateInfo->value = value; |
michael@0 | 1053 | } |
michael@0 | 1054 | } |
michael@0 | 1055 | else { |
michael@0 | 1056 | Key value; |
michael@0 | 1057 | if (NS_FAILED(value.SetFromJSVal(aCx, val)) || |
michael@0 | 1058 | value.IsUnset()) { |
michael@0 | 1059 | // Not a value we can do anything with, ignore it. |
michael@0 | 1060 | return NS_OK; |
michael@0 | 1061 | } |
michael@0 | 1062 | |
michael@0 | 1063 | IndexUpdateInfo* updateInfo = aUpdateInfoArray.AppendElement(); |
michael@0 | 1064 | updateInfo->indexId = aIndexID; |
michael@0 | 1065 | updateInfo->indexUnique = aUnique; |
michael@0 | 1066 | updateInfo->value = value; |
michael@0 | 1067 | } |
michael@0 | 1068 | |
michael@0 | 1069 | return NS_OK; |
michael@0 | 1070 | } |
michael@0 | 1071 | |
michael@0 | 1072 | // static |
michael@0 | 1073 | nsresult |
michael@0 | 1074 | IDBObjectStore::UpdateIndexes(IDBTransaction* aTransaction, |
michael@0 | 1075 | int64_t aObjectStoreId, |
michael@0 | 1076 | const Key& aObjectStoreKey, |
michael@0 | 1077 | bool aOverwrite, |
michael@0 | 1078 | int64_t aObjectDataId, |
michael@0 | 1079 | const nsTArray<IndexUpdateInfo>& aUpdateInfoArray) |
michael@0 | 1080 | { |
michael@0 | 1081 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1082 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 1083 | |
michael@0 | 1084 | PROFILER_LABEL("IndexedDB", "IDBObjectStore::UpdateIndexes"); |
michael@0 | 1085 | |
michael@0 | 1086 | nsresult rv; |
michael@0 | 1087 | |
michael@0 | 1088 | NS_ASSERTION(aObjectDataId != INT64_MIN, "Bad objectData id!"); |
michael@0 | 1089 | |
michael@0 | 1090 | NS_NAMED_LITERAL_CSTRING(objectDataId, "object_data_id"); |
michael@0 | 1091 | |
michael@0 | 1092 | if (aOverwrite) { |
michael@0 | 1093 | nsCOMPtr<mozIStorageStatement> deleteStmt = |
michael@0 | 1094 | aTransaction->GetCachedStatement( |
michael@0 | 1095 | "DELETE FROM unique_index_data " |
michael@0 | 1096 | "WHERE object_data_id = :object_data_id; " |
michael@0 | 1097 | "DELETE FROM index_data " |
michael@0 | 1098 | "WHERE object_data_id = :object_data_id"); |
michael@0 | 1099 | NS_ENSURE_TRUE(deleteStmt, NS_ERROR_FAILURE); |
michael@0 | 1100 | |
michael@0 | 1101 | mozStorageStatementScoper scoper(deleteStmt); |
michael@0 | 1102 | |
michael@0 | 1103 | rv = deleteStmt->BindInt64ByName(objectDataId, aObjectDataId); |
michael@0 | 1104 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1105 | |
michael@0 | 1106 | rv = deleteStmt->Execute(); |
michael@0 | 1107 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1108 | } |
michael@0 | 1109 | |
michael@0 | 1110 | // Avoid lots of hash lookups for objectStores with lots of indexes by lazily |
michael@0 | 1111 | // holding the necessary statements on the stack outside the loop. |
michael@0 | 1112 | nsCOMPtr<mozIStorageStatement> insertUniqueStmt; |
michael@0 | 1113 | nsCOMPtr<mozIStorageStatement> insertStmt; |
michael@0 | 1114 | |
michael@0 | 1115 | uint32_t infoCount = aUpdateInfoArray.Length(); |
michael@0 | 1116 | for (uint32_t i = 0; i < infoCount; i++) { |
michael@0 | 1117 | const IndexUpdateInfo& updateInfo = aUpdateInfoArray[i]; |
michael@0 | 1118 | |
michael@0 | 1119 | nsCOMPtr<mozIStorageStatement>& stmt = |
michael@0 | 1120 | updateInfo.indexUnique ? insertUniqueStmt : insertStmt; |
michael@0 | 1121 | |
michael@0 | 1122 | if (!stmt) { |
michael@0 | 1123 | stmt = updateInfo.indexUnique ? |
michael@0 | 1124 | aTransaction->GetCachedStatement( |
michael@0 | 1125 | "INSERT INTO unique_index_data " |
michael@0 | 1126 | "(index_id, object_data_id, object_data_key, value) " |
michael@0 | 1127 | "VALUES (:index_id, :object_data_id, :object_data_key, :value)") : |
michael@0 | 1128 | aTransaction->GetCachedStatement( |
michael@0 | 1129 | "INSERT OR IGNORE INTO index_data (" |
michael@0 | 1130 | "index_id, object_data_id, object_data_key, value) " |
michael@0 | 1131 | "VALUES (:index_id, :object_data_id, :object_data_key, :value)"); |
michael@0 | 1132 | } |
michael@0 | 1133 | NS_ENSURE_TRUE(stmt, NS_ERROR_FAILURE); |
michael@0 | 1134 | |
michael@0 | 1135 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 1136 | |
michael@0 | 1137 | rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"), |
michael@0 | 1138 | updateInfo.indexId); |
michael@0 | 1139 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1140 | |
michael@0 | 1141 | rv = stmt->BindInt64ByName(objectDataId, aObjectDataId); |
michael@0 | 1142 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1143 | |
michael@0 | 1144 | rv = aObjectStoreKey.BindToStatement(stmt, |
michael@0 | 1145 | NS_LITERAL_CSTRING("object_data_key")); |
michael@0 | 1146 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1147 | |
michael@0 | 1148 | rv = updateInfo.value.BindToStatement(stmt, NS_LITERAL_CSTRING("value")); |
michael@0 | 1149 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1150 | |
michael@0 | 1151 | rv = stmt->Execute(); |
michael@0 | 1152 | if (rv == NS_ERROR_STORAGE_CONSTRAINT && updateInfo.indexUnique) { |
michael@0 | 1153 | // If we're inserting multiple entries for the same unique index, then |
michael@0 | 1154 | // we might have failed to insert due to colliding with another entry for |
michael@0 | 1155 | // the same index in which case we should ignore it. |
michael@0 | 1156 | |
michael@0 | 1157 | for (int32_t j = (int32_t)i - 1; |
michael@0 | 1158 | j >= 0 && aUpdateInfoArray[j].indexId == updateInfo.indexId; |
michael@0 | 1159 | --j) { |
michael@0 | 1160 | if (updateInfo.value == aUpdateInfoArray[j].value) { |
michael@0 | 1161 | // We found a key with the same value for the same index. So we |
michael@0 | 1162 | // must have had a collision with a value we just inserted. |
michael@0 | 1163 | rv = NS_OK; |
michael@0 | 1164 | break; |
michael@0 | 1165 | } |
michael@0 | 1166 | } |
michael@0 | 1167 | } |
michael@0 | 1168 | |
michael@0 | 1169 | if (NS_FAILED(rv)) { |
michael@0 | 1170 | return rv; |
michael@0 | 1171 | } |
michael@0 | 1172 | } |
michael@0 | 1173 | |
michael@0 | 1174 | return NS_OK; |
michael@0 | 1175 | } |
michael@0 | 1176 | |
michael@0 | 1177 | // static |
michael@0 | 1178 | nsresult |
michael@0 | 1179 | IDBObjectStore::GetStructuredCloneReadInfoFromStatement( |
michael@0 | 1180 | mozIStorageStatement* aStatement, |
michael@0 | 1181 | uint32_t aDataIndex, |
michael@0 | 1182 | uint32_t aFileIdsIndex, |
michael@0 | 1183 | IDBDatabase* aDatabase, |
michael@0 | 1184 | StructuredCloneReadInfo& aInfo) |
michael@0 | 1185 | { |
michael@0 | 1186 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1187 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 1188 | |
michael@0 | 1189 | PROFILER_LABEL("IndexedDB", |
michael@0 | 1190 | "IDBObjectStore::GetStructuredCloneReadInfoFromStatement"); |
michael@0 | 1191 | |
michael@0 | 1192 | #ifdef DEBUG |
michael@0 | 1193 | { |
michael@0 | 1194 | int32_t type; |
michael@0 | 1195 | NS_ASSERTION(NS_SUCCEEDED(aStatement->GetTypeOfIndex(aDataIndex, &type)) && |
michael@0 | 1196 | type == mozIStorageStatement::VALUE_TYPE_BLOB, |
michael@0 | 1197 | "Bad value type!"); |
michael@0 | 1198 | } |
michael@0 | 1199 | #endif |
michael@0 | 1200 | |
michael@0 | 1201 | const uint8_t* blobData; |
michael@0 | 1202 | uint32_t blobDataLength; |
michael@0 | 1203 | nsresult rv = aStatement->GetSharedBlob(aDataIndex, &blobDataLength, |
michael@0 | 1204 | &blobData); |
michael@0 | 1205 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 1206 | |
michael@0 | 1207 | const char* compressed = reinterpret_cast<const char*>(blobData); |
michael@0 | 1208 | size_t compressedLength = size_t(blobDataLength); |
michael@0 | 1209 | |
michael@0 | 1210 | static const fallible_t fallible = fallible_t(); |
michael@0 | 1211 | |
michael@0 | 1212 | size_t uncompressedLength; |
michael@0 | 1213 | if (!snappy::GetUncompressedLength(compressed, compressedLength, |
michael@0 | 1214 | &uncompressedLength)) { |
michael@0 | 1215 | IDB_WARNING("Snappy can't determine uncompressed length!"); |
michael@0 | 1216 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 1217 | } |
michael@0 | 1218 | |
michael@0 | 1219 | nsAutoArrayPtr<char> uncompressed(new (fallible) char[uncompressedLength]); |
michael@0 | 1220 | NS_ENSURE_TRUE(uncompressed, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 1221 | |
michael@0 | 1222 | if (!snappy::RawUncompress(compressed, compressedLength, |
michael@0 | 1223 | uncompressed.get())) { |
michael@0 | 1224 | IDB_WARNING("Snappy can't determine uncompressed length!"); |
michael@0 | 1225 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 1226 | } |
michael@0 | 1227 | |
michael@0 | 1228 | JSAutoStructuredCloneBuffer& buffer = aInfo.mCloneBuffer; |
michael@0 | 1229 | if (!buffer.copy(reinterpret_cast<const uint64_t *>(uncompressed.get()), |
michael@0 | 1230 | uncompressedLength)) { |
michael@0 | 1231 | IDB_REPORT_INTERNAL_ERR(); |
michael@0 | 1232 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 1233 | } |
michael@0 | 1234 | |
michael@0 | 1235 | bool isNull; |
michael@0 | 1236 | rv = aStatement->GetIsNull(aFileIdsIndex, &isNull); |
michael@0 | 1237 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 1238 | |
michael@0 | 1239 | if (!isNull) { |
michael@0 | 1240 | nsString ids; |
michael@0 | 1241 | rv = aStatement->GetString(aFileIdsIndex, ids); |
michael@0 | 1242 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 1243 | |
michael@0 | 1244 | nsAutoTArray<int64_t, 10> array; |
michael@0 | 1245 | rv = ConvertFileIdsToArray(ids, array); |
michael@0 | 1246 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 1247 | |
michael@0 | 1248 | FileManager* fileManager = aDatabase->Manager(); |
michael@0 | 1249 | |
michael@0 | 1250 | for (uint32_t i = 0; i < array.Length(); i++) { |
michael@0 | 1251 | const int64_t& id = array[i]; |
michael@0 | 1252 | |
michael@0 | 1253 | nsRefPtr<FileInfo> fileInfo = fileManager->GetFileInfo(id); |
michael@0 | 1254 | NS_ASSERTION(fileInfo, "Null file info!"); |
michael@0 | 1255 | |
michael@0 | 1256 | StructuredCloneFile* file = aInfo.mFiles.AppendElement(); |
michael@0 | 1257 | file->mFileInfo.swap(fileInfo); |
michael@0 | 1258 | } |
michael@0 | 1259 | } |
michael@0 | 1260 | |
michael@0 | 1261 | aInfo.mDatabase = aDatabase; |
michael@0 | 1262 | |
michael@0 | 1263 | return NS_OK; |
michael@0 | 1264 | } |
michael@0 | 1265 | |
michael@0 | 1266 | // static |
michael@0 | 1267 | void |
michael@0 | 1268 | IDBObjectStore::ClearCloneWriteInfo(StructuredCloneWriteInfo& aWriteInfo) |
michael@0 | 1269 | { |
michael@0 | 1270 | // This is kind of tricky, we only want to release stuff on the main thread, |
michael@0 | 1271 | // but we can end up being called on other threads if we have already been |
michael@0 | 1272 | // cleared on the main thread. |
michael@0 | 1273 | if (!aWriteInfo.mCloneBuffer.data() && !aWriteInfo.mFiles.Length()) { |
michael@0 | 1274 | return; |
michael@0 | 1275 | } |
michael@0 | 1276 | |
michael@0 | 1277 | // If there's something to clear, we should be on the main thread. |
michael@0 | 1278 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1279 | |
michael@0 | 1280 | ClearStructuredCloneBuffer(aWriteInfo.mCloneBuffer); |
michael@0 | 1281 | aWriteInfo.mFiles.Clear(); |
michael@0 | 1282 | } |
michael@0 | 1283 | |
michael@0 | 1284 | // static |
michael@0 | 1285 | void |
michael@0 | 1286 | IDBObjectStore::ClearCloneReadInfo(StructuredCloneReadInfo& aReadInfo) |
michael@0 | 1287 | { |
michael@0 | 1288 | // This is kind of tricky, we only want to release stuff on the main thread, |
michael@0 | 1289 | // but we can end up being called on other threads if we have already been |
michael@0 | 1290 | // cleared on the main thread. |
michael@0 | 1291 | if (!aReadInfo.mCloneBuffer.data() && !aReadInfo.mFiles.Length()) { |
michael@0 | 1292 | return; |
michael@0 | 1293 | } |
michael@0 | 1294 | |
michael@0 | 1295 | // If there's something to clear, we should be on the main thread. |
michael@0 | 1296 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1297 | |
michael@0 | 1298 | ClearStructuredCloneBuffer(aReadInfo.mCloneBuffer); |
michael@0 | 1299 | aReadInfo.mFiles.Clear(); |
michael@0 | 1300 | } |
michael@0 | 1301 | |
michael@0 | 1302 | // static |
michael@0 | 1303 | void |
michael@0 | 1304 | IDBObjectStore::ClearStructuredCloneBuffer(JSAutoStructuredCloneBuffer& aBuffer) |
michael@0 | 1305 | { |
michael@0 | 1306 | if (aBuffer.data()) { |
michael@0 | 1307 | aBuffer.clear(); |
michael@0 | 1308 | } |
michael@0 | 1309 | } |
michael@0 | 1310 | |
michael@0 | 1311 | // static |
michael@0 | 1312 | bool |
michael@0 | 1313 | IDBObjectStore::DeserializeValue(JSContext* aCx, |
michael@0 | 1314 | StructuredCloneReadInfo& aCloneReadInfo, |
michael@0 | 1315 | JS::MutableHandle<JS::Value> aValue) |
michael@0 | 1316 | { |
michael@0 | 1317 | NS_ASSERTION(NS_IsMainThread(), |
michael@0 | 1318 | "Should only be deserializing on the main thread!"); |
michael@0 | 1319 | NS_ASSERTION(aCx, "A JSContext is required!"); |
michael@0 | 1320 | |
michael@0 | 1321 | JSAutoStructuredCloneBuffer& buffer = aCloneReadInfo.mCloneBuffer; |
michael@0 | 1322 | |
michael@0 | 1323 | if (!buffer.data()) { |
michael@0 | 1324 | aValue.setUndefined(); |
michael@0 | 1325 | return true; |
michael@0 | 1326 | } |
michael@0 | 1327 | |
michael@0 | 1328 | JSAutoRequest ar(aCx); |
michael@0 | 1329 | |
michael@0 | 1330 | JSStructuredCloneCallbacks callbacks = { |
michael@0 | 1331 | IDBObjectStore::StructuredCloneReadCallback<MainThreadDeserializationTraits>, |
michael@0 | 1332 | nullptr, |
michael@0 | 1333 | nullptr, |
michael@0 | 1334 | nullptr, |
michael@0 | 1335 | nullptr, |
michael@0 | 1336 | nullptr |
michael@0 | 1337 | }; |
michael@0 | 1338 | |
michael@0 | 1339 | return buffer.read(aCx, aValue, &callbacks, &aCloneReadInfo); |
michael@0 | 1340 | } |
michael@0 | 1341 | |
michael@0 | 1342 | // static |
michael@0 | 1343 | bool |
michael@0 | 1344 | IDBObjectStore::SerializeValue(JSContext* aCx, |
michael@0 | 1345 | StructuredCloneWriteInfo& aCloneWriteInfo, |
michael@0 | 1346 | JS::Handle<JS::Value> aValue) |
michael@0 | 1347 | { |
michael@0 | 1348 | NS_ASSERTION(NS_IsMainThread(), |
michael@0 | 1349 | "Should only be serializing on the main thread!"); |
michael@0 | 1350 | NS_ASSERTION(aCx, "A JSContext is required!"); |
michael@0 | 1351 | |
michael@0 | 1352 | JSAutoRequest ar(aCx); |
michael@0 | 1353 | |
michael@0 | 1354 | JSStructuredCloneCallbacks callbacks = { |
michael@0 | 1355 | nullptr, |
michael@0 | 1356 | StructuredCloneWriteCallback, |
michael@0 | 1357 | nullptr, |
michael@0 | 1358 | nullptr, |
michael@0 | 1359 | nullptr, |
michael@0 | 1360 | nullptr |
michael@0 | 1361 | }; |
michael@0 | 1362 | |
michael@0 | 1363 | JSAutoStructuredCloneBuffer& buffer = aCloneWriteInfo.mCloneBuffer; |
michael@0 | 1364 | |
michael@0 | 1365 | return buffer.write(aCx, aValue, &callbacks, &aCloneWriteInfo); |
michael@0 | 1366 | } |
michael@0 | 1367 | |
michael@0 | 1368 | static inline bool |
michael@0 | 1369 | StructuredCloneReadString(JSStructuredCloneReader* aReader, |
michael@0 | 1370 | nsCString& aString) |
michael@0 | 1371 | { |
michael@0 | 1372 | uint32_t length; |
michael@0 | 1373 | if (!JS_ReadBytes(aReader, &length, sizeof(uint32_t))) { |
michael@0 | 1374 | NS_WARNING("Failed to read length!"); |
michael@0 | 1375 | return false; |
michael@0 | 1376 | } |
michael@0 | 1377 | length = NativeEndian::swapFromLittleEndian(length); |
michael@0 | 1378 | |
michael@0 | 1379 | if (!aString.SetLength(length, fallible_t())) { |
michael@0 | 1380 | NS_WARNING("Out of memory?"); |
michael@0 | 1381 | return false; |
michael@0 | 1382 | } |
michael@0 | 1383 | char* buffer = aString.BeginWriting(); |
michael@0 | 1384 | |
michael@0 | 1385 | if (!JS_ReadBytes(aReader, buffer, length)) { |
michael@0 | 1386 | NS_WARNING("Failed to read type!"); |
michael@0 | 1387 | return false; |
michael@0 | 1388 | } |
michael@0 | 1389 | |
michael@0 | 1390 | return true; |
michael@0 | 1391 | } |
michael@0 | 1392 | |
michael@0 | 1393 | // static |
michael@0 | 1394 | bool |
michael@0 | 1395 | IDBObjectStore::ReadFileHandle(JSStructuredCloneReader* aReader, |
michael@0 | 1396 | FileHandleData* aRetval) |
michael@0 | 1397 | { |
michael@0 | 1398 | static_assert(SCTAG_DOM_FILEHANDLE == 0xFFFF8004, |
michael@0 | 1399 | "Update me!"); |
michael@0 | 1400 | MOZ_ASSERT(aReader && aRetval); |
michael@0 | 1401 | |
michael@0 | 1402 | nsCString type; |
michael@0 | 1403 | if (!StructuredCloneReadString(aReader, type)) { |
michael@0 | 1404 | return false; |
michael@0 | 1405 | } |
michael@0 | 1406 | CopyUTF8toUTF16(type, aRetval->type); |
michael@0 | 1407 | |
michael@0 | 1408 | nsCString name; |
michael@0 | 1409 | if (!StructuredCloneReadString(aReader, name)) { |
michael@0 | 1410 | return false; |
michael@0 | 1411 | } |
michael@0 | 1412 | CopyUTF8toUTF16(name, aRetval->name); |
michael@0 | 1413 | |
michael@0 | 1414 | return true; |
michael@0 | 1415 | } |
michael@0 | 1416 | |
michael@0 | 1417 | // static |
michael@0 | 1418 | bool |
michael@0 | 1419 | IDBObjectStore::ReadBlobOrFile(JSStructuredCloneReader* aReader, |
michael@0 | 1420 | uint32_t aTag, |
michael@0 | 1421 | BlobOrFileData* aRetval) |
michael@0 | 1422 | { |
michael@0 | 1423 | static_assert(SCTAG_DOM_BLOB == 0xFFFF8001 && |
michael@0 | 1424 | SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xFFFF8002 && |
michael@0 | 1425 | SCTAG_DOM_FILE == 0xFFFF8005, |
michael@0 | 1426 | "Update me!"); |
michael@0 | 1427 | MOZ_ASSERT(aReader && aRetval); |
michael@0 | 1428 | MOZ_ASSERT(aTag == SCTAG_DOM_FILE || |
michael@0 | 1429 | aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE || |
michael@0 | 1430 | aTag == SCTAG_DOM_BLOB); |
michael@0 | 1431 | |
michael@0 | 1432 | aRetval->tag = aTag; |
michael@0 | 1433 | |
michael@0 | 1434 | // If it's not a FileHandle, it's a Blob or a File. |
michael@0 | 1435 | uint64_t size; |
michael@0 | 1436 | if (!JS_ReadBytes(aReader, &size, sizeof(uint64_t))) { |
michael@0 | 1437 | NS_WARNING("Failed to read size!"); |
michael@0 | 1438 | return false; |
michael@0 | 1439 | } |
michael@0 | 1440 | aRetval->size = NativeEndian::swapFromLittleEndian(size); |
michael@0 | 1441 | |
michael@0 | 1442 | nsCString type; |
michael@0 | 1443 | if (!StructuredCloneReadString(aReader, type)) { |
michael@0 | 1444 | return false; |
michael@0 | 1445 | } |
michael@0 | 1446 | CopyUTF8toUTF16(type, aRetval->type); |
michael@0 | 1447 | |
michael@0 | 1448 | // Blobs are done. |
michael@0 | 1449 | if (aTag == SCTAG_DOM_BLOB) { |
michael@0 | 1450 | return true; |
michael@0 | 1451 | } |
michael@0 | 1452 | |
michael@0 | 1453 | NS_ASSERTION(aTag == SCTAG_DOM_FILE || |
michael@0 | 1454 | aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE, "Huh?!"); |
michael@0 | 1455 | |
michael@0 | 1456 | uint64_t lastModifiedDate; |
michael@0 | 1457 | if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE) { |
michael@0 | 1458 | lastModifiedDate = UINT64_MAX; |
michael@0 | 1459 | } |
michael@0 | 1460 | else { |
michael@0 | 1461 | if(!JS_ReadBytes(aReader, &lastModifiedDate, sizeof(lastModifiedDate))) { |
michael@0 | 1462 | NS_WARNING("Failed to read lastModifiedDate"); |
michael@0 | 1463 | return false; |
michael@0 | 1464 | } |
michael@0 | 1465 | lastModifiedDate = NativeEndian::swapFromLittleEndian(lastModifiedDate); |
michael@0 | 1466 | } |
michael@0 | 1467 | aRetval->lastModifiedDate = lastModifiedDate; |
michael@0 | 1468 | |
michael@0 | 1469 | nsCString name; |
michael@0 | 1470 | if (!StructuredCloneReadString(aReader, name)) { |
michael@0 | 1471 | return false; |
michael@0 | 1472 | } |
michael@0 | 1473 | CopyUTF8toUTF16(name, aRetval->name); |
michael@0 | 1474 | |
michael@0 | 1475 | return true; |
michael@0 | 1476 | } |
michael@0 | 1477 | |
michael@0 | 1478 | // static |
michael@0 | 1479 | template <class DeserializationTraits> |
michael@0 | 1480 | JSObject* |
michael@0 | 1481 | IDBObjectStore::StructuredCloneReadCallback(JSContext* aCx, |
michael@0 | 1482 | JSStructuredCloneReader* aReader, |
michael@0 | 1483 | uint32_t aTag, |
michael@0 | 1484 | uint32_t aData, |
michael@0 | 1485 | void* aClosure) |
michael@0 | 1486 | { |
michael@0 | 1487 | // We need to statically assert that our tag values are what we expect |
michael@0 | 1488 | // so that if people accidentally change them they notice. |
michael@0 | 1489 | static_assert(SCTAG_DOM_BLOB == 0xFFFF8001 && |
michael@0 | 1490 | SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE == 0xFFFF8002 && |
michael@0 | 1491 | SCTAG_DOM_FILEHANDLE == 0xFFFF8004 && |
michael@0 | 1492 | SCTAG_DOM_FILE == 0xFFFF8005, |
michael@0 | 1493 | "You changed our structured clone tag values and just ate " |
michael@0 | 1494 | "everyone's IndexedDB data. I hope you are happy."); |
michael@0 | 1495 | |
michael@0 | 1496 | if (aTag == SCTAG_DOM_FILE_WITHOUT_LASTMODIFIEDDATE || |
michael@0 | 1497 | aTag == SCTAG_DOM_FILEHANDLE || |
michael@0 | 1498 | aTag == SCTAG_DOM_BLOB || |
michael@0 | 1499 | aTag == SCTAG_DOM_FILE) { |
michael@0 | 1500 | StructuredCloneReadInfo* cloneReadInfo = |
michael@0 | 1501 | reinterpret_cast<StructuredCloneReadInfo*>(aClosure); |
michael@0 | 1502 | |
michael@0 | 1503 | if (aData >= cloneReadInfo->mFiles.Length()) { |
michael@0 | 1504 | NS_ERROR("Bad blob index!"); |
michael@0 | 1505 | return nullptr; |
michael@0 | 1506 | } |
michael@0 | 1507 | |
michael@0 | 1508 | StructuredCloneFile& file = cloneReadInfo->mFiles[aData]; |
michael@0 | 1509 | IDBDatabase* database = cloneReadInfo->mDatabase; |
michael@0 | 1510 | |
michael@0 | 1511 | if (aTag == SCTAG_DOM_FILEHANDLE) { |
michael@0 | 1512 | FileHandleData data; |
michael@0 | 1513 | if (!ReadFileHandle(aReader, &data)) { |
michael@0 | 1514 | return nullptr; |
michael@0 | 1515 | } |
michael@0 | 1516 | |
michael@0 | 1517 | return DeserializationTraits::CreateAndWrapFileHandle(aCx, database, |
michael@0 | 1518 | file, data); |
michael@0 | 1519 | } |
michael@0 | 1520 | |
michael@0 | 1521 | BlobOrFileData data; |
michael@0 | 1522 | if (!ReadBlobOrFile(aReader, aTag, &data)) { |
michael@0 | 1523 | return nullptr; |
michael@0 | 1524 | } |
michael@0 | 1525 | |
michael@0 | 1526 | return DeserializationTraits::CreateAndWrapBlobOrFile(aCx, database, |
michael@0 | 1527 | file, data); |
michael@0 | 1528 | } |
michael@0 | 1529 | |
michael@0 | 1530 | const JSStructuredCloneCallbacks* runtimeCallbacks = |
michael@0 | 1531 | js::GetContextStructuredCloneCallbacks(aCx); |
michael@0 | 1532 | |
michael@0 | 1533 | if (runtimeCallbacks) { |
michael@0 | 1534 | return runtimeCallbacks->read(aCx, aReader, aTag, aData, nullptr); |
michael@0 | 1535 | } |
michael@0 | 1536 | |
michael@0 | 1537 | return nullptr; |
michael@0 | 1538 | } |
michael@0 | 1539 | |
michael@0 | 1540 | // static |
michael@0 | 1541 | bool |
michael@0 | 1542 | IDBObjectStore::StructuredCloneWriteCallback(JSContext* aCx, |
michael@0 | 1543 | JSStructuredCloneWriter* aWriter, |
michael@0 | 1544 | JS::Handle<JSObject*> aObj, |
michael@0 | 1545 | void* aClosure) |
michael@0 | 1546 | { |
michael@0 | 1547 | StructuredCloneWriteInfo* cloneWriteInfo = |
michael@0 | 1548 | reinterpret_cast<StructuredCloneWriteInfo*>(aClosure); |
michael@0 | 1549 | |
michael@0 | 1550 | if (JS_GetClass(aObj) == &sDummyPropJSClass) { |
michael@0 | 1551 | NS_ASSERTION(cloneWriteInfo->mOffsetToKeyProp == 0, |
michael@0 | 1552 | "We should not have been here before!"); |
michael@0 | 1553 | cloneWriteInfo->mOffsetToKeyProp = js_GetSCOffset(aWriter); |
michael@0 | 1554 | |
michael@0 | 1555 | uint64_t value = 0; |
michael@0 | 1556 | // Omit endian swap |
michael@0 | 1557 | return JS_WriteBytes(aWriter, &value, sizeof(value)); |
michael@0 | 1558 | } |
michael@0 | 1559 | |
michael@0 | 1560 | IDBTransaction* transaction = cloneWriteInfo->mTransaction; |
michael@0 | 1561 | FileManager* fileManager = transaction->Database()->Manager(); |
michael@0 | 1562 | |
michael@0 | 1563 | file::FileHandle* fileHandle = nullptr; |
michael@0 | 1564 | if (NS_SUCCEEDED(UNWRAP_OBJECT(FileHandle, aObj, fileHandle))) { |
michael@0 | 1565 | nsRefPtr<FileInfo> fileInfo = fileHandle->GetFileInfo(); |
michael@0 | 1566 | |
michael@0 | 1567 | // Throw when trying to store non IDB file handles or IDB file handles |
michael@0 | 1568 | // across databases. |
michael@0 | 1569 | if (!fileInfo || fileInfo->Manager() != fileManager) { |
michael@0 | 1570 | return false; |
michael@0 | 1571 | } |
michael@0 | 1572 | |
michael@0 | 1573 | NS_ConvertUTF16toUTF8 convType(fileHandle->Type()); |
michael@0 | 1574 | uint32_t convTypeLength = |
michael@0 | 1575 | NativeEndian::swapToLittleEndian(convType.Length()); |
michael@0 | 1576 | |
michael@0 | 1577 | NS_ConvertUTF16toUTF8 convName(fileHandle->Name()); |
michael@0 | 1578 | uint32_t convNameLength = |
michael@0 | 1579 | NativeEndian::swapToLittleEndian(convName.Length()); |
michael@0 | 1580 | |
michael@0 | 1581 | if (!JS_WriteUint32Pair(aWriter, SCTAG_DOM_FILEHANDLE, |
michael@0 | 1582 | cloneWriteInfo->mFiles.Length()) || |
michael@0 | 1583 | !JS_WriteBytes(aWriter, &convTypeLength, sizeof(uint32_t)) || |
michael@0 | 1584 | !JS_WriteBytes(aWriter, convType.get(), convType.Length()) || |
michael@0 | 1585 | !JS_WriteBytes(aWriter, &convNameLength, sizeof(uint32_t)) || |
michael@0 | 1586 | !JS_WriteBytes(aWriter, convName.get(), convName.Length())) { |
michael@0 | 1587 | return false; |
michael@0 | 1588 | } |
michael@0 | 1589 | |
michael@0 | 1590 | StructuredCloneFile* file = cloneWriteInfo->mFiles.AppendElement(); |
michael@0 | 1591 | file->mFileInfo = fileInfo.forget(); |
michael@0 | 1592 | |
michael@0 | 1593 | return true; |
michael@0 | 1594 | } |
michael@0 | 1595 | |
michael@0 | 1596 | nsCOMPtr<nsIXPConnectWrappedNative> wrappedNative; |
michael@0 | 1597 | nsContentUtils::XPConnect()-> |
michael@0 | 1598 | GetWrappedNativeOfJSObject(aCx, aObj, getter_AddRefs(wrappedNative)); |
michael@0 | 1599 | |
michael@0 | 1600 | if (wrappedNative) { |
michael@0 | 1601 | nsISupports* supports = wrappedNative->Native(); |
michael@0 | 1602 | |
michael@0 | 1603 | nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(supports); |
michael@0 | 1604 | if (blob) { |
michael@0 | 1605 | nsCOMPtr<nsIInputStream> inputStream; |
michael@0 | 1606 | |
michael@0 | 1607 | // Check if it is a blob created from this db or the blob was already |
michael@0 | 1608 | // stored in this db |
michael@0 | 1609 | nsRefPtr<FileInfo> fileInfo = transaction->GetFileInfo(blob); |
michael@0 | 1610 | if (!fileInfo && fileManager) { |
michael@0 | 1611 | fileInfo = blob->GetFileInfo(fileManager); |
michael@0 | 1612 | |
michael@0 | 1613 | if (!fileInfo) { |
michael@0 | 1614 | fileInfo = fileManager->GetNewFileInfo(); |
michael@0 | 1615 | if (!fileInfo) { |
michael@0 | 1616 | NS_WARNING("Failed to get new file info!"); |
michael@0 | 1617 | return false; |
michael@0 | 1618 | } |
michael@0 | 1619 | |
michael@0 | 1620 | if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) { |
michael@0 | 1621 | NS_WARNING("Failed to get internal steam!"); |
michael@0 | 1622 | return false; |
michael@0 | 1623 | } |
michael@0 | 1624 | |
michael@0 | 1625 | transaction->AddFileInfo(blob, fileInfo); |
michael@0 | 1626 | } |
michael@0 | 1627 | } |
michael@0 | 1628 | |
michael@0 | 1629 | uint64_t size; |
michael@0 | 1630 | if (NS_FAILED(blob->GetSize(&size))) { |
michael@0 | 1631 | NS_WARNING("Failed to get size!"); |
michael@0 | 1632 | return false; |
michael@0 | 1633 | } |
michael@0 | 1634 | size = NativeEndian::swapToLittleEndian(size); |
michael@0 | 1635 | |
michael@0 | 1636 | nsString type; |
michael@0 | 1637 | if (NS_FAILED(blob->GetType(type))) { |
michael@0 | 1638 | NS_WARNING("Failed to get type!"); |
michael@0 | 1639 | return false; |
michael@0 | 1640 | } |
michael@0 | 1641 | NS_ConvertUTF16toUTF8 convType(type); |
michael@0 | 1642 | uint32_t convTypeLength = |
michael@0 | 1643 | NativeEndian::swapToLittleEndian(convType.Length()); |
michael@0 | 1644 | |
michael@0 | 1645 | nsCOMPtr<nsIDOMFile> file = do_QueryInterface(blob); |
michael@0 | 1646 | |
michael@0 | 1647 | if (!JS_WriteUint32Pair(aWriter, file ? SCTAG_DOM_FILE : SCTAG_DOM_BLOB, |
michael@0 | 1648 | cloneWriteInfo->mFiles.Length()) || |
michael@0 | 1649 | !JS_WriteBytes(aWriter, &size, sizeof(size)) || |
michael@0 | 1650 | !JS_WriteBytes(aWriter, &convTypeLength, sizeof(convTypeLength)) || |
michael@0 | 1651 | !JS_WriteBytes(aWriter, convType.get(), convType.Length())) { |
michael@0 | 1652 | return false; |
michael@0 | 1653 | } |
michael@0 | 1654 | |
michael@0 | 1655 | if (file) { |
michael@0 | 1656 | uint64_t lastModifiedDate = 0; |
michael@0 | 1657 | if (NS_FAILED(file->GetMozLastModifiedDate(&lastModifiedDate))) { |
michael@0 | 1658 | NS_WARNING("Failed to get last modified date!"); |
michael@0 | 1659 | return false; |
michael@0 | 1660 | } |
michael@0 | 1661 | |
michael@0 | 1662 | lastModifiedDate = NativeEndian::swapToLittleEndian(lastModifiedDate); |
michael@0 | 1663 | |
michael@0 | 1664 | nsString name; |
michael@0 | 1665 | if (NS_FAILED(file->GetName(name))) { |
michael@0 | 1666 | NS_WARNING("Failed to get name!"); |
michael@0 | 1667 | return false; |
michael@0 | 1668 | } |
michael@0 | 1669 | NS_ConvertUTF16toUTF8 convName(name); |
michael@0 | 1670 | uint32_t convNameLength = |
michael@0 | 1671 | NativeEndian::swapToLittleEndian(convName.Length()); |
michael@0 | 1672 | |
michael@0 | 1673 | if (!JS_WriteBytes(aWriter, &lastModifiedDate, sizeof(lastModifiedDate)) || |
michael@0 | 1674 | !JS_WriteBytes(aWriter, &convNameLength, sizeof(convNameLength)) || |
michael@0 | 1675 | !JS_WriteBytes(aWriter, convName.get(), convName.Length())) { |
michael@0 | 1676 | return false; |
michael@0 | 1677 | } |
michael@0 | 1678 | } |
michael@0 | 1679 | |
michael@0 | 1680 | StructuredCloneFile* cloneFile = cloneWriteInfo->mFiles.AppendElement(); |
michael@0 | 1681 | cloneFile->mFile = blob.forget(); |
michael@0 | 1682 | cloneFile->mFileInfo = fileInfo.forget(); |
michael@0 | 1683 | cloneFile->mInputStream = inputStream.forget(); |
michael@0 | 1684 | |
michael@0 | 1685 | return true; |
michael@0 | 1686 | } |
michael@0 | 1687 | } |
michael@0 | 1688 | |
michael@0 | 1689 | // try using the runtime callbacks |
michael@0 | 1690 | const JSStructuredCloneCallbacks* runtimeCallbacks = |
michael@0 | 1691 | js::GetContextStructuredCloneCallbacks(aCx); |
michael@0 | 1692 | if (runtimeCallbacks) { |
michael@0 | 1693 | return runtimeCallbacks->write(aCx, aWriter, aObj, nullptr); |
michael@0 | 1694 | } |
michael@0 | 1695 | |
michael@0 | 1696 | return false; |
michael@0 | 1697 | } |
michael@0 | 1698 | |
michael@0 | 1699 | // static |
michael@0 | 1700 | nsresult |
michael@0 | 1701 | IDBObjectStore::ConvertFileIdsToArray(const nsAString& aFileIds, |
michael@0 | 1702 | nsTArray<int64_t>& aResult) |
michael@0 | 1703 | { |
michael@0 | 1704 | nsCharSeparatedTokenizerTemplate<IgnoreNothing> tokenizer(aFileIds, ' '); |
michael@0 | 1705 | |
michael@0 | 1706 | while (tokenizer.hasMoreTokens()) { |
michael@0 | 1707 | nsString token(tokenizer.nextToken()); |
michael@0 | 1708 | |
michael@0 | 1709 | NS_ASSERTION(!token.IsEmpty(), "Should be a valid id!"); |
michael@0 | 1710 | |
michael@0 | 1711 | nsresult rv; |
michael@0 | 1712 | int32_t id = token.ToInteger(&rv); |
michael@0 | 1713 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1714 | |
michael@0 | 1715 | int64_t* element = aResult.AppendElement(); |
michael@0 | 1716 | *element = id; |
michael@0 | 1717 | } |
michael@0 | 1718 | |
michael@0 | 1719 | return NS_OK; |
michael@0 | 1720 | } |
michael@0 | 1721 | |
michael@0 | 1722 | // static |
michael@0 | 1723 | void |
michael@0 | 1724 | IDBObjectStore::ConvertActorsToBlobs( |
michael@0 | 1725 | const InfallibleTArray<PBlobChild*>& aActors, |
michael@0 | 1726 | nsTArray<StructuredCloneFile>& aFiles) |
michael@0 | 1727 | { |
michael@0 | 1728 | NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 1729 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1730 | NS_ASSERTION(aFiles.IsEmpty(), "Should be empty!"); |
michael@0 | 1731 | |
michael@0 | 1732 | if (!aActors.IsEmpty()) { |
michael@0 | 1733 | NS_ASSERTION(ContentChild::GetSingleton(), "This should never be null!"); |
michael@0 | 1734 | |
michael@0 | 1735 | uint32_t length = aActors.Length(); |
michael@0 | 1736 | aFiles.SetCapacity(length); |
michael@0 | 1737 | |
michael@0 | 1738 | for (uint32_t index = 0; index < length; index++) { |
michael@0 | 1739 | BlobChild* actor = static_cast<BlobChild*>(aActors[index]); |
michael@0 | 1740 | |
michael@0 | 1741 | StructuredCloneFile* file = aFiles.AppendElement(); |
michael@0 | 1742 | file->mFile = actor->GetBlob(); |
michael@0 | 1743 | } |
michael@0 | 1744 | } |
michael@0 | 1745 | } |
michael@0 | 1746 | |
michael@0 | 1747 | // static |
michael@0 | 1748 | nsresult |
michael@0 | 1749 | IDBObjectStore::ConvertBlobsToActors( |
michael@0 | 1750 | ContentParent* aContentParent, |
michael@0 | 1751 | FileManager* aFileManager, |
michael@0 | 1752 | const nsTArray<StructuredCloneFile>& aFiles, |
michael@0 | 1753 | InfallibleTArray<PBlobParent*>& aActors) |
michael@0 | 1754 | { |
michael@0 | 1755 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 1756 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1757 | NS_ASSERTION(aContentParent, "Null contentParent!"); |
michael@0 | 1758 | NS_ASSERTION(aFileManager, "Null file manager!"); |
michael@0 | 1759 | |
michael@0 | 1760 | if (!aFiles.IsEmpty()) { |
michael@0 | 1761 | nsCOMPtr<nsIFile> directory = aFileManager->GetDirectory(); |
michael@0 | 1762 | if (!directory) { |
michael@0 | 1763 | IDB_WARNING("Failed to get directory!"); |
michael@0 | 1764 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 1765 | } |
michael@0 | 1766 | |
michael@0 | 1767 | uint32_t fileCount = aFiles.Length(); |
michael@0 | 1768 | aActors.SetCapacity(fileCount); |
michael@0 | 1769 | |
michael@0 | 1770 | for (uint32_t index = 0; index < fileCount; index++) { |
michael@0 | 1771 | const StructuredCloneFile& file = aFiles[index]; |
michael@0 | 1772 | NS_ASSERTION(file.mFileInfo, "This should never be null!"); |
michael@0 | 1773 | |
michael@0 | 1774 | nsCOMPtr<nsIFile> nativeFile = |
michael@0 | 1775 | aFileManager->GetFileForId(directory, file.mFileInfo->Id()); |
michael@0 | 1776 | if (!nativeFile) { |
michael@0 | 1777 | IDB_WARNING("Failed to get file!"); |
michael@0 | 1778 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 1779 | } |
michael@0 | 1780 | |
michael@0 | 1781 | nsCOMPtr<nsIDOMBlob> blob = new nsDOMFileFile(nativeFile, file.mFileInfo); |
michael@0 | 1782 | |
michael@0 | 1783 | BlobParent* actor = |
michael@0 | 1784 | aContentParent->GetOrCreateActorForBlob(blob); |
michael@0 | 1785 | if (!actor) { |
michael@0 | 1786 | // This can only fail if the child has crashed. |
michael@0 | 1787 | IDB_REPORT_INTERNAL_ERR(); |
michael@0 | 1788 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 1789 | } |
michael@0 | 1790 | |
michael@0 | 1791 | aActors.AppendElement(actor); |
michael@0 | 1792 | } |
michael@0 | 1793 | } |
michael@0 | 1794 | |
michael@0 | 1795 | return NS_OK; |
michael@0 | 1796 | } |
michael@0 | 1797 | |
michael@0 | 1798 | IDBObjectStore::IDBObjectStore() |
michael@0 | 1799 | : mId(INT64_MIN), |
michael@0 | 1800 | mKeyPath(0), |
michael@0 | 1801 | mCachedKeyPath(JSVAL_VOID), |
michael@0 | 1802 | mRooted(false), |
michael@0 | 1803 | mAutoIncrement(false), |
michael@0 | 1804 | mActorChild(nullptr), |
michael@0 | 1805 | mActorParent(nullptr) |
michael@0 | 1806 | { |
michael@0 | 1807 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1808 | |
michael@0 | 1809 | SetIsDOMBinding(); |
michael@0 | 1810 | } |
michael@0 | 1811 | |
michael@0 | 1812 | IDBObjectStore::~IDBObjectStore() |
michael@0 | 1813 | { |
michael@0 | 1814 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1815 | NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!"); |
michael@0 | 1816 | if (mActorChild) { |
michael@0 | 1817 | NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 1818 | mActorChild->Send__delete__(mActorChild); |
michael@0 | 1819 | NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!"); |
michael@0 | 1820 | } |
michael@0 | 1821 | |
michael@0 | 1822 | if (mRooted) { |
michael@0 | 1823 | mCachedKeyPath = JSVAL_VOID; |
michael@0 | 1824 | mozilla::DropJSObjects(this); |
michael@0 | 1825 | } |
michael@0 | 1826 | } |
michael@0 | 1827 | |
michael@0 | 1828 | nsresult |
michael@0 | 1829 | IDBObjectStore::GetAddInfo(JSContext* aCx, |
michael@0 | 1830 | JS::Handle<JS::Value> aValue, |
michael@0 | 1831 | JS::Handle<JS::Value> aKeyVal, |
michael@0 | 1832 | StructuredCloneWriteInfo& aCloneWriteInfo, |
michael@0 | 1833 | Key& aKey, |
michael@0 | 1834 | nsTArray<IndexUpdateInfo>& aUpdateInfoArray) |
michael@0 | 1835 | { |
michael@0 | 1836 | nsresult rv; |
michael@0 | 1837 | |
michael@0 | 1838 | // Return DATA_ERR if a key was passed in and this objectStore uses inline |
michael@0 | 1839 | // keys. |
michael@0 | 1840 | if (!JSVAL_IS_VOID(aKeyVal) && HasValidKeyPath()) { |
michael@0 | 1841 | return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; |
michael@0 | 1842 | } |
michael@0 | 1843 | |
michael@0 | 1844 | JSAutoRequest ar(aCx); |
michael@0 | 1845 | |
michael@0 | 1846 | if (!HasValidKeyPath()) { |
michael@0 | 1847 | // Out-of-line keys must be passed in. |
michael@0 | 1848 | rv = aKey.SetFromJSVal(aCx, aKeyVal); |
michael@0 | 1849 | if (NS_FAILED(rv)) { |
michael@0 | 1850 | return rv; |
michael@0 | 1851 | } |
michael@0 | 1852 | } |
michael@0 | 1853 | else if (!mAutoIncrement) { |
michael@0 | 1854 | rv = GetKeyPath().ExtractKey(aCx, aValue, aKey); |
michael@0 | 1855 | if (NS_FAILED(rv)) { |
michael@0 | 1856 | return rv; |
michael@0 | 1857 | } |
michael@0 | 1858 | } |
michael@0 | 1859 | |
michael@0 | 1860 | // Return DATA_ERR if no key was specified this isn't an autoIncrement |
michael@0 | 1861 | // objectStore. |
michael@0 | 1862 | if (aKey.IsUnset() && !mAutoIncrement) { |
michael@0 | 1863 | return NS_ERROR_DOM_INDEXEDDB_DATA_ERR; |
michael@0 | 1864 | } |
michael@0 | 1865 | |
michael@0 | 1866 | // Figure out indexes and the index values to update here. |
michael@0 | 1867 | uint32_t count = mInfo->indexes.Length(); |
michael@0 | 1868 | aUpdateInfoArray.SetCapacity(count); // Pretty good estimate |
michael@0 | 1869 | for (uint32_t indexesIndex = 0; indexesIndex < count; indexesIndex++) { |
michael@0 | 1870 | const IndexInfo& indexInfo = mInfo->indexes[indexesIndex]; |
michael@0 | 1871 | |
michael@0 | 1872 | rv = AppendIndexUpdateInfo(indexInfo.id, indexInfo.keyPath, |
michael@0 | 1873 | indexInfo.unique, indexInfo.multiEntry, aCx, |
michael@0 | 1874 | aValue, aUpdateInfoArray); |
michael@0 | 1875 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 1876 | } |
michael@0 | 1877 | |
michael@0 | 1878 | GetAddInfoClosure data = {this, aCloneWriteInfo, aValue}; |
michael@0 | 1879 | |
michael@0 | 1880 | if (mAutoIncrement && HasValidKeyPath()) { |
michael@0 | 1881 | NS_ASSERTION(aKey.IsUnset(), "Shouldn't have gotten the key yet!"); |
michael@0 | 1882 | |
michael@0 | 1883 | rv = GetKeyPath().ExtractOrCreateKey(aCx, aValue, aKey, |
michael@0 | 1884 | &GetAddInfoCallback, &data); |
michael@0 | 1885 | } |
michael@0 | 1886 | else { |
michael@0 | 1887 | rv = GetAddInfoCallback(aCx, &data); |
michael@0 | 1888 | } |
michael@0 | 1889 | |
michael@0 | 1890 | return rv; |
michael@0 | 1891 | } |
michael@0 | 1892 | |
michael@0 | 1893 | already_AddRefed<IDBRequest> |
michael@0 | 1894 | IDBObjectStore::AddOrPut(JSContext* aCx, JS::Handle<JS::Value> aValue, |
michael@0 | 1895 | JS::Handle<JS::Value> aKey, |
michael@0 | 1896 | bool aOverwrite, ErrorResult& aRv) |
michael@0 | 1897 | { |
michael@0 | 1898 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1899 | |
michael@0 | 1900 | if (!mTransaction->IsOpen()) { |
michael@0 | 1901 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 1902 | return nullptr; |
michael@0 | 1903 | } |
michael@0 | 1904 | |
michael@0 | 1905 | if (!IsWriteAllowed()) { |
michael@0 | 1906 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); |
michael@0 | 1907 | return nullptr; |
michael@0 | 1908 | } |
michael@0 | 1909 | |
michael@0 | 1910 | StructuredCloneWriteInfo cloneWriteInfo; |
michael@0 | 1911 | Key key; |
michael@0 | 1912 | nsTArray<IndexUpdateInfo> updateInfo; |
michael@0 | 1913 | |
michael@0 | 1914 | JS::Rooted<JS::Value> value(aCx, aValue); |
michael@0 | 1915 | aRv = GetAddInfo(aCx, value, aKey, cloneWriteInfo, key, updateInfo); |
michael@0 | 1916 | if (aRv.Failed()) { |
michael@0 | 1917 | return nullptr; |
michael@0 | 1918 | } |
michael@0 | 1919 | |
michael@0 | 1920 | nsRefPtr<IDBRequest> request = GenerateRequest(this); |
michael@0 | 1921 | if (!request) { |
michael@0 | 1922 | IDB_WARNING("Failed to generate request!"); |
michael@0 | 1923 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 1924 | return nullptr; |
michael@0 | 1925 | } |
michael@0 | 1926 | |
michael@0 | 1927 | nsRefPtr<AddHelper> helper = |
michael@0 | 1928 | new AddHelper(mTransaction, request, this, Move(cloneWriteInfo), key, |
michael@0 | 1929 | aOverwrite, updateInfo); |
michael@0 | 1930 | |
michael@0 | 1931 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 1932 | if (NS_FAILED(rv)) { |
michael@0 | 1933 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 1934 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 1935 | return nullptr; |
michael@0 | 1936 | } |
michael@0 | 1937 | |
michael@0 | 1938 | #ifdef IDB_PROFILER_USE_MARKS |
michael@0 | 1939 | if (aOverwrite) { |
michael@0 | 1940 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 1941 | "database(%s).transaction(%s).objectStore(%s).%s(%s)", |
michael@0 | 1942 | "IDBRequest[%llu] MT IDBObjectStore.put()", |
michael@0 | 1943 | request->GetSerialNumber(), |
michael@0 | 1944 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 1945 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 1946 | IDB_PROFILER_STRING(this), |
michael@0 | 1947 | key.IsUnset() ? "" : IDB_PROFILER_STRING(key)); |
michael@0 | 1948 | } |
michael@0 | 1949 | else { |
michael@0 | 1950 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 1951 | "database(%s).transaction(%s).objectStore(%s).add(%s)", |
michael@0 | 1952 | "IDBRequest[%llu] MT IDBObjectStore.add()", |
michael@0 | 1953 | request->GetSerialNumber(), |
michael@0 | 1954 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 1955 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 1956 | IDB_PROFILER_STRING(this), |
michael@0 | 1957 | key.IsUnset() ? "" : IDB_PROFILER_STRING(key)); |
michael@0 | 1958 | } |
michael@0 | 1959 | #endif |
michael@0 | 1960 | |
michael@0 | 1961 | return request.forget(); |
michael@0 | 1962 | } |
michael@0 | 1963 | |
michael@0 | 1964 | nsresult |
michael@0 | 1965 | IDBObjectStore::AddOrPutInternal( |
michael@0 | 1966 | const SerializedStructuredCloneWriteInfo& aCloneWriteInfo, |
michael@0 | 1967 | const Key& aKey, |
michael@0 | 1968 | const InfallibleTArray<IndexUpdateInfo>& aUpdateInfoArray, |
michael@0 | 1969 | const nsTArray<nsCOMPtr<nsIDOMBlob> >& aBlobs, |
michael@0 | 1970 | bool aOverwrite, |
michael@0 | 1971 | IDBRequest** _retval) |
michael@0 | 1972 | { |
michael@0 | 1973 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 1974 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 1975 | |
michael@0 | 1976 | if (!mTransaction->IsOpen()) { |
michael@0 | 1977 | return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR; |
michael@0 | 1978 | } |
michael@0 | 1979 | |
michael@0 | 1980 | if (!IsWriteAllowed()) { |
michael@0 | 1981 | return NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR; |
michael@0 | 1982 | } |
michael@0 | 1983 | |
michael@0 | 1984 | nsRefPtr<IDBRequest> request = GenerateRequest(this); |
michael@0 | 1985 | IDB_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 1986 | |
michael@0 | 1987 | StructuredCloneWriteInfo cloneWriteInfo; |
michael@0 | 1988 | if (!cloneWriteInfo.SetFromSerialized(aCloneWriteInfo)) { |
michael@0 | 1989 | IDB_WARNING("Failed to copy structured clone buffer!"); |
michael@0 | 1990 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 1991 | } |
michael@0 | 1992 | |
michael@0 | 1993 | if (!aBlobs.IsEmpty()) { |
michael@0 | 1994 | FileManager* fileManager = Transaction()->Database()->Manager(); |
michael@0 | 1995 | NS_ASSERTION(fileManager, "Null file manager?!"); |
michael@0 | 1996 | |
michael@0 | 1997 | uint32_t length = aBlobs.Length(); |
michael@0 | 1998 | cloneWriteInfo.mFiles.SetCapacity(length); |
michael@0 | 1999 | |
michael@0 | 2000 | for (uint32_t index = 0; index < length; index++) { |
michael@0 | 2001 | const nsCOMPtr<nsIDOMBlob>& blob = aBlobs[index]; |
michael@0 | 2002 | |
michael@0 | 2003 | nsCOMPtr<nsIInputStream> inputStream; |
michael@0 | 2004 | |
michael@0 | 2005 | nsRefPtr<FileInfo> fileInfo = Transaction()->GetFileInfo(blob); |
michael@0 | 2006 | if (!fileInfo) { |
michael@0 | 2007 | fileInfo = blob->GetFileInfo(fileManager); |
michael@0 | 2008 | |
michael@0 | 2009 | if (!fileInfo) { |
michael@0 | 2010 | fileInfo = fileManager->GetNewFileInfo(); |
michael@0 | 2011 | if (!fileInfo) { |
michael@0 | 2012 | IDB_WARNING("Failed to get new file info!"); |
michael@0 | 2013 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 2014 | } |
michael@0 | 2015 | |
michael@0 | 2016 | if (NS_FAILED(blob->GetInternalStream(getter_AddRefs(inputStream)))) { |
michael@0 | 2017 | IDB_WARNING("Failed to get internal steam!"); |
michael@0 | 2018 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 2019 | } |
michael@0 | 2020 | |
michael@0 | 2021 | // XXXbent This is where we should send a message back to the child to |
michael@0 | 2022 | // update the file id. |
michael@0 | 2023 | |
michael@0 | 2024 | Transaction()->AddFileInfo(blob, fileInfo); |
michael@0 | 2025 | } |
michael@0 | 2026 | } |
michael@0 | 2027 | |
michael@0 | 2028 | StructuredCloneFile* file = cloneWriteInfo.mFiles.AppendElement(); |
michael@0 | 2029 | file->mFile = blob; |
michael@0 | 2030 | file->mFileInfo.swap(fileInfo); |
michael@0 | 2031 | file->mInputStream.swap(inputStream); |
michael@0 | 2032 | } |
michael@0 | 2033 | } |
michael@0 | 2034 | |
michael@0 | 2035 | Key key(aKey); |
michael@0 | 2036 | |
michael@0 | 2037 | nsTArray<IndexUpdateInfo> updateInfo(aUpdateInfoArray); |
michael@0 | 2038 | |
michael@0 | 2039 | nsRefPtr<AddHelper> helper = |
michael@0 | 2040 | new AddHelper(mTransaction, request, this, Move(cloneWriteInfo), key, |
michael@0 | 2041 | aOverwrite, updateInfo); |
michael@0 | 2042 | |
michael@0 | 2043 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2044 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2045 | |
michael@0 | 2046 | #ifdef IDB_PROFILER_USE_MARKS |
michael@0 | 2047 | if (aOverwrite) { |
michael@0 | 2048 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 2049 | "database(%s).transaction(%s).objectStore(%s).%s(%s)", |
michael@0 | 2050 | "IDBRequest[%llu] MT IDBObjectStore.put()", |
michael@0 | 2051 | request->GetSerialNumber(), |
michael@0 | 2052 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2053 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2054 | IDB_PROFILER_STRING(this), |
michael@0 | 2055 | key.IsUnset() ? "" : IDB_PROFILER_STRING(key)); |
michael@0 | 2056 | } |
michael@0 | 2057 | else { |
michael@0 | 2058 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 2059 | "database(%s).transaction(%s).objectStore(%s).add(%s)", |
michael@0 | 2060 | "IDBRequest[%llu] MT IDBObjectStore.add()", |
michael@0 | 2061 | request->GetSerialNumber(), |
michael@0 | 2062 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2063 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2064 | IDB_PROFILER_STRING(this), |
michael@0 | 2065 | key.IsUnset() ? "" : IDB_PROFILER_STRING(key)); |
michael@0 | 2066 | } |
michael@0 | 2067 | #endif |
michael@0 | 2068 | |
michael@0 | 2069 | request.forget(_retval); |
michael@0 | 2070 | return NS_OK; |
michael@0 | 2071 | } |
michael@0 | 2072 | |
michael@0 | 2073 | already_AddRefed<IDBRequest> |
michael@0 | 2074 | IDBObjectStore::GetInternal(IDBKeyRange* aKeyRange, ErrorResult& aRv) |
michael@0 | 2075 | { |
michael@0 | 2076 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2077 | NS_ASSERTION(aKeyRange, "Null pointer!"); |
michael@0 | 2078 | |
michael@0 | 2079 | if (!mTransaction->IsOpen()) { |
michael@0 | 2080 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2081 | return nullptr; |
michael@0 | 2082 | } |
michael@0 | 2083 | |
michael@0 | 2084 | nsRefPtr<IDBRequest> request = GenerateRequest(this); |
michael@0 | 2085 | if (!request) { |
michael@0 | 2086 | IDB_WARNING("Failed to generate request!"); |
michael@0 | 2087 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2088 | return nullptr; |
michael@0 | 2089 | } |
michael@0 | 2090 | |
michael@0 | 2091 | nsRefPtr<GetHelper> helper = |
michael@0 | 2092 | new GetHelper(mTransaction, request, this, aKeyRange); |
michael@0 | 2093 | |
michael@0 | 2094 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2095 | if (NS_FAILED(rv)) { |
michael@0 | 2096 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 2097 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2098 | return nullptr; |
michael@0 | 2099 | } |
michael@0 | 2100 | |
michael@0 | 2101 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 2102 | "database(%s).transaction(%s).objectStore(%s).get(%s)", |
michael@0 | 2103 | "IDBRequest[%llu] MT IDBObjectStore.get()", |
michael@0 | 2104 | request->GetSerialNumber(), |
michael@0 | 2105 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2106 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2107 | IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange)); |
michael@0 | 2108 | |
michael@0 | 2109 | return request.forget(); |
michael@0 | 2110 | } |
michael@0 | 2111 | |
michael@0 | 2112 | already_AddRefed<IDBRequest> |
michael@0 | 2113 | IDBObjectStore::GetAllInternal(IDBKeyRange* aKeyRange, |
michael@0 | 2114 | uint32_t aLimit, ErrorResult& aRv) |
michael@0 | 2115 | { |
michael@0 | 2116 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2117 | |
michael@0 | 2118 | if (!mTransaction->IsOpen()) { |
michael@0 | 2119 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2120 | return nullptr; |
michael@0 | 2121 | } |
michael@0 | 2122 | |
michael@0 | 2123 | nsRefPtr<IDBRequest> request = GenerateRequest(this); |
michael@0 | 2124 | if (!request) { |
michael@0 | 2125 | IDB_WARNING("Failed to generate request!"); |
michael@0 | 2126 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2127 | return nullptr; |
michael@0 | 2128 | } |
michael@0 | 2129 | |
michael@0 | 2130 | nsRefPtr<GetAllHelper> helper = |
michael@0 | 2131 | new GetAllHelper(mTransaction, request, this, aKeyRange, aLimit); |
michael@0 | 2132 | |
michael@0 | 2133 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2134 | if (NS_FAILED(rv)) { |
michael@0 | 2135 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 2136 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2137 | return nullptr; |
michael@0 | 2138 | } |
michael@0 | 2139 | |
michael@0 | 2140 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 2141 | "database(%s).transaction(%s).objectStore(%s)." |
michael@0 | 2142 | "getAll(%s, %lu)", |
michael@0 | 2143 | "IDBRequest[%llu] MT IDBObjectStore.getAll()", |
michael@0 | 2144 | request->GetSerialNumber(), |
michael@0 | 2145 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2146 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2147 | IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange), |
michael@0 | 2148 | aLimit); |
michael@0 | 2149 | |
michael@0 | 2150 | return request.forget(); |
michael@0 | 2151 | } |
michael@0 | 2152 | |
michael@0 | 2153 | already_AddRefed<IDBRequest> |
michael@0 | 2154 | IDBObjectStore::GetAllKeysInternal(IDBKeyRange* aKeyRange, uint32_t aLimit, |
michael@0 | 2155 | ErrorResult& aRv) |
michael@0 | 2156 | { |
michael@0 | 2157 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2158 | |
michael@0 | 2159 | if (!mTransaction->IsOpen()) { |
michael@0 | 2160 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2161 | return nullptr; |
michael@0 | 2162 | } |
michael@0 | 2163 | |
michael@0 | 2164 | nsRefPtr<IDBRequest> request = GenerateRequest(this); |
michael@0 | 2165 | if (!request) { |
michael@0 | 2166 | IDB_WARNING("Failed to generate request!"); |
michael@0 | 2167 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2168 | return nullptr; |
michael@0 | 2169 | } |
michael@0 | 2170 | |
michael@0 | 2171 | nsRefPtr<GetAllKeysHelper> helper = |
michael@0 | 2172 | new GetAllKeysHelper(mTransaction, request, this, aKeyRange, aLimit); |
michael@0 | 2173 | |
michael@0 | 2174 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2175 | if (NS_FAILED(rv)) { |
michael@0 | 2176 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 2177 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2178 | return nullptr; |
michael@0 | 2179 | } |
michael@0 | 2180 | |
michael@0 | 2181 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 2182 | "database(%s).transaction(%s).objectStore(%s)." |
michael@0 | 2183 | "getAllKeys(%s, %lu)", |
michael@0 | 2184 | "IDBRequest[%llu] MT IDBObjectStore.getAllKeys()", |
michael@0 | 2185 | request->GetSerialNumber(), |
michael@0 | 2186 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2187 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2188 | IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange), |
michael@0 | 2189 | aLimit); |
michael@0 | 2190 | |
michael@0 | 2191 | return request.forget(); |
michael@0 | 2192 | } |
michael@0 | 2193 | |
michael@0 | 2194 | already_AddRefed<IDBRequest> |
michael@0 | 2195 | IDBObjectStore::DeleteInternal(IDBKeyRange* aKeyRange, |
michael@0 | 2196 | ErrorResult& aRv) |
michael@0 | 2197 | { |
michael@0 | 2198 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2199 | NS_ASSERTION(aKeyRange, "Null key range!"); |
michael@0 | 2200 | |
michael@0 | 2201 | if (!mTransaction->IsOpen()) { |
michael@0 | 2202 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2203 | return nullptr; |
michael@0 | 2204 | } |
michael@0 | 2205 | |
michael@0 | 2206 | if (!IsWriteAllowed()) { |
michael@0 | 2207 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); |
michael@0 | 2208 | return nullptr; |
michael@0 | 2209 | } |
michael@0 | 2210 | |
michael@0 | 2211 | nsRefPtr<IDBRequest> request = GenerateRequest(this); |
michael@0 | 2212 | if (!request) { |
michael@0 | 2213 | IDB_WARNING("Failed to generate request!"); |
michael@0 | 2214 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2215 | return nullptr; |
michael@0 | 2216 | } |
michael@0 | 2217 | |
michael@0 | 2218 | nsRefPtr<DeleteHelper> helper = |
michael@0 | 2219 | new DeleteHelper(mTransaction, request, this, aKeyRange); |
michael@0 | 2220 | |
michael@0 | 2221 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2222 | if (NS_FAILED(rv)) { |
michael@0 | 2223 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 2224 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2225 | return nullptr; |
michael@0 | 2226 | } |
michael@0 | 2227 | |
michael@0 | 2228 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 2229 | "database(%s).transaction(%s).objectStore(%s).delete(%s)", |
michael@0 | 2230 | "IDBRequest[%llu] MT IDBObjectStore.delete()", |
michael@0 | 2231 | request->GetSerialNumber(), |
michael@0 | 2232 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2233 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2234 | IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange)); |
michael@0 | 2235 | |
michael@0 | 2236 | return request.forget(); |
michael@0 | 2237 | } |
michael@0 | 2238 | |
michael@0 | 2239 | already_AddRefed<IDBRequest> |
michael@0 | 2240 | IDBObjectStore::Clear(ErrorResult& aRv) |
michael@0 | 2241 | { |
michael@0 | 2242 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2243 | |
michael@0 | 2244 | if (!mTransaction->IsOpen()) { |
michael@0 | 2245 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2246 | return nullptr; |
michael@0 | 2247 | } |
michael@0 | 2248 | |
michael@0 | 2249 | if (!IsWriteAllowed()) { |
michael@0 | 2250 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); |
michael@0 | 2251 | return nullptr; |
michael@0 | 2252 | } |
michael@0 | 2253 | |
michael@0 | 2254 | nsRefPtr<IDBRequest> request = GenerateRequest(this); |
michael@0 | 2255 | if (!request) { |
michael@0 | 2256 | IDB_WARNING("Failed to generate request!"); |
michael@0 | 2257 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2258 | return nullptr; |
michael@0 | 2259 | } |
michael@0 | 2260 | |
michael@0 | 2261 | nsRefPtr<ClearHelper> helper(new ClearHelper(mTransaction, request, this)); |
michael@0 | 2262 | |
michael@0 | 2263 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2264 | if (NS_FAILED(rv)) { |
michael@0 | 2265 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 2266 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2267 | return nullptr; |
michael@0 | 2268 | } |
michael@0 | 2269 | |
michael@0 | 2270 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 2271 | "database(%s).transaction(%s).objectStore(%s).clear()", |
michael@0 | 2272 | "IDBRequest[%llu] MT IDBObjectStore.clear()", |
michael@0 | 2273 | request->GetSerialNumber(), |
michael@0 | 2274 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2275 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2276 | IDB_PROFILER_STRING(this)); |
michael@0 | 2277 | |
michael@0 | 2278 | return request.forget(); |
michael@0 | 2279 | } |
michael@0 | 2280 | |
michael@0 | 2281 | already_AddRefed<IDBRequest> |
michael@0 | 2282 | IDBObjectStore::CountInternal(IDBKeyRange* aKeyRange, ErrorResult& aRv) |
michael@0 | 2283 | { |
michael@0 | 2284 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2285 | |
michael@0 | 2286 | if (!mTransaction->IsOpen()) { |
michael@0 | 2287 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2288 | return nullptr; |
michael@0 | 2289 | } |
michael@0 | 2290 | |
michael@0 | 2291 | nsRefPtr<IDBRequest> request = GenerateRequest(this); |
michael@0 | 2292 | if (!request) { |
michael@0 | 2293 | IDB_WARNING("Failed to generate request!"); |
michael@0 | 2294 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2295 | return nullptr; |
michael@0 | 2296 | } |
michael@0 | 2297 | |
michael@0 | 2298 | nsRefPtr<CountHelper> helper = |
michael@0 | 2299 | new CountHelper(mTransaction, request, this, aKeyRange); |
michael@0 | 2300 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2301 | if (NS_FAILED(rv)) { |
michael@0 | 2302 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 2303 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2304 | return nullptr; |
michael@0 | 2305 | } |
michael@0 | 2306 | |
michael@0 | 2307 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 2308 | "database(%s).transaction(%s).objectStore(%s).count(%s)", |
michael@0 | 2309 | "IDBRequest[%llu] MT IDBObjectStore.count()", |
michael@0 | 2310 | request->GetSerialNumber(), |
michael@0 | 2311 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2312 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2313 | IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange)); |
michael@0 | 2314 | |
michael@0 | 2315 | return request.forget(); |
michael@0 | 2316 | } |
michael@0 | 2317 | |
michael@0 | 2318 | already_AddRefed<IDBRequest> |
michael@0 | 2319 | IDBObjectStore::OpenCursorInternal(IDBKeyRange* aKeyRange, |
michael@0 | 2320 | size_t aDirection, ErrorResult& aRv) |
michael@0 | 2321 | { |
michael@0 | 2322 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2323 | |
michael@0 | 2324 | if (!mTransaction->IsOpen()) { |
michael@0 | 2325 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2326 | return nullptr; |
michael@0 | 2327 | } |
michael@0 | 2328 | |
michael@0 | 2329 | IDBCursor::Direction direction = |
michael@0 | 2330 | static_cast<IDBCursor::Direction>(aDirection); |
michael@0 | 2331 | |
michael@0 | 2332 | nsRefPtr<IDBRequest> request = GenerateRequest(this); |
michael@0 | 2333 | if (!request) { |
michael@0 | 2334 | IDB_WARNING("Failed to generate request!"); |
michael@0 | 2335 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2336 | return nullptr; |
michael@0 | 2337 | } |
michael@0 | 2338 | |
michael@0 | 2339 | nsRefPtr<OpenCursorHelper> helper = |
michael@0 | 2340 | new OpenCursorHelper(mTransaction, request, this, aKeyRange, direction); |
michael@0 | 2341 | |
michael@0 | 2342 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2343 | if (NS_FAILED(rv)) { |
michael@0 | 2344 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 2345 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2346 | return nullptr; |
michael@0 | 2347 | } |
michael@0 | 2348 | |
michael@0 | 2349 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 2350 | "database(%s).transaction(%s).objectStore(%s)." |
michael@0 | 2351 | "openCursor(%s, %s)", |
michael@0 | 2352 | "IDBRequest[%llu] MT IDBObjectStore.openCursor()", |
michael@0 | 2353 | request->GetSerialNumber(), |
michael@0 | 2354 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2355 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2356 | IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange), |
michael@0 | 2357 | IDB_PROFILER_STRING(direction)); |
michael@0 | 2358 | |
michael@0 | 2359 | return request.forget(); |
michael@0 | 2360 | } |
michael@0 | 2361 | |
michael@0 | 2362 | nsresult |
michael@0 | 2363 | IDBObjectStore::OpenCursorFromChildProcess( |
michael@0 | 2364 | IDBRequest* aRequest, |
michael@0 | 2365 | size_t aDirection, |
michael@0 | 2366 | const Key& aKey, |
michael@0 | 2367 | const SerializedStructuredCloneReadInfo& aCloneInfo, |
michael@0 | 2368 | nsTArray<StructuredCloneFile>& aBlobs, |
michael@0 | 2369 | IDBCursor** _retval) |
michael@0 | 2370 | { |
michael@0 | 2371 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2372 | NS_ASSERTION((!aCloneInfo.dataLength && !aCloneInfo.data) || |
michael@0 | 2373 | (aCloneInfo.dataLength && aCloneInfo.data), |
michael@0 | 2374 | "Inconsistent clone info!"); |
michael@0 | 2375 | |
michael@0 | 2376 | IDBCursor::Direction direction = |
michael@0 | 2377 | static_cast<IDBCursor::Direction>(aDirection); |
michael@0 | 2378 | |
michael@0 | 2379 | StructuredCloneReadInfo cloneInfo; |
michael@0 | 2380 | |
michael@0 | 2381 | if (!cloneInfo.SetFromSerialized(aCloneInfo)) { |
michael@0 | 2382 | IDB_WARNING("Failed to copy clone buffer!"); |
michael@0 | 2383 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 2384 | } |
michael@0 | 2385 | |
michael@0 | 2386 | cloneInfo.mFiles.SwapElements(aBlobs); |
michael@0 | 2387 | |
michael@0 | 2388 | nsRefPtr<IDBCursor> cursor = |
michael@0 | 2389 | IDBCursor::Create(aRequest, mTransaction, this, direction, Key(), |
michael@0 | 2390 | EmptyCString(), EmptyCString(), aKey, Move(cloneInfo)); |
michael@0 | 2391 | IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2392 | |
michael@0 | 2393 | NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!"); |
michael@0 | 2394 | |
michael@0 | 2395 | cursor.forget(_retval); |
michael@0 | 2396 | return NS_OK; |
michael@0 | 2397 | } |
michael@0 | 2398 | |
michael@0 | 2399 | nsresult |
michael@0 | 2400 | IDBObjectStore::OpenCursorFromChildProcess(IDBRequest* aRequest, |
michael@0 | 2401 | size_t aDirection, |
michael@0 | 2402 | const Key& aKey, |
michael@0 | 2403 | IDBCursor** _retval) |
michael@0 | 2404 | { |
michael@0 | 2405 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2406 | MOZ_ASSERT(aRequest); |
michael@0 | 2407 | |
michael@0 | 2408 | auto direction = static_cast<IDBCursor::Direction>(aDirection); |
michael@0 | 2409 | |
michael@0 | 2410 | nsRefPtr<IDBCursor> cursor = |
michael@0 | 2411 | IDBCursor::Create(aRequest, mTransaction, this, direction, Key(), |
michael@0 | 2412 | EmptyCString(), EmptyCString(), aKey); |
michael@0 | 2413 | IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2414 | |
michael@0 | 2415 | cursor.forget(_retval); |
michael@0 | 2416 | return NS_OK; |
michael@0 | 2417 | } |
michael@0 | 2418 | |
michael@0 | 2419 | already_AddRefed<IDBRequest> |
michael@0 | 2420 | IDBObjectStore::OpenKeyCursorInternal(IDBKeyRange* aKeyRange, size_t aDirection, |
michael@0 | 2421 | ErrorResult& aRv) |
michael@0 | 2422 | { |
michael@0 | 2423 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2424 | |
michael@0 | 2425 | if (!mTransaction->IsOpen()) { |
michael@0 | 2426 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2427 | return nullptr; |
michael@0 | 2428 | } |
michael@0 | 2429 | |
michael@0 | 2430 | nsRefPtr<IDBRequest> request = GenerateRequest(this); |
michael@0 | 2431 | if (!request) { |
michael@0 | 2432 | IDB_WARNING("Failed to generate request!"); |
michael@0 | 2433 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2434 | return nullptr; |
michael@0 | 2435 | } |
michael@0 | 2436 | |
michael@0 | 2437 | auto direction = static_cast<IDBCursor::Direction>(aDirection); |
michael@0 | 2438 | |
michael@0 | 2439 | nsRefPtr<OpenKeyCursorHelper> helper = |
michael@0 | 2440 | new OpenKeyCursorHelper(mTransaction, request, this, aKeyRange, direction); |
michael@0 | 2441 | |
michael@0 | 2442 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2443 | if (NS_FAILED(rv)) { |
michael@0 | 2444 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 2445 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2446 | return nullptr; |
michael@0 | 2447 | } |
michael@0 | 2448 | |
michael@0 | 2449 | IDB_PROFILER_MARK("IndexedDB Request %llu: " |
michael@0 | 2450 | "database(%s).transaction(%s).objectStore(%s)." |
michael@0 | 2451 | "openKeyCursor(%s, %s)", |
michael@0 | 2452 | "IDBRequest[%llu] MT IDBObjectStore.openKeyCursor()", |
michael@0 | 2453 | request->GetSerialNumber(), |
michael@0 | 2454 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2455 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2456 | IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange), |
michael@0 | 2457 | IDB_PROFILER_STRING(direction)); |
michael@0 | 2458 | |
michael@0 | 2459 | return request.forget(); |
michael@0 | 2460 | } |
michael@0 | 2461 | |
michael@0 | 2462 | void |
michael@0 | 2463 | IDBObjectStore::SetInfo(ObjectStoreInfo* aInfo) |
michael@0 | 2464 | { |
michael@0 | 2465 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread"); |
michael@0 | 2466 | NS_ASSERTION(aInfo != mInfo, "This is nonsense"); |
michael@0 | 2467 | |
michael@0 | 2468 | mInfo = aInfo; |
michael@0 | 2469 | } |
michael@0 | 2470 | |
michael@0 | 2471 | already_AddRefed<IDBIndex> |
michael@0 | 2472 | IDBObjectStore::CreateIndexInternal(const IndexInfo& aInfo, ErrorResult& aRv) |
michael@0 | 2473 | { |
michael@0 | 2474 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2475 | |
michael@0 | 2476 | IndexInfo* indexInfo = mInfo->indexes.AppendElement(); |
michael@0 | 2477 | |
michael@0 | 2478 | indexInfo->name = aInfo.name; |
michael@0 | 2479 | indexInfo->id = aInfo.id; |
michael@0 | 2480 | indexInfo->keyPath = aInfo.keyPath; |
michael@0 | 2481 | indexInfo->unique = aInfo.unique; |
michael@0 | 2482 | indexInfo->multiEntry = aInfo.multiEntry; |
michael@0 | 2483 | |
michael@0 | 2484 | // Don't leave this in the list if we fail below! |
michael@0 | 2485 | AutoRemoveIndex autoRemove(mInfo, aInfo.name); |
michael@0 | 2486 | |
michael@0 | 2487 | nsRefPtr<IDBIndex> index = IDBIndex::Create(this, indexInfo, true); |
michael@0 | 2488 | |
michael@0 | 2489 | mCreatedIndexes.AppendElement(index); |
michael@0 | 2490 | |
michael@0 | 2491 | if (IndexedDatabaseManager::IsMainProcess()) { |
michael@0 | 2492 | nsRefPtr<CreateIndexHelper> helper = |
michael@0 | 2493 | new CreateIndexHelper(mTransaction, index); |
michael@0 | 2494 | |
michael@0 | 2495 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2496 | if (NS_FAILED(rv)) { |
michael@0 | 2497 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 2498 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2499 | return nullptr; |
michael@0 | 2500 | } |
michael@0 | 2501 | } |
michael@0 | 2502 | |
michael@0 | 2503 | autoRemove.forget(); |
michael@0 | 2504 | |
michael@0 | 2505 | IDB_PROFILER_MARK("IndexedDB Pseudo-request: " |
michael@0 | 2506 | "database(%s).transaction(%s).objectStore(%s)." |
michael@0 | 2507 | "createIndex(%s)", |
michael@0 | 2508 | "MT IDBObjectStore.createIndex()", |
michael@0 | 2509 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2510 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2511 | IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(index)); |
michael@0 | 2512 | |
michael@0 | 2513 | return index.forget(); |
michael@0 | 2514 | } |
michael@0 | 2515 | |
michael@0 | 2516 | already_AddRefed<IDBIndex> |
michael@0 | 2517 | IDBObjectStore::Index(const nsAString& aName, ErrorResult &aRv) |
michael@0 | 2518 | { |
michael@0 | 2519 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2520 | |
michael@0 | 2521 | if (mTransaction->IsFinished()) { |
michael@0 | 2522 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2523 | return nullptr; |
michael@0 | 2524 | } |
michael@0 | 2525 | |
michael@0 | 2526 | IndexInfo* indexInfo = nullptr; |
michael@0 | 2527 | uint32_t indexCount = mInfo->indexes.Length(); |
michael@0 | 2528 | for (uint32_t index = 0; index < indexCount; index++) { |
michael@0 | 2529 | if (mInfo->indexes[index].name == aName) { |
michael@0 | 2530 | indexInfo = &(mInfo->indexes[index]); |
michael@0 | 2531 | break; |
michael@0 | 2532 | } |
michael@0 | 2533 | } |
michael@0 | 2534 | |
michael@0 | 2535 | if (!indexInfo) { |
michael@0 | 2536 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR); |
michael@0 | 2537 | return nullptr; |
michael@0 | 2538 | } |
michael@0 | 2539 | |
michael@0 | 2540 | nsRefPtr<IDBIndex> retval; |
michael@0 | 2541 | for (uint32_t i = 0; i < mCreatedIndexes.Length(); i++) { |
michael@0 | 2542 | nsRefPtr<IDBIndex>& index = mCreatedIndexes[i]; |
michael@0 | 2543 | if (index->Name() == aName) { |
michael@0 | 2544 | retval = index; |
michael@0 | 2545 | break; |
michael@0 | 2546 | } |
michael@0 | 2547 | } |
michael@0 | 2548 | |
michael@0 | 2549 | if (!retval) { |
michael@0 | 2550 | retval = IDBIndex::Create(this, indexInfo, false); |
michael@0 | 2551 | if (!retval) { |
michael@0 | 2552 | IDB_WARNING("Failed to create index!"); |
michael@0 | 2553 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2554 | return nullptr; |
michael@0 | 2555 | } |
michael@0 | 2556 | |
michael@0 | 2557 | if (!mCreatedIndexes.AppendElement(retval)) { |
michael@0 | 2558 | IDB_WARNING("Out of memory!"); |
michael@0 | 2559 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2560 | return nullptr; |
michael@0 | 2561 | } |
michael@0 | 2562 | } |
michael@0 | 2563 | |
michael@0 | 2564 | return retval.forget(); |
michael@0 | 2565 | } |
michael@0 | 2566 | |
michael@0 | 2567 | NS_IMPL_CYCLE_COLLECTION_CLASS(IDBObjectStore) |
michael@0 | 2568 | |
michael@0 | 2569 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBObjectStore) |
michael@0 | 2570 | NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER |
michael@0 | 2571 | NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKeyPath) |
michael@0 | 2572 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
michael@0 | 2573 | |
michael@0 | 2574 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBObjectStore) |
michael@0 | 2575 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS |
michael@0 | 2576 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mTransaction) |
michael@0 | 2577 | |
michael@0 | 2578 | for (uint32_t i = 0; i < tmp->mCreatedIndexes.Length(); i++) { |
michael@0 | 2579 | NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mCreatedIndexes[i]"); |
michael@0 | 2580 | cb.NoteXPCOMChild(static_cast<nsISupports*>(tmp->mCreatedIndexes[i].get())); |
michael@0 | 2581 | } |
michael@0 | 2582 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
michael@0 | 2583 | |
michael@0 | 2584 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBObjectStore) |
michael@0 | 2585 | NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
michael@0 | 2586 | |
michael@0 | 2587 | // Don't unlink mTransaction! |
michael@0 | 2588 | |
michael@0 | 2589 | tmp->mCreatedIndexes.Clear(); |
michael@0 | 2590 | |
michael@0 | 2591 | tmp->mCachedKeyPath = JSVAL_VOID; |
michael@0 | 2592 | |
michael@0 | 2593 | if (tmp->mRooted) { |
michael@0 | 2594 | mozilla::DropJSObjects(tmp); |
michael@0 | 2595 | tmp->mRooted = false; |
michael@0 | 2596 | } |
michael@0 | 2597 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
michael@0 | 2598 | |
michael@0 | 2599 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBObjectStore) |
michael@0 | 2600 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
michael@0 | 2601 | NS_INTERFACE_MAP_ENTRY(nsISupports) |
michael@0 | 2602 | NS_INTERFACE_MAP_END |
michael@0 | 2603 | |
michael@0 | 2604 | NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBObjectStore) |
michael@0 | 2605 | NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBObjectStore) |
michael@0 | 2606 | |
michael@0 | 2607 | JSObject* |
michael@0 | 2608 | IDBObjectStore::WrapObject(JSContext* aCx) |
michael@0 | 2609 | { |
michael@0 | 2610 | return IDBObjectStoreBinding::Wrap(aCx, this); |
michael@0 | 2611 | } |
michael@0 | 2612 | |
michael@0 | 2613 | void |
michael@0 | 2614 | IDBObjectStore::GetKeyPath(JSContext* aCx, JS::MutableHandle<JS::Value> aResult, |
michael@0 | 2615 | ErrorResult& aRv) |
michael@0 | 2616 | { |
michael@0 | 2617 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2618 | |
michael@0 | 2619 | if (!JSVAL_IS_VOID(mCachedKeyPath)) { |
michael@0 | 2620 | JS::ExposeValueToActiveJS(mCachedKeyPath); |
michael@0 | 2621 | aResult.set(mCachedKeyPath); |
michael@0 | 2622 | return; |
michael@0 | 2623 | } |
michael@0 | 2624 | |
michael@0 | 2625 | aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath); |
michael@0 | 2626 | if (NS_WARN_IF(aRv.Failed())) { |
michael@0 | 2627 | return; |
michael@0 | 2628 | } |
michael@0 | 2629 | |
michael@0 | 2630 | if (JSVAL_IS_GCTHING(mCachedKeyPath)) { |
michael@0 | 2631 | mozilla::HoldJSObjects(this); |
michael@0 | 2632 | mRooted = true; |
michael@0 | 2633 | } |
michael@0 | 2634 | |
michael@0 | 2635 | JS::ExposeValueToActiveJS(mCachedKeyPath); |
michael@0 | 2636 | aResult.set(mCachedKeyPath); |
michael@0 | 2637 | } |
michael@0 | 2638 | |
michael@0 | 2639 | already_AddRefed<DOMStringList> |
michael@0 | 2640 | IDBObjectStore::GetIndexNames(ErrorResult& aRv) |
michael@0 | 2641 | { |
michael@0 | 2642 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2643 | |
michael@0 | 2644 | nsRefPtr<DOMStringList> list(new DOMStringList()); |
michael@0 | 2645 | |
michael@0 | 2646 | nsTArray<nsString>& names = list->StringArray(); |
michael@0 | 2647 | uint32_t count = mInfo->indexes.Length(); |
michael@0 | 2648 | names.SetCapacity(count); |
michael@0 | 2649 | |
michael@0 | 2650 | for (uint32_t index = 0; index < count; index++) { |
michael@0 | 2651 | names.InsertElementSorted(mInfo->indexes[index].name); |
michael@0 | 2652 | } |
michael@0 | 2653 | |
michael@0 | 2654 | return list.forget(); |
michael@0 | 2655 | } |
michael@0 | 2656 | |
michael@0 | 2657 | already_AddRefed<IDBRequest> |
michael@0 | 2658 | IDBObjectStore::Get(JSContext* aCx, JS::Handle<JS::Value> aKey, |
michael@0 | 2659 | ErrorResult& aRv) |
michael@0 | 2660 | { |
michael@0 | 2661 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2662 | |
michael@0 | 2663 | if (!mTransaction->IsOpen()) { |
michael@0 | 2664 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2665 | return nullptr; |
michael@0 | 2666 | } |
michael@0 | 2667 | |
michael@0 | 2668 | nsRefPtr<IDBKeyRange> keyRange; |
michael@0 | 2669 | aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); |
michael@0 | 2670 | ENSURE_SUCCESS(aRv, nullptr); |
michael@0 | 2671 | |
michael@0 | 2672 | if (!keyRange) { |
michael@0 | 2673 | // Must specify a key or keyRange for get(). |
michael@0 | 2674 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); |
michael@0 | 2675 | return nullptr; |
michael@0 | 2676 | } |
michael@0 | 2677 | |
michael@0 | 2678 | return GetInternal(keyRange, aRv); |
michael@0 | 2679 | } |
michael@0 | 2680 | |
michael@0 | 2681 | already_AddRefed<IDBRequest> |
michael@0 | 2682 | IDBObjectStore::GetAll(JSContext* aCx, |
michael@0 | 2683 | JS::Handle<JS::Value> aKey, |
michael@0 | 2684 | const Optional<uint32_t>& aLimit, ErrorResult& aRv) |
michael@0 | 2685 | { |
michael@0 | 2686 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2687 | |
michael@0 | 2688 | if (!mTransaction->IsOpen()) { |
michael@0 | 2689 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2690 | return nullptr; |
michael@0 | 2691 | } |
michael@0 | 2692 | |
michael@0 | 2693 | nsRefPtr<IDBKeyRange> keyRange; |
michael@0 | 2694 | aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); |
michael@0 | 2695 | ENSURE_SUCCESS(aRv, nullptr); |
michael@0 | 2696 | |
michael@0 | 2697 | uint32_t limit = UINT32_MAX; |
michael@0 | 2698 | if (aLimit.WasPassed() && aLimit.Value() != 0) { |
michael@0 | 2699 | limit = aLimit.Value(); |
michael@0 | 2700 | } |
michael@0 | 2701 | |
michael@0 | 2702 | return GetAllInternal(keyRange, limit, aRv); |
michael@0 | 2703 | } |
michael@0 | 2704 | |
michael@0 | 2705 | already_AddRefed<IDBRequest> |
michael@0 | 2706 | IDBObjectStore::Delete(JSContext* aCx, JS::Handle<JS::Value> aKey, |
michael@0 | 2707 | ErrorResult& aRv) |
michael@0 | 2708 | { |
michael@0 | 2709 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2710 | |
michael@0 | 2711 | if (!mTransaction->IsOpen()) { |
michael@0 | 2712 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2713 | return nullptr; |
michael@0 | 2714 | } |
michael@0 | 2715 | |
michael@0 | 2716 | if (!IsWriteAllowed()) { |
michael@0 | 2717 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_READ_ONLY_ERR); |
michael@0 | 2718 | return nullptr; |
michael@0 | 2719 | } |
michael@0 | 2720 | |
michael@0 | 2721 | nsRefPtr<IDBKeyRange> keyRange; |
michael@0 | 2722 | aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); |
michael@0 | 2723 | ENSURE_SUCCESS(aRv, nullptr); |
michael@0 | 2724 | |
michael@0 | 2725 | if (!keyRange) { |
michael@0 | 2726 | // Must specify a key or keyRange for delete(). |
michael@0 | 2727 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR); |
michael@0 | 2728 | return nullptr; |
michael@0 | 2729 | } |
michael@0 | 2730 | |
michael@0 | 2731 | return DeleteInternal(keyRange, aRv); |
michael@0 | 2732 | } |
michael@0 | 2733 | |
michael@0 | 2734 | already_AddRefed<IDBRequest> |
michael@0 | 2735 | IDBObjectStore::OpenCursor(JSContext* aCx, |
michael@0 | 2736 | JS::Handle<JS::Value> aRange, |
michael@0 | 2737 | IDBCursorDirection aDirection, ErrorResult& aRv) |
michael@0 | 2738 | { |
michael@0 | 2739 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2740 | |
michael@0 | 2741 | if (!mTransaction->IsOpen()) { |
michael@0 | 2742 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2743 | return nullptr; |
michael@0 | 2744 | } |
michael@0 | 2745 | |
michael@0 | 2746 | nsRefPtr<IDBKeyRange> keyRange; |
michael@0 | 2747 | aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange)); |
michael@0 | 2748 | ENSURE_SUCCESS(aRv, nullptr); |
michael@0 | 2749 | |
michael@0 | 2750 | IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection); |
michael@0 | 2751 | size_t argDirection = static_cast<size_t>(direction); |
michael@0 | 2752 | |
michael@0 | 2753 | return OpenCursorInternal(keyRange, argDirection, aRv); |
michael@0 | 2754 | } |
michael@0 | 2755 | |
michael@0 | 2756 | already_AddRefed<IDBIndex> |
michael@0 | 2757 | IDBObjectStore::CreateIndex(JSContext* aCx, const nsAString& aName, |
michael@0 | 2758 | const nsAString& aKeyPath, |
michael@0 | 2759 | const IDBIndexParameters& aOptionalParameters, |
michael@0 | 2760 | ErrorResult& aRv) |
michael@0 | 2761 | { |
michael@0 | 2762 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2763 | |
michael@0 | 2764 | KeyPath keyPath(0); |
michael@0 | 2765 | if (NS_FAILED(KeyPath::Parse(aCx, aKeyPath, &keyPath)) || |
michael@0 | 2766 | !keyPath.IsValid()) { |
michael@0 | 2767 | aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); |
michael@0 | 2768 | return nullptr; |
michael@0 | 2769 | } |
michael@0 | 2770 | |
michael@0 | 2771 | return CreateIndex(aCx, aName, keyPath, aOptionalParameters, aRv); |
michael@0 | 2772 | } |
michael@0 | 2773 | |
michael@0 | 2774 | already_AddRefed<IDBIndex> |
michael@0 | 2775 | IDBObjectStore::CreateIndex(JSContext* aCx, const nsAString& aName, |
michael@0 | 2776 | const Sequence<nsString >& aKeyPath, |
michael@0 | 2777 | const IDBIndexParameters& aOptionalParameters, |
michael@0 | 2778 | ErrorResult& aRv) |
michael@0 | 2779 | { |
michael@0 | 2780 | NS_PRECONDITION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2781 | |
michael@0 | 2782 | if (!aKeyPath.Length()) { |
michael@0 | 2783 | aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); |
michael@0 | 2784 | return nullptr; |
michael@0 | 2785 | } |
michael@0 | 2786 | |
michael@0 | 2787 | KeyPath keyPath(0); |
michael@0 | 2788 | if (NS_FAILED(KeyPath::Parse(aCx, aKeyPath, &keyPath))) { |
michael@0 | 2789 | aRv.Throw(NS_ERROR_DOM_SYNTAX_ERR); |
michael@0 | 2790 | return nullptr; |
michael@0 | 2791 | } |
michael@0 | 2792 | |
michael@0 | 2793 | return CreateIndex(aCx, aName, keyPath, aOptionalParameters, aRv); |
michael@0 | 2794 | } |
michael@0 | 2795 | |
michael@0 | 2796 | already_AddRefed<IDBIndex> |
michael@0 | 2797 | IDBObjectStore::CreateIndex(JSContext* aCx, const nsAString& aName, |
michael@0 | 2798 | KeyPath& aKeyPath, |
michael@0 | 2799 | const IDBIndexParameters& aOptionalParameters, |
michael@0 | 2800 | ErrorResult& aRv) |
michael@0 | 2801 | { |
michael@0 | 2802 | // Check name and current mode |
michael@0 | 2803 | IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction(); |
michael@0 | 2804 | |
michael@0 | 2805 | if (!transaction || |
michael@0 | 2806 | transaction != mTransaction || |
michael@0 | 2807 | mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) { |
michael@0 | 2808 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); |
michael@0 | 2809 | return nullptr; |
michael@0 | 2810 | } |
michael@0 | 2811 | |
michael@0 | 2812 | bool found = false; |
michael@0 | 2813 | uint32_t indexCount = mInfo->indexes.Length(); |
michael@0 | 2814 | for (uint32_t index = 0; index < indexCount; index++) { |
michael@0 | 2815 | if (mInfo->indexes[index].name == aName) { |
michael@0 | 2816 | found = true; |
michael@0 | 2817 | break; |
michael@0 | 2818 | } |
michael@0 | 2819 | } |
michael@0 | 2820 | |
michael@0 | 2821 | if (found) { |
michael@0 | 2822 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR); |
michael@0 | 2823 | return nullptr; |
michael@0 | 2824 | } |
michael@0 | 2825 | |
michael@0 | 2826 | NS_ASSERTION(mTransaction->IsOpen(), "Impossible!"); |
michael@0 | 2827 | |
michael@0 | 2828 | #ifdef DEBUG |
michael@0 | 2829 | for (uint32_t index = 0; index < mCreatedIndexes.Length(); index++) { |
michael@0 | 2830 | if (mCreatedIndexes[index]->Name() == aName) { |
michael@0 | 2831 | NS_ERROR("Already created this one!"); |
michael@0 | 2832 | } |
michael@0 | 2833 | } |
michael@0 | 2834 | #endif |
michael@0 | 2835 | |
michael@0 | 2836 | if (aOptionalParameters.mMultiEntry && aKeyPath.IsArray()) { |
michael@0 | 2837 | aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); |
michael@0 | 2838 | return nullptr; |
michael@0 | 2839 | } |
michael@0 | 2840 | |
michael@0 | 2841 | DatabaseInfo* databaseInfo = mTransaction->DBInfo(); |
michael@0 | 2842 | |
michael@0 | 2843 | IndexInfo info; |
michael@0 | 2844 | |
michael@0 | 2845 | info.name = aName; |
michael@0 | 2846 | info.id = databaseInfo->nextIndexId++; |
michael@0 | 2847 | info.keyPath = aKeyPath; |
michael@0 | 2848 | info.unique = aOptionalParameters.mUnique; |
michael@0 | 2849 | info.multiEntry = aOptionalParameters.mMultiEntry; |
michael@0 | 2850 | |
michael@0 | 2851 | return CreateIndexInternal(info, aRv); |
michael@0 | 2852 | } |
michael@0 | 2853 | |
michael@0 | 2854 | void |
michael@0 | 2855 | IDBObjectStore::DeleteIndex(const nsAString& aName, ErrorResult& aRv) |
michael@0 | 2856 | { |
michael@0 | 2857 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2858 | |
michael@0 | 2859 | IDBTransaction* transaction = AsyncConnectionHelper::GetCurrentTransaction(); |
michael@0 | 2860 | |
michael@0 | 2861 | if (!transaction || |
michael@0 | 2862 | transaction != mTransaction || |
michael@0 | 2863 | mTransaction->GetMode() != IDBTransaction::VERSION_CHANGE) { |
michael@0 | 2864 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); |
michael@0 | 2865 | return; |
michael@0 | 2866 | } |
michael@0 | 2867 | |
michael@0 | 2868 | NS_ASSERTION(mTransaction->IsOpen(), "Impossible!"); |
michael@0 | 2869 | |
michael@0 | 2870 | uint32_t index = 0; |
michael@0 | 2871 | for (; index < mInfo->indexes.Length(); index++) { |
michael@0 | 2872 | if (mInfo->indexes[index].name == aName) { |
michael@0 | 2873 | break; |
michael@0 | 2874 | } |
michael@0 | 2875 | } |
michael@0 | 2876 | |
michael@0 | 2877 | if (index == mInfo->indexes.Length()) { |
michael@0 | 2878 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR); |
michael@0 | 2879 | return; |
michael@0 | 2880 | } |
michael@0 | 2881 | |
michael@0 | 2882 | if (IndexedDatabaseManager::IsMainProcess()) { |
michael@0 | 2883 | nsRefPtr<DeleteIndexHelper> helper = |
michael@0 | 2884 | new DeleteIndexHelper(mTransaction, this, aName); |
michael@0 | 2885 | |
michael@0 | 2886 | nsresult rv = helper->DispatchToTransactionPool(); |
michael@0 | 2887 | if (NS_FAILED(rv)) { |
michael@0 | 2888 | IDB_WARNING("Failed to dispatch!"); |
michael@0 | 2889 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 2890 | return; |
michael@0 | 2891 | } |
michael@0 | 2892 | } |
michael@0 | 2893 | else { |
michael@0 | 2894 | NS_ASSERTION(mActorChild, "Must have an actor here!"); |
michael@0 | 2895 | |
michael@0 | 2896 | mActorChild->SendDeleteIndex(nsString(aName)); |
michael@0 | 2897 | } |
michael@0 | 2898 | |
michael@0 | 2899 | mInfo->indexes.RemoveElementAt(index); |
michael@0 | 2900 | |
michael@0 | 2901 | for (uint32_t i = 0; i < mCreatedIndexes.Length(); i++) { |
michael@0 | 2902 | if (mCreatedIndexes[i]->Name() == aName) { |
michael@0 | 2903 | mCreatedIndexes.RemoveElementAt(i); |
michael@0 | 2904 | break; |
michael@0 | 2905 | } |
michael@0 | 2906 | } |
michael@0 | 2907 | |
michael@0 | 2908 | IDB_PROFILER_MARK("IndexedDB Pseudo-request: " |
michael@0 | 2909 | "database(%s).transaction(%s).objectStore(%s)." |
michael@0 | 2910 | "deleteIndex(\"%s\")", |
michael@0 | 2911 | "MT IDBObjectStore.deleteIndex()", |
michael@0 | 2912 | IDB_PROFILER_STRING(Transaction()->Database()), |
michael@0 | 2913 | IDB_PROFILER_STRING(Transaction()), |
michael@0 | 2914 | IDB_PROFILER_STRING(this), |
michael@0 | 2915 | NS_ConvertUTF16toUTF8(aName).get()); |
michael@0 | 2916 | } |
michael@0 | 2917 | |
michael@0 | 2918 | already_AddRefed<IDBRequest> |
michael@0 | 2919 | IDBObjectStore::Count(JSContext* aCx, |
michael@0 | 2920 | JS::Handle<JS::Value> aKey, |
michael@0 | 2921 | ErrorResult& aRv) |
michael@0 | 2922 | { |
michael@0 | 2923 | if (!mTransaction->IsOpen()) { |
michael@0 | 2924 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2925 | return nullptr; |
michael@0 | 2926 | } |
michael@0 | 2927 | |
michael@0 | 2928 | nsRefPtr<IDBKeyRange> keyRange; |
michael@0 | 2929 | aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); |
michael@0 | 2930 | ENSURE_SUCCESS(aRv, nullptr); |
michael@0 | 2931 | |
michael@0 | 2932 | return CountInternal(keyRange, aRv); |
michael@0 | 2933 | } |
michael@0 | 2934 | |
michael@0 | 2935 | already_AddRefed<IDBRequest> |
michael@0 | 2936 | IDBObjectStore::GetAllKeys(JSContext* aCx, |
michael@0 | 2937 | JS::Handle<JS::Value> aKey, |
michael@0 | 2938 | const Optional<uint32_t>& aLimit, ErrorResult& aRv) |
michael@0 | 2939 | { |
michael@0 | 2940 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2941 | |
michael@0 | 2942 | if (!mTransaction->IsOpen()) { |
michael@0 | 2943 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2944 | return nullptr; |
michael@0 | 2945 | } |
michael@0 | 2946 | |
michael@0 | 2947 | nsRefPtr<IDBKeyRange> keyRange; |
michael@0 | 2948 | aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); |
michael@0 | 2949 | ENSURE_SUCCESS(aRv, nullptr); |
michael@0 | 2950 | |
michael@0 | 2951 | uint32_t limit = UINT32_MAX; |
michael@0 | 2952 | if (aLimit.WasPassed() && aLimit.Value() != 0) { |
michael@0 | 2953 | limit = aLimit.Value(); |
michael@0 | 2954 | } |
michael@0 | 2955 | |
michael@0 | 2956 | return GetAllKeysInternal(keyRange, limit, aRv); |
michael@0 | 2957 | } |
michael@0 | 2958 | |
michael@0 | 2959 | already_AddRefed<IDBRequest> |
michael@0 | 2960 | IDBObjectStore::OpenKeyCursor(JSContext* aCx, |
michael@0 | 2961 | JS::Handle<JS::Value> aRange, |
michael@0 | 2962 | IDBCursorDirection aDirection, ErrorResult& aRv) |
michael@0 | 2963 | { |
michael@0 | 2964 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 2965 | |
michael@0 | 2966 | if (!mTransaction->IsOpen()) { |
michael@0 | 2967 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
michael@0 | 2968 | return nullptr; |
michael@0 | 2969 | } |
michael@0 | 2970 | |
michael@0 | 2971 | nsRefPtr<IDBKeyRange> keyRange; |
michael@0 | 2972 | aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange)); |
michael@0 | 2973 | ENSURE_SUCCESS(aRv, nullptr); |
michael@0 | 2974 | |
michael@0 | 2975 | IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection); |
michael@0 | 2976 | |
michael@0 | 2977 | return OpenKeyCursorInternal(keyRange, static_cast<size_t>(direction), aRv); |
michael@0 | 2978 | } |
michael@0 | 2979 | |
michael@0 | 2980 | inline nsresult |
michael@0 | 2981 | CopyData(nsIInputStream* aInputStream, nsIOutputStream* aOutputStream) |
michael@0 | 2982 | { |
michael@0 | 2983 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 2984 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 2985 | |
michael@0 | 2986 | PROFILER_LABEL("IndexedDB", "CopyData"); |
michael@0 | 2987 | |
michael@0 | 2988 | nsresult rv; |
michael@0 | 2989 | |
michael@0 | 2990 | do { |
michael@0 | 2991 | char copyBuffer[FILE_COPY_BUFFER_SIZE]; |
michael@0 | 2992 | |
michael@0 | 2993 | uint32_t numRead; |
michael@0 | 2994 | rv = aInputStream->Read(copyBuffer, sizeof(copyBuffer), &numRead); |
michael@0 | 2995 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 2996 | |
michael@0 | 2997 | if (!numRead) { |
michael@0 | 2998 | break; |
michael@0 | 2999 | } |
michael@0 | 3000 | |
michael@0 | 3001 | uint32_t numWrite; |
michael@0 | 3002 | rv = aOutputStream->Write(copyBuffer, numRead, &numWrite); |
michael@0 | 3003 | if (rv == NS_ERROR_FILE_NO_DEVICE_SPACE) { |
michael@0 | 3004 | rv = NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; |
michael@0 | 3005 | } |
michael@0 | 3006 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 3007 | |
michael@0 | 3008 | NS_ENSURE_TRUE(numWrite == numRead, NS_ERROR_FAILURE); |
michael@0 | 3009 | } while (true); |
michael@0 | 3010 | |
michael@0 | 3011 | rv = aOutputStream->Flush(); |
michael@0 | 3012 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 3013 | |
michael@0 | 3014 | return NS_OK; |
michael@0 | 3015 | } |
michael@0 | 3016 | |
michael@0 | 3017 | void |
michael@0 | 3018 | ObjectStoreHelper::ReleaseMainThreadObjects() |
michael@0 | 3019 | { |
michael@0 | 3020 | mObjectStore = nullptr; |
michael@0 | 3021 | AsyncConnectionHelper::ReleaseMainThreadObjects(); |
michael@0 | 3022 | } |
michael@0 | 3023 | |
michael@0 | 3024 | nsresult |
michael@0 | 3025 | ObjectStoreHelper::Dispatch(nsIEventTarget* aDatabaseThread) |
michael@0 | 3026 | { |
michael@0 | 3027 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3028 | |
michael@0 | 3029 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", "ObjectStoreHelper::Dispatch"); |
michael@0 | 3030 | |
michael@0 | 3031 | if (IndexedDatabaseManager::IsMainProcess()) { |
michael@0 | 3032 | return AsyncConnectionHelper::Dispatch(aDatabaseThread); |
michael@0 | 3033 | } |
michael@0 | 3034 | |
michael@0 | 3035 | // If we've been invalidated then there's no point sending anything to the |
michael@0 | 3036 | // parent process. |
michael@0 | 3037 | if (mObjectStore->Transaction()->Database()->IsInvalidated()) { |
michael@0 | 3038 | IDB_REPORT_INTERNAL_ERR(); |
michael@0 | 3039 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 3040 | } |
michael@0 | 3041 | |
michael@0 | 3042 | IndexedDBObjectStoreChild* objectStoreActor = mObjectStore->GetActorChild(); |
michael@0 | 3043 | NS_ASSERTION(objectStoreActor, "Must have an actor here!"); |
michael@0 | 3044 | |
michael@0 | 3045 | ObjectStoreRequestParams params; |
michael@0 | 3046 | nsresult rv = PackArgumentsForParentProcess(params); |
michael@0 | 3047 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3048 | |
michael@0 | 3049 | NoDispatchEventTarget target; |
michael@0 | 3050 | rv = AsyncConnectionHelper::Dispatch(&target); |
michael@0 | 3051 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3052 | |
michael@0 | 3053 | mActor = |
michael@0 | 3054 | new IndexedDBObjectStoreRequestChild(this, mObjectStore, params.type()); |
michael@0 | 3055 | objectStoreActor->SendPIndexedDBRequestConstructor(mActor, params); |
michael@0 | 3056 | |
michael@0 | 3057 | return NS_OK; |
michael@0 | 3058 | } |
michael@0 | 3059 | |
michael@0 | 3060 | void |
michael@0 | 3061 | NoRequestObjectStoreHelper::ReleaseMainThreadObjects() |
michael@0 | 3062 | { |
michael@0 | 3063 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3064 | mObjectStore = nullptr; |
michael@0 | 3065 | AsyncConnectionHelper::ReleaseMainThreadObjects(); |
michael@0 | 3066 | } |
michael@0 | 3067 | |
michael@0 | 3068 | nsresult |
michael@0 | 3069 | NoRequestObjectStoreHelper::UnpackResponseFromParentProcess( |
michael@0 | 3070 | const ResponseValue& aResponseValue) |
michael@0 | 3071 | { |
michael@0 | 3072 | MOZ_CRASH(); |
michael@0 | 3073 | } |
michael@0 | 3074 | |
michael@0 | 3075 | AsyncConnectionHelper::ChildProcessSendResult |
michael@0 | 3076 | NoRequestObjectStoreHelper::SendResponseToChildProcess(nsresult aResultCode) |
michael@0 | 3077 | { |
michael@0 | 3078 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3079 | return Success_NotSent; |
michael@0 | 3080 | } |
michael@0 | 3081 | |
michael@0 | 3082 | nsresult |
michael@0 | 3083 | NoRequestObjectStoreHelper::OnSuccess() |
michael@0 | 3084 | { |
michael@0 | 3085 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3086 | return NS_OK; |
michael@0 | 3087 | } |
michael@0 | 3088 | |
michael@0 | 3089 | void |
michael@0 | 3090 | NoRequestObjectStoreHelper::OnError() |
michael@0 | 3091 | { |
michael@0 | 3092 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3093 | mTransaction->Abort(GetResultCode()); |
michael@0 | 3094 | } |
michael@0 | 3095 | |
michael@0 | 3096 | // This is a duplicate of the js engine's byte munging in StructuredClone.cpp |
michael@0 | 3097 | uint64_t |
michael@0 | 3098 | ReinterpretDoubleAsUInt64(double d) |
michael@0 | 3099 | { |
michael@0 | 3100 | union { |
michael@0 | 3101 | double d; |
michael@0 | 3102 | uint64_t u; |
michael@0 | 3103 | } pun; |
michael@0 | 3104 | pun.d = d; |
michael@0 | 3105 | return pun.u; |
michael@0 | 3106 | } |
michael@0 | 3107 | |
michael@0 | 3108 | nsresult |
michael@0 | 3109 | AddHelper::DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 3110 | { |
michael@0 | 3111 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3112 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3113 | NS_ASSERTION(aConnection, "Passed a null connection!"); |
michael@0 | 3114 | |
michael@0 | 3115 | PROFILER_LABEL("IndexedDB", "AddHelper::DoDatabaseWork"); |
michael@0 | 3116 | |
michael@0 | 3117 | if (IndexedDatabaseManager::InLowDiskSpaceMode()) { |
michael@0 | 3118 | NS_WARNING("Refusing to add more data because disk space is low!"); |
michael@0 | 3119 | return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; |
michael@0 | 3120 | } |
michael@0 | 3121 | |
michael@0 | 3122 | nsresult rv; |
michael@0 | 3123 | bool keyUnset = mKey.IsUnset(); |
michael@0 | 3124 | int64_t osid = mObjectStore->Id(); |
michael@0 | 3125 | const KeyPath& keyPath = mObjectStore->GetKeyPath(); |
michael@0 | 3126 | |
michael@0 | 3127 | // The "|| keyUnset" here is mostly a debugging tool. If a key isn't |
michael@0 | 3128 | // specified we should never have a collision and so it shouldn't matter |
michael@0 | 3129 | // if we allow overwrite or not. By not allowing overwrite we raise |
michael@0 | 3130 | // detectable errors rather than corrupting data |
michael@0 | 3131 | nsCOMPtr<mozIStorageStatement> stmt = !mOverwrite || keyUnset ? |
michael@0 | 3132 | mTransaction->GetCachedStatement( |
michael@0 | 3133 | "INSERT INTO object_data (object_store_id, key_value, data, file_ids) " |
michael@0 | 3134 | "VALUES (:osid, :key_value, :data, :file_ids)") : |
michael@0 | 3135 | mTransaction->GetCachedStatement( |
michael@0 | 3136 | "INSERT OR REPLACE INTO object_data (object_store_id, key_value, data, " |
michael@0 | 3137 | "file_ids) " |
michael@0 | 3138 | "VALUES (:osid, :key_value, :data, :file_ids)"); |
michael@0 | 3139 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3140 | |
michael@0 | 3141 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 3142 | |
michael@0 | 3143 | rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), osid); |
michael@0 | 3144 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3145 | |
michael@0 | 3146 | NS_ASSERTION(!keyUnset || mObjectStore->IsAutoIncrement(), |
michael@0 | 3147 | "Should have key unless autoincrement"); |
michael@0 | 3148 | |
michael@0 | 3149 | int64_t autoIncrementNum = 0; |
michael@0 | 3150 | |
michael@0 | 3151 | if (mObjectStore->IsAutoIncrement()) { |
michael@0 | 3152 | if (keyUnset) { |
michael@0 | 3153 | autoIncrementNum = mObjectStore->Info()->nextAutoIncrementId; |
michael@0 | 3154 | |
michael@0 | 3155 | MOZ_ASSERT(autoIncrementNum > 0, |
michael@0 | 3156 | "Generated key must always be a positive integer"); |
michael@0 | 3157 | |
michael@0 | 3158 | if (autoIncrementNum > (1LL << 53)) { |
michael@0 | 3159 | IDB_REPORT_INTERNAL_ERR(); |
michael@0 | 3160 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 3161 | } |
michael@0 | 3162 | |
michael@0 | 3163 | mKey.SetFromInteger(autoIncrementNum); |
michael@0 | 3164 | } |
michael@0 | 3165 | else if (mKey.IsFloat() && |
michael@0 | 3166 | mKey.ToFloat() >= mObjectStore->Info()->nextAutoIncrementId) { |
michael@0 | 3167 | autoIncrementNum = floor(mKey.ToFloat()); |
michael@0 | 3168 | } |
michael@0 | 3169 | |
michael@0 | 3170 | if (keyUnset && keyPath.IsValid()) { |
michael@0 | 3171 | // Special case where someone put an object into an autoIncrement'ing |
michael@0 | 3172 | // objectStore with no key in its keyPath set. We needed to figure out |
michael@0 | 3173 | // which row id we would get above before we could set that properly. |
michael@0 | 3174 | |
michael@0 | 3175 | LittleEndian::writeUint64((char*)mCloneWriteInfo.mCloneBuffer.data() + |
michael@0 | 3176 | mCloneWriteInfo.mOffsetToKeyProp, |
michael@0 | 3177 | ReinterpretDoubleAsUInt64(static_cast<double>( |
michael@0 | 3178 | autoIncrementNum))); |
michael@0 | 3179 | } |
michael@0 | 3180 | } |
michael@0 | 3181 | |
michael@0 | 3182 | mKey.BindToStatement(stmt, NS_LITERAL_CSTRING("key_value")); |
michael@0 | 3183 | |
michael@0 | 3184 | |
michael@0 | 3185 | // Compress the bytes before adding into the database. |
michael@0 | 3186 | const char* uncompressed = |
michael@0 | 3187 | reinterpret_cast<const char*>(mCloneWriteInfo.mCloneBuffer.data()); |
michael@0 | 3188 | size_t uncompressedLength = mCloneWriteInfo.mCloneBuffer.nbytes(); |
michael@0 | 3189 | |
michael@0 | 3190 | // We don't have a smart pointer class that calls moz_free, so we need to |
michael@0 | 3191 | // manage | compressed | manually. |
michael@0 | 3192 | { |
michael@0 | 3193 | size_t compressedLength = snappy::MaxCompressedLength(uncompressedLength); |
michael@0 | 3194 | // moz_malloc is equivalent to NS_Alloc, which we use because mozStorage |
michael@0 | 3195 | // expects to be able to free the adopted pointer with NS_Free. |
michael@0 | 3196 | char* compressed = (char*)moz_malloc(compressedLength); |
michael@0 | 3197 | NS_ENSURE_TRUE(compressed, NS_ERROR_OUT_OF_MEMORY); |
michael@0 | 3198 | |
michael@0 | 3199 | snappy::RawCompress(uncompressed, uncompressedLength, compressed, |
michael@0 | 3200 | &compressedLength); |
michael@0 | 3201 | |
michael@0 | 3202 | uint8_t* dataBuffer = reinterpret_cast<uint8_t*>(compressed); |
michael@0 | 3203 | size_t dataBufferLength = compressedLength; |
michael@0 | 3204 | |
michael@0 | 3205 | // If this call succeeds, | compressed | is now owned by the statement, and |
michael@0 | 3206 | // we are no longer responsible for it. |
michael@0 | 3207 | rv = stmt->BindAdoptedBlobByName(NS_LITERAL_CSTRING("data"), dataBuffer, |
michael@0 | 3208 | dataBufferLength); |
michael@0 | 3209 | if (NS_FAILED(rv)) { |
michael@0 | 3210 | moz_free(compressed); |
michael@0 | 3211 | } |
michael@0 | 3212 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3213 | } |
michael@0 | 3214 | |
michael@0 | 3215 | // Handle blobs |
michael@0 | 3216 | uint32_t length = mCloneWriteInfo.mFiles.Length(); |
michael@0 | 3217 | if (length) { |
michael@0 | 3218 | nsRefPtr<FileManager> fileManager = mDatabase->Manager(); |
michael@0 | 3219 | |
michael@0 | 3220 | nsCOMPtr<nsIFile> directory = fileManager->GetDirectory(); |
michael@0 | 3221 | IDB_ENSURE_TRUE(directory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3222 | |
michael@0 | 3223 | nsCOMPtr<nsIFile> journalDirectory = fileManager->EnsureJournalDirectory(); |
michael@0 | 3224 | IDB_ENSURE_TRUE(journalDirectory, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3225 | |
michael@0 | 3226 | nsAutoString fileIds; |
michael@0 | 3227 | |
michael@0 | 3228 | for (uint32_t index = 0; index < length; index++) { |
michael@0 | 3229 | StructuredCloneFile& cloneFile = mCloneWriteInfo.mFiles[index]; |
michael@0 | 3230 | |
michael@0 | 3231 | FileInfo* fileInfo = cloneFile.mFileInfo; |
michael@0 | 3232 | nsIInputStream* inputStream = cloneFile.mInputStream; |
michael@0 | 3233 | |
michael@0 | 3234 | int64_t id = fileInfo->Id(); |
michael@0 | 3235 | if (inputStream) { |
michael@0 | 3236 | // Create a journal file first |
michael@0 | 3237 | nsCOMPtr<nsIFile> nativeFile = |
michael@0 | 3238 | fileManager->GetFileForId(journalDirectory, id); |
michael@0 | 3239 | IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3240 | |
michael@0 | 3241 | rv = nativeFile->Create(nsIFile::NORMAL_FILE_TYPE, 0644); |
michael@0 | 3242 | IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3243 | |
michael@0 | 3244 | // Now we can copy the blob |
michael@0 | 3245 | nativeFile = fileManager->GetFileForId(directory, id); |
michael@0 | 3246 | IDB_ENSURE_TRUE(nativeFile, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3247 | |
michael@0 | 3248 | IDBDatabase* database = mObjectStore->Transaction()->Database(); |
michael@0 | 3249 | nsRefPtr<FileOutputStream> outputStream = |
michael@0 | 3250 | FileOutputStream::Create(database->Type(), database->Group(), |
michael@0 | 3251 | database->Origin(), nativeFile); |
michael@0 | 3252 | IDB_ENSURE_TRUE(outputStream, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3253 | |
michael@0 | 3254 | rv = CopyData(inputStream, outputStream); |
michael@0 | 3255 | if (NS_FAILED(rv) && |
michael@0 | 3256 | NS_ERROR_GET_MODULE(rv) != NS_ERROR_MODULE_DOM_INDEXEDDB) { |
michael@0 | 3257 | IDB_REPORT_INTERNAL_ERR(); |
michael@0 | 3258 | rv = NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 3259 | } |
michael@0 | 3260 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 3261 | |
michael@0 | 3262 | cloneFile.mFile->AddFileInfo(fileInfo); |
michael@0 | 3263 | } |
michael@0 | 3264 | |
michael@0 | 3265 | if (index) { |
michael@0 | 3266 | fileIds.Append(NS_LITERAL_STRING(" ")); |
michael@0 | 3267 | } |
michael@0 | 3268 | fileIds.AppendInt(id); |
michael@0 | 3269 | } |
michael@0 | 3270 | |
michael@0 | 3271 | rv = stmt->BindStringByName(NS_LITERAL_CSTRING("file_ids"), fileIds); |
michael@0 | 3272 | } |
michael@0 | 3273 | else { |
michael@0 | 3274 | rv = stmt->BindNullByName(NS_LITERAL_CSTRING("file_ids")); |
michael@0 | 3275 | } |
michael@0 | 3276 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3277 | |
michael@0 | 3278 | rv = stmt->Execute(); |
michael@0 | 3279 | if (rv == NS_ERROR_STORAGE_CONSTRAINT) { |
michael@0 | 3280 | NS_ASSERTION(!keyUnset, "Generated key had a collision!?"); |
michael@0 | 3281 | return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; |
michael@0 | 3282 | } |
michael@0 | 3283 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3284 | |
michael@0 | 3285 | int64_t objectDataId; |
michael@0 | 3286 | rv = aConnection->GetLastInsertRowID(&objectDataId); |
michael@0 | 3287 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3288 | |
michael@0 | 3289 | // Update our indexes if needed. |
michael@0 | 3290 | if (mOverwrite || !mIndexUpdateInfo.IsEmpty()) { |
michael@0 | 3291 | rv = IDBObjectStore::UpdateIndexes(mTransaction, osid, mKey, mOverwrite, |
michael@0 | 3292 | objectDataId, mIndexUpdateInfo); |
michael@0 | 3293 | if (rv == NS_ERROR_STORAGE_CONSTRAINT) { |
michael@0 | 3294 | return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; |
michael@0 | 3295 | } |
michael@0 | 3296 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3297 | } |
michael@0 | 3298 | |
michael@0 | 3299 | if (autoIncrementNum) { |
michael@0 | 3300 | mObjectStore->Info()->nextAutoIncrementId = autoIncrementNum + 1; |
michael@0 | 3301 | } |
michael@0 | 3302 | |
michael@0 | 3303 | return NS_OK; |
michael@0 | 3304 | } |
michael@0 | 3305 | |
michael@0 | 3306 | nsresult |
michael@0 | 3307 | AddHelper::GetSuccessResult(JSContext* aCx, |
michael@0 | 3308 | JS::MutableHandle<JS::Value> aVal) |
michael@0 | 3309 | { |
michael@0 | 3310 | NS_ASSERTION(!mKey.IsUnset(), "Badness!"); |
michael@0 | 3311 | |
michael@0 | 3312 | mCloneWriteInfo.mCloneBuffer.clear(); |
michael@0 | 3313 | |
michael@0 | 3314 | return mKey.ToJSVal(aCx, aVal); |
michael@0 | 3315 | } |
michael@0 | 3316 | |
michael@0 | 3317 | void |
michael@0 | 3318 | AddHelper::ReleaseMainThreadObjects() |
michael@0 | 3319 | { |
michael@0 | 3320 | IDBObjectStore::ClearCloneWriteInfo(mCloneWriteInfo); |
michael@0 | 3321 | ObjectStoreHelper::ReleaseMainThreadObjects(); |
michael@0 | 3322 | } |
michael@0 | 3323 | |
michael@0 | 3324 | nsresult |
michael@0 | 3325 | AddHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) |
michael@0 | 3326 | { |
michael@0 | 3327 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3328 | NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3329 | |
michael@0 | 3330 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 3331 | "AddHelper::PackArgumentsForParentProcess"); |
michael@0 | 3332 | |
michael@0 | 3333 | AddPutParams commonParams; |
michael@0 | 3334 | commonParams.cloneInfo() = mCloneWriteInfo; |
michael@0 | 3335 | commonParams.key() = mKey; |
michael@0 | 3336 | commonParams.indexUpdateInfos().AppendElements(mIndexUpdateInfo); |
michael@0 | 3337 | |
michael@0 | 3338 | const nsTArray<StructuredCloneFile>& files = mCloneWriteInfo.mFiles; |
michael@0 | 3339 | |
michael@0 | 3340 | if (!files.IsEmpty()) { |
michael@0 | 3341 | uint32_t fileCount = files.Length(); |
michael@0 | 3342 | |
michael@0 | 3343 | InfallibleTArray<PBlobChild*>& blobsChild = commonParams.blobsChild(); |
michael@0 | 3344 | blobsChild.SetCapacity(fileCount); |
michael@0 | 3345 | |
michael@0 | 3346 | ContentChild* contentChild = ContentChild::GetSingleton(); |
michael@0 | 3347 | NS_ASSERTION(contentChild, "This should never be null!"); |
michael@0 | 3348 | |
michael@0 | 3349 | for (uint32_t index = 0; index < fileCount; index++) { |
michael@0 | 3350 | const StructuredCloneFile& file = files[index]; |
michael@0 | 3351 | |
michael@0 | 3352 | NS_ASSERTION(file.mFile, "This should never be null!"); |
michael@0 | 3353 | NS_ASSERTION(!file.mFileInfo, "This is not yet supported!"); |
michael@0 | 3354 | |
michael@0 | 3355 | BlobChild* actor = |
michael@0 | 3356 | contentChild->GetOrCreateActorForBlob(file.mFile); |
michael@0 | 3357 | if (!actor) { |
michael@0 | 3358 | IDB_REPORT_INTERNAL_ERR(); |
michael@0 | 3359 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 3360 | } |
michael@0 | 3361 | blobsChild.AppendElement(actor); |
michael@0 | 3362 | } |
michael@0 | 3363 | } |
michael@0 | 3364 | |
michael@0 | 3365 | if (mOverwrite) { |
michael@0 | 3366 | PutParams putParams; |
michael@0 | 3367 | putParams.commonParams() = commonParams; |
michael@0 | 3368 | aParams = putParams; |
michael@0 | 3369 | } |
michael@0 | 3370 | else { |
michael@0 | 3371 | AddParams addParams; |
michael@0 | 3372 | addParams.commonParams() = commonParams; |
michael@0 | 3373 | aParams = addParams; |
michael@0 | 3374 | } |
michael@0 | 3375 | |
michael@0 | 3376 | return NS_OK; |
michael@0 | 3377 | } |
michael@0 | 3378 | |
michael@0 | 3379 | AsyncConnectionHelper::ChildProcessSendResult |
michael@0 | 3380 | AddHelper::SendResponseToChildProcess(nsresult aResultCode) |
michael@0 | 3381 | { |
michael@0 | 3382 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3383 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3384 | |
michael@0 | 3385 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 3386 | "AddHelper::SendResponseToChildProcess"); |
michael@0 | 3387 | |
michael@0 | 3388 | IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); |
michael@0 | 3389 | NS_ASSERTION(actor, "How did we get this far without an actor?"); |
michael@0 | 3390 | |
michael@0 | 3391 | ResponseValue response; |
michael@0 | 3392 | if (NS_FAILED(aResultCode)) { |
michael@0 | 3393 | response = aResultCode; |
michael@0 | 3394 | } |
michael@0 | 3395 | else if (mOverwrite) { |
michael@0 | 3396 | PutResponse putResponse; |
michael@0 | 3397 | putResponse.key() = mKey; |
michael@0 | 3398 | response = putResponse; |
michael@0 | 3399 | } |
michael@0 | 3400 | else { |
michael@0 | 3401 | AddResponse addResponse; |
michael@0 | 3402 | addResponse.key() = mKey; |
michael@0 | 3403 | response = addResponse; |
michael@0 | 3404 | } |
michael@0 | 3405 | |
michael@0 | 3406 | if (!actor->SendResponse(response)) { |
michael@0 | 3407 | return Error; |
michael@0 | 3408 | } |
michael@0 | 3409 | |
michael@0 | 3410 | return Success_Sent; |
michael@0 | 3411 | } |
michael@0 | 3412 | |
michael@0 | 3413 | nsresult |
michael@0 | 3414 | AddHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 3415 | { |
michael@0 | 3416 | NS_ASSERTION(aResponseValue.type() == ResponseValue::TAddResponse || |
michael@0 | 3417 | aResponseValue.type() == ResponseValue::TPutResponse, |
michael@0 | 3418 | "Bad response type!"); |
michael@0 | 3419 | |
michael@0 | 3420 | mKey = mOverwrite ? |
michael@0 | 3421 | aResponseValue.get_PutResponse().key() : |
michael@0 | 3422 | aResponseValue.get_AddResponse().key(); |
michael@0 | 3423 | |
michael@0 | 3424 | return NS_OK; |
michael@0 | 3425 | } |
michael@0 | 3426 | |
michael@0 | 3427 | nsresult |
michael@0 | 3428 | GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) |
michael@0 | 3429 | { |
michael@0 | 3430 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3431 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3432 | NS_ASSERTION(mKeyRange, "Must have a key range here!"); |
michael@0 | 3433 | |
michael@0 | 3434 | PROFILER_LABEL("IndexedDB", "GetHelper::DoDatabaseWork [IDBObjectStore.cpp]"); |
michael@0 | 3435 | |
michael@0 | 3436 | nsCString keyRangeClause; |
michael@0 | 3437 | mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause); |
michael@0 | 3438 | |
michael@0 | 3439 | NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!"); |
michael@0 | 3440 | |
michael@0 | 3441 | nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data " |
michael@0 | 3442 | "WHERE object_store_id = :osid") + |
michael@0 | 3443 | keyRangeClause + NS_LITERAL_CSTRING(" LIMIT 1"); |
michael@0 | 3444 | |
michael@0 | 3445 | nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); |
michael@0 | 3446 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3447 | |
michael@0 | 3448 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 3449 | |
michael@0 | 3450 | nsresult rv = |
michael@0 | 3451 | stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), mObjectStore->Id()); |
michael@0 | 3452 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3453 | |
michael@0 | 3454 | rv = mKeyRange->BindToStatement(stmt); |
michael@0 | 3455 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 3456 | |
michael@0 | 3457 | bool hasResult; |
michael@0 | 3458 | rv = stmt->ExecuteStep(&hasResult); |
michael@0 | 3459 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3460 | |
michael@0 | 3461 | if (hasResult) { |
michael@0 | 3462 | rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1, |
michael@0 | 3463 | mDatabase, mCloneReadInfo); |
michael@0 | 3464 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 3465 | } |
michael@0 | 3466 | |
michael@0 | 3467 | return NS_OK; |
michael@0 | 3468 | } |
michael@0 | 3469 | |
michael@0 | 3470 | nsresult |
michael@0 | 3471 | GetHelper::GetSuccessResult(JSContext* aCx, |
michael@0 | 3472 | JS::MutableHandle<JS::Value> aVal) |
michael@0 | 3473 | { |
michael@0 | 3474 | bool result = IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, aVal); |
michael@0 | 3475 | |
michael@0 | 3476 | mCloneReadInfo.mCloneBuffer.clear(); |
michael@0 | 3477 | |
michael@0 | 3478 | NS_ENSURE_TRUE(result, NS_ERROR_DOM_DATA_CLONE_ERR); |
michael@0 | 3479 | return NS_OK; |
michael@0 | 3480 | } |
michael@0 | 3481 | |
michael@0 | 3482 | void |
michael@0 | 3483 | GetHelper::ReleaseMainThreadObjects() |
michael@0 | 3484 | { |
michael@0 | 3485 | mKeyRange = nullptr; |
michael@0 | 3486 | IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo); |
michael@0 | 3487 | ObjectStoreHelper::ReleaseMainThreadObjects(); |
michael@0 | 3488 | } |
michael@0 | 3489 | |
michael@0 | 3490 | nsresult |
michael@0 | 3491 | GetHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) |
michael@0 | 3492 | { |
michael@0 | 3493 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3494 | NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3495 | NS_ASSERTION(mKeyRange, "This should never be null!"); |
michael@0 | 3496 | |
michael@0 | 3497 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 3498 | "GetHelper::PackArgumentsForParentProcess " |
michael@0 | 3499 | "[IDBObjectStore.cpp]"); |
michael@0 | 3500 | |
michael@0 | 3501 | GetParams params; |
michael@0 | 3502 | |
michael@0 | 3503 | mKeyRange->ToSerializedKeyRange(params.keyRange()); |
michael@0 | 3504 | |
michael@0 | 3505 | aParams = params; |
michael@0 | 3506 | return NS_OK; |
michael@0 | 3507 | } |
michael@0 | 3508 | |
michael@0 | 3509 | AsyncConnectionHelper::ChildProcessSendResult |
michael@0 | 3510 | GetHelper::SendResponseToChildProcess(nsresult aResultCode) |
michael@0 | 3511 | { |
michael@0 | 3512 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3513 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3514 | |
michael@0 | 3515 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 3516 | "GetHelper::SendResponseToChildProcess " |
michael@0 | 3517 | "[IDBObjectStore.cpp]"); |
michael@0 | 3518 | |
michael@0 | 3519 | IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); |
michael@0 | 3520 | NS_ASSERTION(actor, "How did we get this far without an actor?"); |
michael@0 | 3521 | |
michael@0 | 3522 | InfallibleTArray<PBlobParent*> blobsParent; |
michael@0 | 3523 | |
michael@0 | 3524 | if (NS_SUCCEEDED(aResultCode)) { |
michael@0 | 3525 | IDBDatabase* database = mObjectStore->Transaction()->Database(); |
michael@0 | 3526 | NS_ASSERTION(database, "This should never be null!"); |
michael@0 | 3527 | |
michael@0 | 3528 | ContentParent* contentParent = database->GetContentParent(); |
michael@0 | 3529 | NS_ASSERTION(contentParent, "This should never be null!"); |
michael@0 | 3530 | |
michael@0 | 3531 | FileManager* fileManager = database->Manager(); |
michael@0 | 3532 | NS_ASSERTION(fileManager, "This should never be null!"); |
michael@0 | 3533 | |
michael@0 | 3534 | const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles; |
michael@0 | 3535 | |
michael@0 | 3536 | aResultCode = |
michael@0 | 3537 | IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files, |
michael@0 | 3538 | blobsParent); |
michael@0 | 3539 | if (NS_FAILED(aResultCode)) { |
michael@0 | 3540 | NS_WARNING("ConvertBlobsToActors failed!"); |
michael@0 | 3541 | } |
michael@0 | 3542 | } |
michael@0 | 3543 | |
michael@0 | 3544 | ResponseValue response; |
michael@0 | 3545 | if (NS_FAILED(aResultCode)) { |
michael@0 | 3546 | response = aResultCode; |
michael@0 | 3547 | } |
michael@0 | 3548 | else { |
michael@0 | 3549 | GetResponse getResponse; |
michael@0 | 3550 | getResponse.cloneInfo() = mCloneReadInfo; |
michael@0 | 3551 | getResponse.blobsParent().SwapElements(blobsParent); |
michael@0 | 3552 | response = getResponse; |
michael@0 | 3553 | } |
michael@0 | 3554 | |
michael@0 | 3555 | if (!actor->SendResponse(response)) { |
michael@0 | 3556 | return Error; |
michael@0 | 3557 | } |
michael@0 | 3558 | |
michael@0 | 3559 | return Success_Sent; |
michael@0 | 3560 | } |
michael@0 | 3561 | |
michael@0 | 3562 | nsresult |
michael@0 | 3563 | GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) |
michael@0 | 3564 | { |
michael@0 | 3565 | NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse, |
michael@0 | 3566 | "Bad response type!"); |
michael@0 | 3567 | |
michael@0 | 3568 | const GetResponse& getResponse = aResponseValue.get_GetResponse(); |
michael@0 | 3569 | const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo(); |
michael@0 | 3570 | |
michael@0 | 3571 | NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) || |
michael@0 | 3572 | (cloneInfo.dataLength && cloneInfo.data), |
michael@0 | 3573 | "Inconsistent clone info!"); |
michael@0 | 3574 | |
michael@0 | 3575 | if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) { |
michael@0 | 3576 | IDB_WARNING("Failed to copy clone buffer!"); |
michael@0 | 3577 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 3578 | } |
michael@0 | 3579 | |
michael@0 | 3580 | IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(), |
michael@0 | 3581 | mCloneReadInfo.mFiles); |
michael@0 | 3582 | return NS_OK; |
michael@0 | 3583 | } |
michael@0 | 3584 | |
michael@0 | 3585 | nsresult |
michael@0 | 3586 | DeleteHelper::DoDatabaseWork(mozIStorageConnection* /*aConnection */) |
michael@0 | 3587 | { |
michael@0 | 3588 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3589 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3590 | NS_ASSERTION(mKeyRange, "Must have a key range here!"); |
michael@0 | 3591 | |
michael@0 | 3592 | PROFILER_LABEL("IndexedDB", "DeleteHelper::DoDatabaseWork"); |
michael@0 | 3593 | |
michael@0 | 3594 | nsCString keyRangeClause; |
michael@0 | 3595 | mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("key_value"), keyRangeClause); |
michael@0 | 3596 | |
michael@0 | 3597 | NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!"); |
michael@0 | 3598 | |
michael@0 | 3599 | nsCString query = NS_LITERAL_CSTRING("DELETE FROM object_data " |
michael@0 | 3600 | "WHERE object_store_id = :osid") + |
michael@0 | 3601 | keyRangeClause; |
michael@0 | 3602 | |
michael@0 | 3603 | nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); |
michael@0 | 3604 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3605 | |
michael@0 | 3606 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 3607 | |
michael@0 | 3608 | nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), |
michael@0 | 3609 | mObjectStore->Id()); |
michael@0 | 3610 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3611 | |
michael@0 | 3612 | rv = mKeyRange->BindToStatement(stmt); |
michael@0 | 3613 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 3614 | |
michael@0 | 3615 | rv = stmt->Execute(); |
michael@0 | 3616 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3617 | |
michael@0 | 3618 | return NS_OK; |
michael@0 | 3619 | } |
michael@0 | 3620 | |
michael@0 | 3621 | nsresult |
michael@0 | 3622 | DeleteHelper::GetSuccessResult(JSContext* aCx, |
michael@0 | 3623 | JS::MutableHandle<JS::Value> aVal) |
michael@0 | 3624 | { |
michael@0 | 3625 | aVal.setUndefined(); |
michael@0 | 3626 | return NS_OK; |
michael@0 | 3627 | } |
michael@0 | 3628 | |
michael@0 | 3629 | nsresult |
michael@0 | 3630 | DeleteHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) |
michael@0 | 3631 | { |
michael@0 | 3632 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3633 | NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3634 | NS_ASSERTION(mKeyRange, "This should never be null!"); |
michael@0 | 3635 | |
michael@0 | 3636 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 3637 | "DeleteHelper::PackArgumentsForParentProcess"); |
michael@0 | 3638 | |
michael@0 | 3639 | DeleteParams params; |
michael@0 | 3640 | |
michael@0 | 3641 | mKeyRange->ToSerializedKeyRange(params.keyRange()); |
michael@0 | 3642 | |
michael@0 | 3643 | aParams = params; |
michael@0 | 3644 | return NS_OK; |
michael@0 | 3645 | } |
michael@0 | 3646 | |
michael@0 | 3647 | AsyncConnectionHelper::ChildProcessSendResult |
michael@0 | 3648 | DeleteHelper::SendResponseToChildProcess(nsresult aResultCode) |
michael@0 | 3649 | { |
michael@0 | 3650 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3651 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3652 | |
michael@0 | 3653 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 3654 | "DeleteHelper::SendResponseToChildProcess"); |
michael@0 | 3655 | |
michael@0 | 3656 | IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); |
michael@0 | 3657 | NS_ASSERTION(actor, "How did we get this far without an actor?"); |
michael@0 | 3658 | |
michael@0 | 3659 | ResponseValue response; |
michael@0 | 3660 | if (NS_FAILED(aResultCode)) { |
michael@0 | 3661 | response = aResultCode; |
michael@0 | 3662 | } |
michael@0 | 3663 | else { |
michael@0 | 3664 | response = DeleteResponse(); |
michael@0 | 3665 | } |
michael@0 | 3666 | |
michael@0 | 3667 | if (!actor->SendResponse(response)) { |
michael@0 | 3668 | return Error; |
michael@0 | 3669 | } |
michael@0 | 3670 | |
michael@0 | 3671 | return Success_Sent; |
michael@0 | 3672 | } |
michael@0 | 3673 | |
michael@0 | 3674 | nsresult |
michael@0 | 3675 | DeleteHelper::UnpackResponseFromParentProcess( |
michael@0 | 3676 | const ResponseValue& aResponseValue) |
michael@0 | 3677 | { |
michael@0 | 3678 | NS_ASSERTION(aResponseValue.type() == ResponseValue::TDeleteResponse, |
michael@0 | 3679 | "Bad response type!"); |
michael@0 | 3680 | |
michael@0 | 3681 | return NS_OK; |
michael@0 | 3682 | } |
michael@0 | 3683 | |
michael@0 | 3684 | nsresult |
michael@0 | 3685 | ClearHelper::DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 3686 | { |
michael@0 | 3687 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3688 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3689 | NS_ASSERTION(aConnection, "Passed a null connection!"); |
michael@0 | 3690 | |
michael@0 | 3691 | PROFILER_LABEL("IndexedDB", "ClearHelper::DoDatabaseWork"); |
michael@0 | 3692 | |
michael@0 | 3693 | nsCOMPtr<mozIStorageStatement> stmt = |
michael@0 | 3694 | mTransaction->GetCachedStatement( |
michael@0 | 3695 | NS_LITERAL_CSTRING("DELETE FROM object_data " |
michael@0 | 3696 | "WHERE object_store_id = :osid")); |
michael@0 | 3697 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3698 | |
michael@0 | 3699 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 3700 | |
michael@0 | 3701 | nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), |
michael@0 | 3702 | mObjectStore->Id()); |
michael@0 | 3703 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3704 | |
michael@0 | 3705 | rv = stmt->Execute(); |
michael@0 | 3706 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3707 | |
michael@0 | 3708 | return NS_OK; |
michael@0 | 3709 | } |
michael@0 | 3710 | |
michael@0 | 3711 | nsresult |
michael@0 | 3712 | ClearHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) |
michael@0 | 3713 | { |
michael@0 | 3714 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3715 | NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3716 | |
michael@0 | 3717 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 3718 | "ClearHelper::PackArgumentsForParentProcess"); |
michael@0 | 3719 | |
michael@0 | 3720 | aParams = ClearParams(); |
michael@0 | 3721 | return NS_OK; |
michael@0 | 3722 | } |
michael@0 | 3723 | |
michael@0 | 3724 | AsyncConnectionHelper::ChildProcessSendResult |
michael@0 | 3725 | ClearHelper::SendResponseToChildProcess(nsresult aResultCode) |
michael@0 | 3726 | { |
michael@0 | 3727 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3728 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3729 | |
michael@0 | 3730 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 3731 | "ClearHelper::SendResponseToChildProcess"); |
michael@0 | 3732 | |
michael@0 | 3733 | IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); |
michael@0 | 3734 | NS_ASSERTION(actor, "How did we get this far without an actor?"); |
michael@0 | 3735 | |
michael@0 | 3736 | ResponseValue response; |
michael@0 | 3737 | if (NS_FAILED(aResultCode)) { |
michael@0 | 3738 | response = aResultCode; |
michael@0 | 3739 | } |
michael@0 | 3740 | else { |
michael@0 | 3741 | response = ClearResponse(); |
michael@0 | 3742 | } |
michael@0 | 3743 | |
michael@0 | 3744 | if (!actor->SendResponse(response)) { |
michael@0 | 3745 | return Error; |
michael@0 | 3746 | } |
michael@0 | 3747 | |
michael@0 | 3748 | return Success_Sent; |
michael@0 | 3749 | } |
michael@0 | 3750 | |
michael@0 | 3751 | nsresult |
michael@0 | 3752 | ClearHelper::UnpackResponseFromParentProcess( |
michael@0 | 3753 | const ResponseValue& aResponseValue) |
michael@0 | 3754 | { |
michael@0 | 3755 | NS_ASSERTION(aResponseValue.type() == ResponseValue::TClearResponse, |
michael@0 | 3756 | "Bad response type!"); |
michael@0 | 3757 | |
michael@0 | 3758 | return NS_OK; |
michael@0 | 3759 | } |
michael@0 | 3760 | |
michael@0 | 3761 | nsresult |
michael@0 | 3762 | OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 3763 | { |
michael@0 | 3764 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3765 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3766 | |
michael@0 | 3767 | PROFILER_LABEL("IndexedDB", |
michael@0 | 3768 | "OpenCursorHelper::DoDatabaseWork [IDBObjectStore.cpp]"); |
michael@0 | 3769 | |
michael@0 | 3770 | NS_NAMED_LITERAL_CSTRING(keyValue, "key_value"); |
michael@0 | 3771 | |
michael@0 | 3772 | nsCString keyRangeClause; |
michael@0 | 3773 | if (mKeyRange) { |
michael@0 | 3774 | mKeyRange->GetBindingClause(keyValue, keyRangeClause); |
michael@0 | 3775 | } |
michael@0 | 3776 | |
michael@0 | 3777 | nsAutoCString directionClause; |
michael@0 | 3778 | switch (mDirection) { |
michael@0 | 3779 | case IDBCursor::NEXT: |
michael@0 | 3780 | case IDBCursor::NEXT_UNIQUE: |
michael@0 | 3781 | directionClause.AssignLiteral(" ORDER BY key_value ASC"); |
michael@0 | 3782 | break; |
michael@0 | 3783 | |
michael@0 | 3784 | case IDBCursor::PREV: |
michael@0 | 3785 | case IDBCursor::PREV_UNIQUE: |
michael@0 | 3786 | directionClause.AssignLiteral(" ORDER BY key_value DESC"); |
michael@0 | 3787 | break; |
michael@0 | 3788 | |
michael@0 | 3789 | default: |
michael@0 | 3790 | NS_NOTREACHED("Unknown direction type!"); |
michael@0 | 3791 | } |
michael@0 | 3792 | |
michael@0 | 3793 | nsCString firstQuery = NS_LITERAL_CSTRING("SELECT key_value, data, file_ids " |
michael@0 | 3794 | "FROM object_data " |
michael@0 | 3795 | "WHERE object_store_id = :id") + |
michael@0 | 3796 | keyRangeClause + directionClause + |
michael@0 | 3797 | NS_LITERAL_CSTRING(" LIMIT 1"); |
michael@0 | 3798 | |
michael@0 | 3799 | nsCOMPtr<mozIStorageStatement> stmt = |
michael@0 | 3800 | mTransaction->GetCachedStatement(firstQuery); |
michael@0 | 3801 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3802 | |
michael@0 | 3803 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 3804 | |
michael@0 | 3805 | nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), |
michael@0 | 3806 | mObjectStore->Id()); |
michael@0 | 3807 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3808 | |
michael@0 | 3809 | if (mKeyRange) { |
michael@0 | 3810 | rv = mKeyRange->BindToStatement(stmt); |
michael@0 | 3811 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 3812 | } |
michael@0 | 3813 | |
michael@0 | 3814 | bool hasResult; |
michael@0 | 3815 | rv = stmt->ExecuteStep(&hasResult); |
michael@0 | 3816 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3817 | |
michael@0 | 3818 | if (!hasResult) { |
michael@0 | 3819 | mKey.Unset(); |
michael@0 | 3820 | return NS_OK; |
michael@0 | 3821 | } |
michael@0 | 3822 | |
michael@0 | 3823 | rv = mKey.SetFromStatement(stmt, 0); |
michael@0 | 3824 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 3825 | |
michael@0 | 3826 | rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 1, 2, |
michael@0 | 3827 | mDatabase, mCloneReadInfo); |
michael@0 | 3828 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 3829 | |
michael@0 | 3830 | // Now we need to make the query to get the next match. |
michael@0 | 3831 | keyRangeClause.Truncate(); |
michael@0 | 3832 | nsAutoCString continueToKeyRangeClause; |
michael@0 | 3833 | |
michael@0 | 3834 | NS_NAMED_LITERAL_CSTRING(currentKey, "current_key"); |
michael@0 | 3835 | NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key"); |
michael@0 | 3836 | |
michael@0 | 3837 | switch (mDirection) { |
michael@0 | 3838 | case IDBCursor::NEXT: |
michael@0 | 3839 | case IDBCursor::NEXT_UNIQUE: |
michael@0 | 3840 | AppendConditionClause(keyValue, currentKey, false, false, |
michael@0 | 3841 | keyRangeClause); |
michael@0 | 3842 | AppendConditionClause(keyValue, currentKey, false, true, |
michael@0 | 3843 | continueToKeyRangeClause); |
michael@0 | 3844 | if (mKeyRange && !mKeyRange->Upper().IsUnset()) { |
michael@0 | 3845 | AppendConditionClause(keyValue, rangeKey, true, |
michael@0 | 3846 | !mKeyRange->IsUpperOpen(), keyRangeClause); |
michael@0 | 3847 | AppendConditionClause(keyValue, rangeKey, true, |
michael@0 | 3848 | !mKeyRange->IsUpperOpen(), |
michael@0 | 3849 | continueToKeyRangeClause); |
michael@0 | 3850 | mRangeKey = mKeyRange->Upper(); |
michael@0 | 3851 | } |
michael@0 | 3852 | break; |
michael@0 | 3853 | |
michael@0 | 3854 | case IDBCursor::PREV: |
michael@0 | 3855 | case IDBCursor::PREV_UNIQUE: |
michael@0 | 3856 | AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause); |
michael@0 | 3857 | AppendConditionClause(keyValue, currentKey, true, true, |
michael@0 | 3858 | continueToKeyRangeClause); |
michael@0 | 3859 | if (mKeyRange && !mKeyRange->Lower().IsUnset()) { |
michael@0 | 3860 | AppendConditionClause(keyValue, rangeKey, false, |
michael@0 | 3861 | !mKeyRange->IsLowerOpen(), keyRangeClause); |
michael@0 | 3862 | AppendConditionClause(keyValue, rangeKey, false, |
michael@0 | 3863 | !mKeyRange->IsLowerOpen(), |
michael@0 | 3864 | continueToKeyRangeClause); |
michael@0 | 3865 | mRangeKey = mKeyRange->Lower(); |
michael@0 | 3866 | } |
michael@0 | 3867 | break; |
michael@0 | 3868 | |
michael@0 | 3869 | default: |
michael@0 | 3870 | NS_NOTREACHED("Unknown direction type!"); |
michael@0 | 3871 | } |
michael@0 | 3872 | |
michael@0 | 3873 | NS_NAMED_LITERAL_CSTRING(queryStart, "SELECT key_value, data, file_ids " |
michael@0 | 3874 | "FROM object_data " |
michael@0 | 3875 | "WHERE object_store_id = :id"); |
michael@0 | 3876 | |
michael@0 | 3877 | mContinueQuery = queryStart + keyRangeClause + directionClause + |
michael@0 | 3878 | NS_LITERAL_CSTRING(" LIMIT "); |
michael@0 | 3879 | |
michael@0 | 3880 | mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause + |
michael@0 | 3881 | NS_LITERAL_CSTRING(" LIMIT "); |
michael@0 | 3882 | |
michael@0 | 3883 | return NS_OK; |
michael@0 | 3884 | } |
michael@0 | 3885 | |
michael@0 | 3886 | nsresult |
michael@0 | 3887 | OpenCursorHelper::EnsureCursor() |
michael@0 | 3888 | { |
michael@0 | 3889 | if (mCursor || mKey.IsUnset()) { |
michael@0 | 3890 | return NS_OK; |
michael@0 | 3891 | } |
michael@0 | 3892 | |
michael@0 | 3893 | mSerializedCloneReadInfo = mCloneReadInfo; |
michael@0 | 3894 | |
michael@0 | 3895 | NS_ASSERTION(mSerializedCloneReadInfo.data && |
michael@0 | 3896 | mSerializedCloneReadInfo.dataLength, |
michael@0 | 3897 | "Shouldn't be possible!"); |
michael@0 | 3898 | |
michael@0 | 3899 | nsRefPtr<IDBCursor> cursor = |
michael@0 | 3900 | IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection, |
michael@0 | 3901 | mRangeKey, mContinueQuery, mContinueToQuery, mKey, |
michael@0 | 3902 | Move(mCloneReadInfo)); |
michael@0 | 3903 | IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3904 | |
michael@0 | 3905 | NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!"); |
michael@0 | 3906 | |
michael@0 | 3907 | mCursor.swap(cursor); |
michael@0 | 3908 | return NS_OK; |
michael@0 | 3909 | } |
michael@0 | 3910 | |
michael@0 | 3911 | nsresult |
michael@0 | 3912 | OpenCursorHelper::GetSuccessResult(JSContext* aCx, |
michael@0 | 3913 | JS::MutableHandle<JS::Value> aVal) |
michael@0 | 3914 | { |
michael@0 | 3915 | nsresult rv = EnsureCursor(); |
michael@0 | 3916 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 3917 | |
michael@0 | 3918 | if (mCursor) { |
michael@0 | 3919 | rv = WrapNative(aCx, mCursor, aVal); |
michael@0 | 3920 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 3921 | } |
michael@0 | 3922 | else { |
michael@0 | 3923 | aVal.setUndefined(); |
michael@0 | 3924 | } |
michael@0 | 3925 | |
michael@0 | 3926 | return NS_OK; |
michael@0 | 3927 | } |
michael@0 | 3928 | |
michael@0 | 3929 | void |
michael@0 | 3930 | OpenCursorHelper::ReleaseMainThreadObjects() |
michael@0 | 3931 | { |
michael@0 | 3932 | mKeyRange = nullptr; |
michael@0 | 3933 | IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo); |
michael@0 | 3934 | |
michael@0 | 3935 | mCursor = nullptr; |
michael@0 | 3936 | |
michael@0 | 3937 | // These don't need to be released on the main thread but they're only valid |
michael@0 | 3938 | // as long as mCursor is set. |
michael@0 | 3939 | mSerializedCloneReadInfo.data = nullptr; |
michael@0 | 3940 | mSerializedCloneReadInfo.dataLength = 0; |
michael@0 | 3941 | |
michael@0 | 3942 | ObjectStoreHelper::ReleaseMainThreadObjects(); |
michael@0 | 3943 | } |
michael@0 | 3944 | |
michael@0 | 3945 | nsresult |
michael@0 | 3946 | OpenCursorHelper::PackArgumentsForParentProcess( |
michael@0 | 3947 | ObjectStoreRequestParams& aParams) |
michael@0 | 3948 | { |
michael@0 | 3949 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3950 | NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3951 | |
michael@0 | 3952 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 3953 | "OpenCursorHelper::PackArgumentsForParentProcess " |
michael@0 | 3954 | "[IDBObjectStore.cpp]"); |
michael@0 | 3955 | |
michael@0 | 3956 | OpenCursorParams params; |
michael@0 | 3957 | |
michael@0 | 3958 | if (mKeyRange) { |
michael@0 | 3959 | KeyRange keyRange; |
michael@0 | 3960 | mKeyRange->ToSerializedKeyRange(keyRange); |
michael@0 | 3961 | params.optionalKeyRange() = keyRange; |
michael@0 | 3962 | } |
michael@0 | 3963 | else { |
michael@0 | 3964 | params.optionalKeyRange() = mozilla::void_t(); |
michael@0 | 3965 | } |
michael@0 | 3966 | |
michael@0 | 3967 | params.direction() = mDirection; |
michael@0 | 3968 | |
michael@0 | 3969 | aParams = params; |
michael@0 | 3970 | return NS_OK; |
michael@0 | 3971 | } |
michael@0 | 3972 | |
michael@0 | 3973 | AsyncConnectionHelper::ChildProcessSendResult |
michael@0 | 3974 | OpenCursorHelper::SendResponseToChildProcess(nsresult aResultCode) |
michael@0 | 3975 | { |
michael@0 | 3976 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 3977 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 3978 | NS_ASSERTION(!mCursor, "Shouldn't have this yet!"); |
michael@0 | 3979 | |
michael@0 | 3980 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 3981 | "OpenCursorHelper::SendResponseToChildProcess " |
michael@0 | 3982 | "[IDBObjectStore.cpp]"); |
michael@0 | 3983 | |
michael@0 | 3984 | IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); |
michael@0 | 3985 | NS_ASSERTION(actor, "How did we get this far without an actor?"); |
michael@0 | 3986 | |
michael@0 | 3987 | InfallibleTArray<PBlobParent*> blobsParent; |
michael@0 | 3988 | |
michael@0 | 3989 | if (NS_SUCCEEDED(aResultCode)) { |
michael@0 | 3990 | IDBDatabase* database = mObjectStore->Transaction()->Database(); |
michael@0 | 3991 | NS_ASSERTION(database, "This should never be null!"); |
michael@0 | 3992 | |
michael@0 | 3993 | ContentParent* contentParent = database->GetContentParent(); |
michael@0 | 3994 | NS_ASSERTION(contentParent, "This should never be null!"); |
michael@0 | 3995 | |
michael@0 | 3996 | FileManager* fileManager = database->Manager(); |
michael@0 | 3997 | NS_ASSERTION(fileManager, "This should never be null!"); |
michael@0 | 3998 | |
michael@0 | 3999 | const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles; |
michael@0 | 4000 | |
michael@0 | 4001 | aResultCode = |
michael@0 | 4002 | IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files, |
michael@0 | 4003 | blobsParent); |
michael@0 | 4004 | if (NS_FAILED(aResultCode)) { |
michael@0 | 4005 | NS_WARNING("ConvertBlobsToActors failed!"); |
michael@0 | 4006 | } |
michael@0 | 4007 | } |
michael@0 | 4008 | |
michael@0 | 4009 | if (NS_SUCCEEDED(aResultCode)) { |
michael@0 | 4010 | nsresult rv = EnsureCursor(); |
michael@0 | 4011 | if (NS_FAILED(rv)) { |
michael@0 | 4012 | NS_WARNING("EnsureCursor failed!"); |
michael@0 | 4013 | aResultCode = rv; |
michael@0 | 4014 | } |
michael@0 | 4015 | } |
michael@0 | 4016 | |
michael@0 | 4017 | ResponseValue response; |
michael@0 | 4018 | if (NS_FAILED(aResultCode)) { |
michael@0 | 4019 | response = aResultCode; |
michael@0 | 4020 | } |
michael@0 | 4021 | else { |
michael@0 | 4022 | OpenCursorResponse openCursorResponse; |
michael@0 | 4023 | |
michael@0 | 4024 | if (!mCursor) { |
michael@0 | 4025 | openCursorResponse = mozilla::void_t(); |
michael@0 | 4026 | } |
michael@0 | 4027 | else { |
michael@0 | 4028 | IndexedDBObjectStoreParent* objectStoreActor = |
michael@0 | 4029 | mObjectStore->GetActorParent(); |
michael@0 | 4030 | NS_ASSERTION(objectStoreActor, "Must have an actor here!"); |
michael@0 | 4031 | |
michael@0 | 4032 | IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent(); |
michael@0 | 4033 | NS_ASSERTION(requestActor, "Must have an actor here!"); |
michael@0 | 4034 | |
michael@0 | 4035 | NS_ASSERTION(mSerializedCloneReadInfo.data && |
michael@0 | 4036 | mSerializedCloneReadInfo.dataLength, |
michael@0 | 4037 | "Shouldn't be possible!"); |
michael@0 | 4038 | |
michael@0 | 4039 | ObjectStoreCursorConstructorParams params; |
michael@0 | 4040 | params.requestParent() = requestActor; |
michael@0 | 4041 | params.direction() = mDirection; |
michael@0 | 4042 | params.key() = mKey; |
michael@0 | 4043 | params.optionalCloneInfo() = mSerializedCloneReadInfo; |
michael@0 | 4044 | params.blobsParent().SwapElements(blobsParent); |
michael@0 | 4045 | |
michael@0 | 4046 | if (!objectStoreActor->OpenCursor(mCursor, params, openCursorResponse)) { |
michael@0 | 4047 | return Error; |
michael@0 | 4048 | } |
michael@0 | 4049 | } |
michael@0 | 4050 | |
michael@0 | 4051 | response = openCursorResponse; |
michael@0 | 4052 | } |
michael@0 | 4053 | |
michael@0 | 4054 | if (!actor->SendResponse(response)) { |
michael@0 | 4055 | return Error; |
michael@0 | 4056 | } |
michael@0 | 4057 | |
michael@0 | 4058 | return Success_Sent; |
michael@0 | 4059 | } |
michael@0 | 4060 | |
michael@0 | 4061 | nsresult |
michael@0 | 4062 | OpenCursorHelper::UnpackResponseFromParentProcess( |
michael@0 | 4063 | const ResponseValue& aResponseValue) |
michael@0 | 4064 | { |
michael@0 | 4065 | NS_ASSERTION(aResponseValue.type() == ResponseValue::TOpenCursorResponse, |
michael@0 | 4066 | "Bad response type!"); |
michael@0 | 4067 | NS_ASSERTION(aResponseValue.get_OpenCursorResponse().type() == |
michael@0 | 4068 | OpenCursorResponse::Tvoid_t || |
michael@0 | 4069 | aResponseValue.get_OpenCursorResponse().type() == |
michael@0 | 4070 | OpenCursorResponse::TPIndexedDBCursorChild, |
michael@0 | 4071 | "Bad response union type!"); |
michael@0 | 4072 | NS_ASSERTION(!mCursor, "Shouldn't have this yet!"); |
michael@0 | 4073 | |
michael@0 | 4074 | const OpenCursorResponse& response = |
michael@0 | 4075 | aResponseValue.get_OpenCursorResponse(); |
michael@0 | 4076 | |
michael@0 | 4077 | switch (response.type()) { |
michael@0 | 4078 | case OpenCursorResponse::Tvoid_t: |
michael@0 | 4079 | break; |
michael@0 | 4080 | |
michael@0 | 4081 | case OpenCursorResponse::TPIndexedDBCursorChild: { |
michael@0 | 4082 | IndexedDBCursorChild* actor = |
michael@0 | 4083 | static_cast<IndexedDBCursorChild*>( |
michael@0 | 4084 | response.get_PIndexedDBCursorChild()); |
michael@0 | 4085 | |
michael@0 | 4086 | mCursor = actor->ForgetStrongCursor(); |
michael@0 | 4087 | NS_ASSERTION(mCursor, "This should never be null!"); |
michael@0 | 4088 | |
michael@0 | 4089 | } break; |
michael@0 | 4090 | |
michael@0 | 4091 | default: |
michael@0 | 4092 | MOZ_CRASH(); |
michael@0 | 4093 | } |
michael@0 | 4094 | |
michael@0 | 4095 | return NS_OK; |
michael@0 | 4096 | } |
michael@0 | 4097 | |
michael@0 | 4098 | nsresult |
michael@0 | 4099 | OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) |
michael@0 | 4100 | { |
michael@0 | 4101 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 4102 | MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess()); |
michael@0 | 4103 | |
michael@0 | 4104 | PROFILER_LABEL("IndexedDB", |
michael@0 | 4105 | "OpenKeyCursorHelper::DoDatabaseWork [IDBObjectStore.cpp]"); |
michael@0 | 4106 | |
michael@0 | 4107 | NS_NAMED_LITERAL_CSTRING(keyValue, "key_value"); |
michael@0 | 4108 | NS_NAMED_LITERAL_CSTRING(id, "id"); |
michael@0 | 4109 | NS_NAMED_LITERAL_CSTRING(openLimit, " LIMIT "); |
michael@0 | 4110 | |
michael@0 | 4111 | nsAutoCString queryStart = NS_LITERAL_CSTRING("SELECT ") + keyValue + |
michael@0 | 4112 | NS_LITERAL_CSTRING(" FROM object_data WHERE " |
michael@0 | 4113 | "object_store_id = :") + |
michael@0 | 4114 | id; |
michael@0 | 4115 | |
michael@0 | 4116 | nsAutoCString keyRangeClause; |
michael@0 | 4117 | if (mKeyRange) { |
michael@0 | 4118 | mKeyRange->GetBindingClause(keyValue, keyRangeClause); |
michael@0 | 4119 | } |
michael@0 | 4120 | |
michael@0 | 4121 | nsAutoCString directionClause = NS_LITERAL_CSTRING(" ORDER BY ") + keyValue; |
michael@0 | 4122 | switch (mDirection) { |
michael@0 | 4123 | case IDBCursor::NEXT: |
michael@0 | 4124 | case IDBCursor::NEXT_UNIQUE: |
michael@0 | 4125 | directionClause.AppendLiteral(" ASC"); |
michael@0 | 4126 | break; |
michael@0 | 4127 | |
michael@0 | 4128 | case IDBCursor::PREV: |
michael@0 | 4129 | case IDBCursor::PREV_UNIQUE: |
michael@0 | 4130 | directionClause.AppendLiteral(" DESC"); |
michael@0 | 4131 | break; |
michael@0 | 4132 | |
michael@0 | 4133 | default: |
michael@0 | 4134 | MOZ_ASSUME_UNREACHABLE("Unknown direction type!"); |
michael@0 | 4135 | } |
michael@0 | 4136 | |
michael@0 | 4137 | nsCString firstQuery = queryStart + keyRangeClause + directionClause + |
michael@0 | 4138 | openLimit + NS_LITERAL_CSTRING("1"); |
michael@0 | 4139 | |
michael@0 | 4140 | nsCOMPtr<mozIStorageStatement> stmt = |
michael@0 | 4141 | mTransaction->GetCachedStatement(firstQuery); |
michael@0 | 4142 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4143 | |
michael@0 | 4144 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 4145 | |
michael@0 | 4146 | nsresult rv = stmt->BindInt64ByName(id, mObjectStore->Id()); |
michael@0 | 4147 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4148 | |
michael@0 | 4149 | if (mKeyRange) { |
michael@0 | 4150 | rv = mKeyRange->BindToStatement(stmt); |
michael@0 | 4151 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4152 | } |
michael@0 | 4153 | |
michael@0 | 4154 | bool hasResult; |
michael@0 | 4155 | rv = stmt->ExecuteStep(&hasResult); |
michael@0 | 4156 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4157 | |
michael@0 | 4158 | if (!hasResult) { |
michael@0 | 4159 | mKey.Unset(); |
michael@0 | 4160 | return NS_OK; |
michael@0 | 4161 | } |
michael@0 | 4162 | |
michael@0 | 4163 | rv = mKey.SetFromStatement(stmt, 0); |
michael@0 | 4164 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4165 | |
michael@0 | 4166 | // Now we need to make the query to get the next match. |
michael@0 | 4167 | keyRangeClause.Truncate(); |
michael@0 | 4168 | nsAutoCString continueToKeyRangeClause; |
michael@0 | 4169 | |
michael@0 | 4170 | NS_NAMED_LITERAL_CSTRING(currentKey, "current_key"); |
michael@0 | 4171 | NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key"); |
michael@0 | 4172 | |
michael@0 | 4173 | switch (mDirection) { |
michael@0 | 4174 | case IDBCursor::NEXT: |
michael@0 | 4175 | case IDBCursor::NEXT_UNIQUE: |
michael@0 | 4176 | AppendConditionClause(keyValue, currentKey, false, false, |
michael@0 | 4177 | keyRangeClause); |
michael@0 | 4178 | AppendConditionClause(keyValue, currentKey, false, true, |
michael@0 | 4179 | continueToKeyRangeClause); |
michael@0 | 4180 | if (mKeyRange && !mKeyRange->Upper().IsUnset()) { |
michael@0 | 4181 | AppendConditionClause(keyValue, rangeKey, true, |
michael@0 | 4182 | !mKeyRange->IsUpperOpen(), keyRangeClause); |
michael@0 | 4183 | AppendConditionClause(keyValue, rangeKey, true, |
michael@0 | 4184 | !mKeyRange->IsUpperOpen(), |
michael@0 | 4185 | continueToKeyRangeClause); |
michael@0 | 4186 | mRangeKey = mKeyRange->Upper(); |
michael@0 | 4187 | } |
michael@0 | 4188 | break; |
michael@0 | 4189 | |
michael@0 | 4190 | case IDBCursor::PREV: |
michael@0 | 4191 | case IDBCursor::PREV_UNIQUE: |
michael@0 | 4192 | AppendConditionClause(keyValue, currentKey, true, false, keyRangeClause); |
michael@0 | 4193 | AppendConditionClause(keyValue, currentKey, true, true, |
michael@0 | 4194 | continueToKeyRangeClause); |
michael@0 | 4195 | if (mKeyRange && !mKeyRange->Lower().IsUnset()) { |
michael@0 | 4196 | AppendConditionClause(keyValue, rangeKey, false, |
michael@0 | 4197 | !mKeyRange->IsLowerOpen(), keyRangeClause); |
michael@0 | 4198 | AppendConditionClause(keyValue, rangeKey, false, |
michael@0 | 4199 | !mKeyRange->IsLowerOpen(), |
michael@0 | 4200 | continueToKeyRangeClause); |
michael@0 | 4201 | mRangeKey = mKeyRange->Lower(); |
michael@0 | 4202 | } |
michael@0 | 4203 | break; |
michael@0 | 4204 | |
michael@0 | 4205 | default: |
michael@0 | 4206 | MOZ_ASSUME_UNREACHABLE("Unknown direction type!"); |
michael@0 | 4207 | } |
michael@0 | 4208 | |
michael@0 | 4209 | mContinueQuery = queryStart + keyRangeClause + directionClause + openLimit; |
michael@0 | 4210 | mContinueToQuery = queryStart + continueToKeyRangeClause + directionClause + |
michael@0 | 4211 | openLimit; |
michael@0 | 4212 | |
michael@0 | 4213 | return NS_OK; |
michael@0 | 4214 | } |
michael@0 | 4215 | |
michael@0 | 4216 | nsresult |
michael@0 | 4217 | OpenKeyCursorHelper::EnsureCursor() |
michael@0 | 4218 | { |
michael@0 | 4219 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4220 | |
michael@0 | 4221 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 4222 | "OpenKeyCursorHelper::EnsureCursor " |
michael@0 | 4223 | "[IDBObjectStore.cpp]"); |
michael@0 | 4224 | |
michael@0 | 4225 | if (mCursor || mKey.IsUnset()) { |
michael@0 | 4226 | return NS_OK; |
michael@0 | 4227 | } |
michael@0 | 4228 | |
michael@0 | 4229 | mCursor = IDBCursor::Create(mRequest, mTransaction, mObjectStore, mDirection, |
michael@0 | 4230 | mRangeKey, mContinueQuery, mContinueToQuery, |
michael@0 | 4231 | mKey); |
michael@0 | 4232 | IDB_ENSURE_TRUE(mCursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4233 | |
michael@0 | 4234 | return NS_OK; |
michael@0 | 4235 | } |
michael@0 | 4236 | |
michael@0 | 4237 | nsresult |
michael@0 | 4238 | OpenKeyCursorHelper::GetSuccessResult(JSContext* aCx, |
michael@0 | 4239 | JS::MutableHandle<JS::Value> aVal) |
michael@0 | 4240 | { |
michael@0 | 4241 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4242 | |
michael@0 | 4243 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 4244 | "OpenKeyCursorHelper::GetSuccessResult " |
michael@0 | 4245 | "[IDBObjectStore.cpp]"); |
michael@0 | 4246 | |
michael@0 | 4247 | nsresult rv = EnsureCursor(); |
michael@0 | 4248 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4249 | |
michael@0 | 4250 | if (mCursor) { |
michael@0 | 4251 | rv = WrapNative(aCx, mCursor, aVal); |
michael@0 | 4252 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4253 | } |
michael@0 | 4254 | else { |
michael@0 | 4255 | aVal.setUndefined(); |
michael@0 | 4256 | } |
michael@0 | 4257 | |
michael@0 | 4258 | return NS_OK; |
michael@0 | 4259 | } |
michael@0 | 4260 | |
michael@0 | 4261 | void |
michael@0 | 4262 | OpenKeyCursorHelper::ReleaseMainThreadObjects() |
michael@0 | 4263 | { |
michael@0 | 4264 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4265 | |
michael@0 | 4266 | mKeyRange = nullptr; |
michael@0 | 4267 | mCursor = nullptr; |
michael@0 | 4268 | |
michael@0 | 4269 | ObjectStoreHelper::ReleaseMainThreadObjects(); |
michael@0 | 4270 | } |
michael@0 | 4271 | |
michael@0 | 4272 | nsresult |
michael@0 | 4273 | OpenKeyCursorHelper::PackArgumentsForParentProcess( |
michael@0 | 4274 | ObjectStoreRequestParams& aParams) |
michael@0 | 4275 | { |
michael@0 | 4276 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4277 | MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess()); |
michael@0 | 4278 | |
michael@0 | 4279 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 4280 | "OpenKeyCursorHelper::" |
michael@0 | 4281 | "PackArgumentsForParentProcess " |
michael@0 | 4282 | "[IDBObjectStore.cpp]"); |
michael@0 | 4283 | |
michael@0 | 4284 | OpenKeyCursorParams params; |
michael@0 | 4285 | |
michael@0 | 4286 | if (mKeyRange) { |
michael@0 | 4287 | KeyRange keyRange; |
michael@0 | 4288 | mKeyRange->ToSerializedKeyRange(keyRange); |
michael@0 | 4289 | params.optionalKeyRange() = keyRange; |
michael@0 | 4290 | } |
michael@0 | 4291 | else { |
michael@0 | 4292 | params.optionalKeyRange() = mozilla::void_t(); |
michael@0 | 4293 | } |
michael@0 | 4294 | |
michael@0 | 4295 | params.direction() = mDirection; |
michael@0 | 4296 | |
michael@0 | 4297 | aParams = params; |
michael@0 | 4298 | return NS_OK; |
michael@0 | 4299 | } |
michael@0 | 4300 | |
michael@0 | 4301 | AsyncConnectionHelper::ChildProcessSendResult |
michael@0 | 4302 | OpenKeyCursorHelper::SendResponseToChildProcess(nsresult aResultCode) |
michael@0 | 4303 | { |
michael@0 | 4304 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4305 | MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess()); |
michael@0 | 4306 | MOZ_ASSERT(!mCursor); |
michael@0 | 4307 | |
michael@0 | 4308 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 4309 | "OpenKeyCursorHelper::SendResponseToChildProcess " |
michael@0 | 4310 | "[IDBObjectStore.cpp]"); |
michael@0 | 4311 | |
michael@0 | 4312 | IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); |
michael@0 | 4313 | MOZ_ASSERT(actor); |
michael@0 | 4314 | |
michael@0 | 4315 | if (NS_SUCCEEDED(aResultCode)) { |
michael@0 | 4316 | nsresult rv = EnsureCursor(); |
michael@0 | 4317 | if (NS_FAILED(rv)) { |
michael@0 | 4318 | NS_WARNING("EnsureCursor failed!"); |
michael@0 | 4319 | aResultCode = rv; |
michael@0 | 4320 | } |
michael@0 | 4321 | } |
michael@0 | 4322 | |
michael@0 | 4323 | ResponseValue response; |
michael@0 | 4324 | if (NS_FAILED(aResultCode)) { |
michael@0 | 4325 | response = aResultCode; |
michael@0 | 4326 | } else { |
michael@0 | 4327 | OpenCursorResponse openCursorResponse; |
michael@0 | 4328 | |
michael@0 | 4329 | if (!mCursor) { |
michael@0 | 4330 | openCursorResponse = mozilla::void_t(); |
michael@0 | 4331 | } |
michael@0 | 4332 | else { |
michael@0 | 4333 | IndexedDBObjectStoreParent* objectStoreActor = |
michael@0 | 4334 | mObjectStore->GetActorParent(); |
michael@0 | 4335 | MOZ_ASSERT(objectStoreActor); |
michael@0 | 4336 | |
michael@0 | 4337 | IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent(); |
michael@0 | 4338 | MOZ_ASSERT(requestActor); |
michael@0 | 4339 | |
michael@0 | 4340 | ObjectStoreCursorConstructorParams params; |
michael@0 | 4341 | params.requestParent() = requestActor; |
michael@0 | 4342 | params.direction() = mDirection; |
michael@0 | 4343 | params.key() = mKey; |
michael@0 | 4344 | params.optionalCloneInfo() = mozilla::void_t(); |
michael@0 | 4345 | |
michael@0 | 4346 | if (!objectStoreActor->OpenCursor(mCursor, params, openCursorResponse)) { |
michael@0 | 4347 | return Error; |
michael@0 | 4348 | } |
michael@0 | 4349 | } |
michael@0 | 4350 | |
michael@0 | 4351 | response = openCursorResponse; |
michael@0 | 4352 | } |
michael@0 | 4353 | |
michael@0 | 4354 | if (!actor->SendResponse(response)) { |
michael@0 | 4355 | return Error; |
michael@0 | 4356 | } |
michael@0 | 4357 | |
michael@0 | 4358 | return Success_Sent; |
michael@0 | 4359 | } |
michael@0 | 4360 | |
michael@0 | 4361 | nsresult |
michael@0 | 4362 | OpenKeyCursorHelper::UnpackResponseFromParentProcess( |
michael@0 | 4363 | const ResponseValue& aResponseValue) |
michael@0 | 4364 | { |
michael@0 | 4365 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4366 | MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess()); |
michael@0 | 4367 | MOZ_ASSERT(aResponseValue.type() == ResponseValue::TOpenCursorResponse); |
michael@0 | 4368 | MOZ_ASSERT(aResponseValue.get_OpenCursorResponse().type() == |
michael@0 | 4369 | OpenCursorResponse::Tvoid_t || |
michael@0 | 4370 | aResponseValue.get_OpenCursorResponse().type() == |
michael@0 | 4371 | OpenCursorResponse::TPIndexedDBCursorChild); |
michael@0 | 4372 | MOZ_ASSERT(!mCursor); |
michael@0 | 4373 | |
michael@0 | 4374 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 4375 | "OpenKeyCursorHelper::" |
michael@0 | 4376 | "UnpackResponseFromParentProcess " |
michael@0 | 4377 | "[IDBObjectStore.cpp]"); |
michael@0 | 4378 | |
michael@0 | 4379 | const OpenCursorResponse& response = |
michael@0 | 4380 | aResponseValue.get_OpenCursorResponse(); |
michael@0 | 4381 | |
michael@0 | 4382 | switch (response.type()) { |
michael@0 | 4383 | case OpenCursorResponse::Tvoid_t: |
michael@0 | 4384 | break; |
michael@0 | 4385 | |
michael@0 | 4386 | case OpenCursorResponse::TPIndexedDBCursorChild: { |
michael@0 | 4387 | IndexedDBCursorChild* actor = |
michael@0 | 4388 | static_cast<IndexedDBCursorChild*>( |
michael@0 | 4389 | response.get_PIndexedDBCursorChild()); |
michael@0 | 4390 | |
michael@0 | 4391 | mCursor = actor->ForgetStrongCursor(); |
michael@0 | 4392 | NS_ASSERTION(mCursor, "This should never be null!"); |
michael@0 | 4393 | |
michael@0 | 4394 | } break; |
michael@0 | 4395 | |
michael@0 | 4396 | default: |
michael@0 | 4397 | MOZ_CRASH("Unknown response union type!"); |
michael@0 | 4398 | } |
michael@0 | 4399 | |
michael@0 | 4400 | return NS_OK; |
michael@0 | 4401 | } |
michael@0 | 4402 | |
michael@0 | 4403 | nsresult |
michael@0 | 4404 | CreateIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 4405 | { |
michael@0 | 4406 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 4407 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 4408 | |
michael@0 | 4409 | PROFILER_LABEL("IndexedDB", "CreateIndexHelper::DoDatabaseWork"); |
michael@0 | 4410 | |
michael@0 | 4411 | if (IndexedDatabaseManager::InLowDiskSpaceMode()) { |
michael@0 | 4412 | NS_WARNING("Refusing to create index because disk space is low!"); |
michael@0 | 4413 | return NS_ERROR_DOM_INDEXEDDB_QUOTA_ERR; |
michael@0 | 4414 | } |
michael@0 | 4415 | |
michael@0 | 4416 | // Insert the data into the database. |
michael@0 | 4417 | nsCOMPtr<mozIStorageStatement> stmt = |
michael@0 | 4418 | mTransaction->GetCachedStatement( |
michael@0 | 4419 | "INSERT INTO object_store_index (id, name, key_path, unique_index, " |
michael@0 | 4420 | "multientry, object_store_id) " |
michael@0 | 4421 | "VALUES (:id, :name, :key_path, :unique, :multientry, :osid)" |
michael@0 | 4422 | ); |
michael@0 | 4423 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4424 | |
michael@0 | 4425 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 4426 | |
michael@0 | 4427 | nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), |
michael@0 | 4428 | mIndex->Id()); |
michael@0 | 4429 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4430 | |
michael@0 | 4431 | rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mIndex->Name()); |
michael@0 | 4432 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4433 | |
michael@0 | 4434 | nsAutoString keyPathSerialization; |
michael@0 | 4435 | mIndex->GetKeyPath().SerializeToString(keyPathSerialization); |
michael@0 | 4436 | rv = stmt->BindStringByName(NS_LITERAL_CSTRING("key_path"), |
michael@0 | 4437 | keyPathSerialization); |
michael@0 | 4438 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4439 | |
michael@0 | 4440 | rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("unique"), |
michael@0 | 4441 | mIndex->IsUnique() ? 1 : 0); |
michael@0 | 4442 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4443 | |
michael@0 | 4444 | rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("multientry"), |
michael@0 | 4445 | mIndex->IsMultiEntry() ? 1 : 0); |
michael@0 | 4446 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4447 | |
michael@0 | 4448 | rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), |
michael@0 | 4449 | mIndex->ObjectStore()->Id()); |
michael@0 | 4450 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4451 | |
michael@0 | 4452 | if (NS_FAILED(stmt->Execute())) { |
michael@0 | 4453 | return NS_ERROR_DOM_INDEXEDDB_CONSTRAINT_ERR; |
michael@0 | 4454 | } |
michael@0 | 4455 | |
michael@0 | 4456 | #ifdef DEBUG |
michael@0 | 4457 | { |
michael@0 | 4458 | int64_t id; |
michael@0 | 4459 | aConnection->GetLastInsertRowID(&id); |
michael@0 | 4460 | NS_ASSERTION(mIndex->Id() == id, "Bad index id!"); |
michael@0 | 4461 | } |
michael@0 | 4462 | #endif |
michael@0 | 4463 | |
michael@0 | 4464 | // Now we need to populate the index with data from the object store. |
michael@0 | 4465 | rv = InsertDataFromObjectStore(aConnection); |
michael@0 | 4466 | if (NS_FAILED(rv)) { |
michael@0 | 4467 | return rv; |
michael@0 | 4468 | } |
michael@0 | 4469 | |
michael@0 | 4470 | return NS_OK; |
michael@0 | 4471 | } |
michael@0 | 4472 | |
michael@0 | 4473 | void |
michael@0 | 4474 | CreateIndexHelper::ReleaseMainThreadObjects() |
michael@0 | 4475 | { |
michael@0 | 4476 | mIndex = nullptr; |
michael@0 | 4477 | NoRequestObjectStoreHelper::ReleaseMainThreadObjects(); |
michael@0 | 4478 | } |
michael@0 | 4479 | |
michael@0 | 4480 | nsresult |
michael@0 | 4481 | CreateIndexHelper::InsertDataFromObjectStore(mozIStorageConnection* aConnection) |
michael@0 | 4482 | { |
michael@0 | 4483 | nsCOMPtr<mozIStorageStatement> stmt = |
michael@0 | 4484 | mTransaction->GetCachedStatement( |
michael@0 | 4485 | NS_LITERAL_CSTRING("SELECT id, data, file_ids, key_value FROM " |
michael@0 | 4486 | "object_data WHERE object_store_id = :osid")); |
michael@0 | 4487 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4488 | |
michael@0 | 4489 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 4490 | |
michael@0 | 4491 | nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), |
michael@0 | 4492 | mIndex->ObjectStore()->Id()); |
michael@0 | 4493 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4494 | |
michael@0 | 4495 | IDB_ENSURE_TRUE(sTLSIndex != BAD_TLS_INDEX, |
michael@0 | 4496 | NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4497 | |
michael@0 | 4498 | bool hasResult; |
michael@0 | 4499 | rv = stmt->ExecuteStep(&hasResult); |
michael@0 | 4500 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4501 | if (!hasResult) { |
michael@0 | 4502 | // Bail early if we have no data to avoid creating the below runtime |
michael@0 | 4503 | return NS_OK; |
michael@0 | 4504 | } |
michael@0 | 4505 | |
michael@0 | 4506 | ThreadLocalJSRuntime* tlsEntry = |
michael@0 | 4507 | reinterpret_cast<ThreadLocalJSRuntime*>(PR_GetThreadPrivate(sTLSIndex)); |
michael@0 | 4508 | |
michael@0 | 4509 | if (!tlsEntry) { |
michael@0 | 4510 | tlsEntry = ThreadLocalJSRuntime::Create(); |
michael@0 | 4511 | IDB_ENSURE_TRUE(tlsEntry, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4512 | |
michael@0 | 4513 | PR_SetThreadPrivate(sTLSIndex, tlsEntry); |
michael@0 | 4514 | } |
michael@0 | 4515 | |
michael@0 | 4516 | JSContext* cx = tlsEntry->Context(); |
michael@0 | 4517 | JSAutoRequest ar(cx); |
michael@0 | 4518 | JSAutoCompartment ac(cx, tlsEntry->Global()); |
michael@0 | 4519 | |
michael@0 | 4520 | do { |
michael@0 | 4521 | StructuredCloneReadInfo cloneReadInfo; |
michael@0 | 4522 | rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 1, 2, |
michael@0 | 4523 | mDatabase, cloneReadInfo); |
michael@0 | 4524 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4525 | |
michael@0 | 4526 | JSAutoStructuredCloneBuffer& buffer = cloneReadInfo.mCloneBuffer; |
michael@0 | 4527 | |
michael@0 | 4528 | JSStructuredCloneCallbacks callbacks = { |
michael@0 | 4529 | IDBObjectStore::StructuredCloneReadCallback<CreateIndexDeserializationTraits>, |
michael@0 | 4530 | nullptr, |
michael@0 | 4531 | nullptr, |
michael@0 | 4532 | nullptr, |
michael@0 | 4533 | nullptr, |
michael@0 | 4534 | nullptr |
michael@0 | 4535 | }; |
michael@0 | 4536 | |
michael@0 | 4537 | JS::Rooted<JS::Value> clone(cx); |
michael@0 | 4538 | if (!buffer.read(cx, &clone, &callbacks, &cloneReadInfo)) { |
michael@0 | 4539 | NS_WARNING("Failed to deserialize structured clone data!"); |
michael@0 | 4540 | return NS_ERROR_DOM_DATA_CLONE_ERR; |
michael@0 | 4541 | } |
michael@0 | 4542 | |
michael@0 | 4543 | nsTArray<IndexUpdateInfo> updateInfo; |
michael@0 | 4544 | rv = IDBObjectStore::AppendIndexUpdateInfo(mIndex->Id(), |
michael@0 | 4545 | mIndex->GetKeyPath(), |
michael@0 | 4546 | mIndex->IsUnique(), |
michael@0 | 4547 | mIndex->IsMultiEntry(), |
michael@0 | 4548 | tlsEntry->Context(), |
michael@0 | 4549 | clone, updateInfo); |
michael@0 | 4550 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4551 | |
michael@0 | 4552 | int64_t objectDataID = stmt->AsInt64(0); |
michael@0 | 4553 | |
michael@0 | 4554 | Key key; |
michael@0 | 4555 | rv = key.SetFromStatement(stmt, 3); |
michael@0 | 4556 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4557 | |
michael@0 | 4558 | rv = IDBObjectStore::UpdateIndexes(mTransaction, mIndex->Id(), |
michael@0 | 4559 | key, false, objectDataID, updateInfo); |
michael@0 | 4560 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4561 | |
michael@0 | 4562 | } while (NS_SUCCEEDED(rv = stmt->ExecuteStep(&hasResult)) && hasResult); |
michael@0 | 4563 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4564 | |
michael@0 | 4565 | return NS_OK; |
michael@0 | 4566 | } |
michael@0 | 4567 | |
michael@0 | 4568 | void |
michael@0 | 4569 | CreateIndexHelper::DestroyTLSEntry(void* aPtr) |
michael@0 | 4570 | { |
michael@0 | 4571 | delete reinterpret_cast<ThreadLocalJSRuntime *>(aPtr); |
michael@0 | 4572 | } |
michael@0 | 4573 | |
michael@0 | 4574 | nsresult |
michael@0 | 4575 | DeleteIndexHelper::DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 4576 | { |
michael@0 | 4577 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 4578 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 4579 | |
michael@0 | 4580 | PROFILER_LABEL("IndexedDB", "DeleteIndexHelper::DoDatabaseWork"); |
michael@0 | 4581 | |
michael@0 | 4582 | nsCOMPtr<mozIStorageStatement> stmt = |
michael@0 | 4583 | mTransaction->GetCachedStatement( |
michael@0 | 4584 | "DELETE FROM object_store_index " |
michael@0 | 4585 | "WHERE name = :name " |
michael@0 | 4586 | ); |
michael@0 | 4587 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4588 | |
michael@0 | 4589 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 4590 | |
michael@0 | 4591 | nsresult rv = stmt->BindStringByName(NS_LITERAL_CSTRING("name"), mName); |
michael@0 | 4592 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4593 | |
michael@0 | 4594 | if (NS_FAILED(stmt->Execute())) { |
michael@0 | 4595 | return NS_ERROR_DOM_INDEXEDDB_NOT_FOUND_ERR; |
michael@0 | 4596 | } |
michael@0 | 4597 | |
michael@0 | 4598 | return NS_OK; |
michael@0 | 4599 | } |
michael@0 | 4600 | |
michael@0 | 4601 | nsresult |
michael@0 | 4602 | GetAllHelper::DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 4603 | { |
michael@0 | 4604 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 4605 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 4606 | |
michael@0 | 4607 | PROFILER_LABEL("IndexedDB", |
michael@0 | 4608 | "GetAllHelper::DoDatabaseWork [IDBObjectStore.cpp]"); |
michael@0 | 4609 | |
michael@0 | 4610 | NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key"); |
michael@0 | 4611 | NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key"); |
michael@0 | 4612 | |
michael@0 | 4613 | nsAutoCString keyRangeClause; |
michael@0 | 4614 | if (mKeyRange) { |
michael@0 | 4615 | if (!mKeyRange->Lower().IsUnset()) { |
michael@0 | 4616 | keyRangeClause = NS_LITERAL_CSTRING(" AND key_value"); |
michael@0 | 4617 | if (mKeyRange->IsLowerOpen()) { |
michael@0 | 4618 | keyRangeClause.AppendLiteral(" > :"); |
michael@0 | 4619 | } |
michael@0 | 4620 | else { |
michael@0 | 4621 | keyRangeClause.AppendLiteral(" >= :"); |
michael@0 | 4622 | } |
michael@0 | 4623 | keyRangeClause.Append(lowerKeyName); |
michael@0 | 4624 | } |
michael@0 | 4625 | |
michael@0 | 4626 | if (!mKeyRange->Upper().IsUnset()) { |
michael@0 | 4627 | keyRangeClause += NS_LITERAL_CSTRING(" AND key_value"); |
michael@0 | 4628 | if (mKeyRange->IsUpperOpen()) { |
michael@0 | 4629 | keyRangeClause.AppendLiteral(" < :"); |
michael@0 | 4630 | } |
michael@0 | 4631 | else { |
michael@0 | 4632 | keyRangeClause.AppendLiteral(" <= :"); |
michael@0 | 4633 | } |
michael@0 | 4634 | keyRangeClause.Append(upperKeyName); |
michael@0 | 4635 | } |
michael@0 | 4636 | } |
michael@0 | 4637 | |
michael@0 | 4638 | nsAutoCString limitClause; |
michael@0 | 4639 | if (mLimit != UINT32_MAX) { |
michael@0 | 4640 | limitClause.AssignLiteral(" LIMIT "); |
michael@0 | 4641 | limitClause.AppendInt(mLimit); |
michael@0 | 4642 | } |
michael@0 | 4643 | |
michael@0 | 4644 | nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data " |
michael@0 | 4645 | "WHERE object_store_id = :osid") + |
michael@0 | 4646 | keyRangeClause + |
michael@0 | 4647 | NS_LITERAL_CSTRING(" ORDER BY key_value ASC") + |
michael@0 | 4648 | limitClause; |
michael@0 | 4649 | |
michael@0 | 4650 | mCloneReadInfos.SetCapacity(50); |
michael@0 | 4651 | |
michael@0 | 4652 | nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); |
michael@0 | 4653 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4654 | |
michael@0 | 4655 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 4656 | |
michael@0 | 4657 | nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), |
michael@0 | 4658 | mObjectStore->Id()); |
michael@0 | 4659 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4660 | |
michael@0 | 4661 | if (mKeyRange) { |
michael@0 | 4662 | if (!mKeyRange->Lower().IsUnset()) { |
michael@0 | 4663 | rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName); |
michael@0 | 4664 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4665 | } |
michael@0 | 4666 | if (!mKeyRange->Upper().IsUnset()) { |
michael@0 | 4667 | rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName); |
michael@0 | 4668 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4669 | } |
michael@0 | 4670 | } |
michael@0 | 4671 | |
michael@0 | 4672 | bool hasResult; |
michael@0 | 4673 | while (NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) { |
michael@0 | 4674 | if (mCloneReadInfos.Capacity() == mCloneReadInfos.Length()) { |
michael@0 | 4675 | mCloneReadInfos.SetCapacity(mCloneReadInfos.Capacity() * 2); |
michael@0 | 4676 | } |
michael@0 | 4677 | |
michael@0 | 4678 | StructuredCloneReadInfo* readInfo = mCloneReadInfos.AppendElement(); |
michael@0 | 4679 | NS_ASSERTION(readInfo, "Shouldn't fail since SetCapacity succeeded!"); |
michael@0 | 4680 | |
michael@0 | 4681 | rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1, |
michael@0 | 4682 | mDatabase, *readInfo); |
michael@0 | 4683 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4684 | } |
michael@0 | 4685 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4686 | |
michael@0 | 4687 | return NS_OK; |
michael@0 | 4688 | } |
michael@0 | 4689 | |
michael@0 | 4690 | nsresult |
michael@0 | 4691 | GetAllHelper::GetSuccessResult(JSContext* aCx, |
michael@0 | 4692 | JS::MutableHandle<JS::Value> aVal) |
michael@0 | 4693 | { |
michael@0 | 4694 | NS_ASSERTION(mCloneReadInfos.Length() <= mLimit, "Too many results!"); |
michael@0 | 4695 | |
michael@0 | 4696 | nsresult rv = ConvertToArrayAndCleanup(aCx, mCloneReadInfos, aVal); |
michael@0 | 4697 | |
michael@0 | 4698 | NS_ASSERTION(mCloneReadInfos.IsEmpty(), |
michael@0 | 4699 | "Should have cleared in ConvertToArrayAndCleanup"); |
michael@0 | 4700 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4701 | |
michael@0 | 4702 | return NS_OK; |
michael@0 | 4703 | } |
michael@0 | 4704 | |
michael@0 | 4705 | void |
michael@0 | 4706 | GetAllHelper::ReleaseMainThreadObjects() |
michael@0 | 4707 | { |
michael@0 | 4708 | mKeyRange = nullptr; |
michael@0 | 4709 | for (uint32_t index = 0; index < mCloneReadInfos.Length(); index++) { |
michael@0 | 4710 | IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos[index]); |
michael@0 | 4711 | } |
michael@0 | 4712 | ObjectStoreHelper::ReleaseMainThreadObjects(); |
michael@0 | 4713 | } |
michael@0 | 4714 | |
michael@0 | 4715 | nsresult |
michael@0 | 4716 | GetAllHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) |
michael@0 | 4717 | { |
michael@0 | 4718 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 4719 | NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 4720 | |
michael@0 | 4721 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 4722 | "GetAllHelper::PackArgumentsForParentProcess " |
michael@0 | 4723 | "[IDBObjectStore.cpp]"); |
michael@0 | 4724 | |
michael@0 | 4725 | GetAllParams params; |
michael@0 | 4726 | |
michael@0 | 4727 | if (mKeyRange) { |
michael@0 | 4728 | KeyRange keyRange; |
michael@0 | 4729 | mKeyRange->ToSerializedKeyRange(keyRange); |
michael@0 | 4730 | params.optionalKeyRange() = keyRange; |
michael@0 | 4731 | } |
michael@0 | 4732 | else { |
michael@0 | 4733 | params.optionalKeyRange() = mozilla::void_t(); |
michael@0 | 4734 | } |
michael@0 | 4735 | |
michael@0 | 4736 | params.limit() = mLimit; |
michael@0 | 4737 | |
michael@0 | 4738 | aParams = params; |
michael@0 | 4739 | return NS_OK; |
michael@0 | 4740 | } |
michael@0 | 4741 | |
michael@0 | 4742 | AsyncConnectionHelper::ChildProcessSendResult |
michael@0 | 4743 | GetAllHelper::SendResponseToChildProcess(nsresult aResultCode) |
michael@0 | 4744 | { |
michael@0 | 4745 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 4746 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 4747 | |
michael@0 | 4748 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 4749 | "GetAllHelper::SendResponseToChildProcess " |
michael@0 | 4750 | "[IDBObjectStore.cpp]"); |
michael@0 | 4751 | |
michael@0 | 4752 | IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); |
michael@0 | 4753 | NS_ASSERTION(actor, "How did we get this far without an actor?"); |
michael@0 | 4754 | |
michael@0 | 4755 | GetAllResponse getAllResponse; |
michael@0 | 4756 | if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) { |
michael@0 | 4757 | IDBDatabase* database = mObjectStore->Transaction()->Database(); |
michael@0 | 4758 | NS_ASSERTION(database, "This should never be null!"); |
michael@0 | 4759 | |
michael@0 | 4760 | ContentParent* contentParent = database->GetContentParent(); |
michael@0 | 4761 | NS_ASSERTION(contentParent, "This should never be null!"); |
michael@0 | 4762 | |
michael@0 | 4763 | FileManager* fileManager = database->Manager(); |
michael@0 | 4764 | NS_ASSERTION(fileManager, "This should never be null!"); |
michael@0 | 4765 | |
michael@0 | 4766 | uint32_t length = mCloneReadInfos.Length(); |
michael@0 | 4767 | |
michael@0 | 4768 | InfallibleTArray<SerializedStructuredCloneReadInfo>& infos = |
michael@0 | 4769 | getAllResponse.cloneInfos(); |
michael@0 | 4770 | infos.SetCapacity(length); |
michael@0 | 4771 | |
michael@0 | 4772 | InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs(); |
michael@0 | 4773 | blobArrays.SetCapacity(length); |
michael@0 | 4774 | |
michael@0 | 4775 | for (uint32_t index = 0; |
michael@0 | 4776 | NS_SUCCEEDED(aResultCode) && index < length; |
michael@0 | 4777 | index++) { |
michael@0 | 4778 | // Append the structured clone data. |
michael@0 | 4779 | const StructuredCloneReadInfo& clone = mCloneReadInfos[index]; |
michael@0 | 4780 | SerializedStructuredCloneReadInfo* info = infos.AppendElement(); |
michael@0 | 4781 | *info = clone; |
michael@0 | 4782 | |
michael@0 | 4783 | // Now take care of the files. |
michael@0 | 4784 | const nsTArray<StructuredCloneFile>& files = clone.mFiles; |
michael@0 | 4785 | BlobArray* blobArray = blobArrays.AppendElement(); |
michael@0 | 4786 | InfallibleTArray<PBlobParent*>& blobs = blobArray->blobsParent(); |
michael@0 | 4787 | |
michael@0 | 4788 | aResultCode = |
michael@0 | 4789 | IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files, |
michael@0 | 4790 | blobs); |
michael@0 | 4791 | if (NS_FAILED(aResultCode)) { |
michael@0 | 4792 | NS_WARNING("ConvertBlobsToActors failed!"); |
michael@0 | 4793 | break; |
michael@0 | 4794 | } |
michael@0 | 4795 | } |
michael@0 | 4796 | } |
michael@0 | 4797 | |
michael@0 | 4798 | ResponseValue response; |
michael@0 | 4799 | if (NS_FAILED(aResultCode)) { |
michael@0 | 4800 | response = aResultCode; |
michael@0 | 4801 | } |
michael@0 | 4802 | else { |
michael@0 | 4803 | response = getAllResponse; |
michael@0 | 4804 | } |
michael@0 | 4805 | |
michael@0 | 4806 | if (!actor->SendResponse(response)) { |
michael@0 | 4807 | return Error; |
michael@0 | 4808 | } |
michael@0 | 4809 | |
michael@0 | 4810 | return Success_Sent; |
michael@0 | 4811 | } |
michael@0 | 4812 | |
michael@0 | 4813 | nsresult |
michael@0 | 4814 | GetAllHelper::UnpackResponseFromParentProcess( |
michael@0 | 4815 | const ResponseValue& aResponseValue) |
michael@0 | 4816 | { |
michael@0 | 4817 | NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse, |
michael@0 | 4818 | "Bad response type!"); |
michael@0 | 4819 | |
michael@0 | 4820 | const GetAllResponse& getAllResponse = aResponseValue.get_GetAllResponse(); |
michael@0 | 4821 | const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos = |
michael@0 | 4822 | getAllResponse.cloneInfos(); |
michael@0 | 4823 | const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs(); |
michael@0 | 4824 | |
michael@0 | 4825 | mCloneReadInfos.SetCapacity(cloneInfos.Length()); |
michael@0 | 4826 | |
michael@0 | 4827 | for (uint32_t index = 0; index < cloneInfos.Length(); index++) { |
michael@0 | 4828 | const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index]; |
michael@0 | 4829 | const InfallibleTArray<PBlobChild*>& blobs = blobArrays[index].blobsChild(); |
michael@0 | 4830 | |
michael@0 | 4831 | StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement(); |
michael@0 | 4832 | if (!destInfo->SetFromSerialized(srcInfo)) { |
michael@0 | 4833 | IDB_WARNING("Failed to copy clone buffer!"); |
michael@0 | 4834 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 4835 | } |
michael@0 | 4836 | |
michael@0 | 4837 | IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles); |
michael@0 | 4838 | } |
michael@0 | 4839 | |
michael@0 | 4840 | return NS_OK; |
michael@0 | 4841 | } |
michael@0 | 4842 | |
michael@0 | 4843 | nsresult |
michael@0 | 4844 | GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */) |
michael@0 | 4845 | { |
michael@0 | 4846 | MOZ_ASSERT(!NS_IsMainThread()); |
michael@0 | 4847 | MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess()); |
michael@0 | 4848 | |
michael@0 | 4849 | PROFILER_LABEL("IndexedDB", |
michael@0 | 4850 | "GetAllKeysHelper::DoDatabaseWork [IDObjectStore.cpp]"); |
michael@0 | 4851 | |
michael@0 | 4852 | NS_NAMED_LITERAL_CSTRING(keyValue, "key_value"); |
michael@0 | 4853 | |
michael@0 | 4854 | nsAutoCString keyRangeClause; |
michael@0 | 4855 | if (mKeyRange) { |
michael@0 | 4856 | mKeyRange->GetBindingClause(keyValue, keyRangeClause); |
michael@0 | 4857 | } |
michael@0 | 4858 | |
michael@0 | 4859 | nsAutoCString limitClause; |
michael@0 | 4860 | if (mLimit != UINT32_MAX) { |
michael@0 | 4861 | limitClause = NS_LITERAL_CSTRING(" LIMIT "); |
michael@0 | 4862 | limitClause.AppendInt(mLimit); |
michael@0 | 4863 | } |
michael@0 | 4864 | |
michael@0 | 4865 | NS_NAMED_LITERAL_CSTRING(osid, "osid"); |
michael@0 | 4866 | |
michael@0 | 4867 | nsCString query = NS_LITERAL_CSTRING("SELECT ") + keyValue + |
michael@0 | 4868 | NS_LITERAL_CSTRING(" FROM object_data WHERE " |
michael@0 | 4869 | "object_store_id = :") + |
michael@0 | 4870 | osid + keyRangeClause + |
michael@0 | 4871 | NS_LITERAL_CSTRING(" ORDER BY key_value ASC") + |
michael@0 | 4872 | limitClause; |
michael@0 | 4873 | |
michael@0 | 4874 | nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); |
michael@0 | 4875 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4876 | |
michael@0 | 4877 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 4878 | |
michael@0 | 4879 | nsresult rv = stmt->BindInt64ByName(osid, mObjectStore->Id()); |
michael@0 | 4880 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4881 | |
michael@0 | 4882 | if (mKeyRange) { |
michael@0 | 4883 | rv = mKeyRange->BindToStatement(stmt); |
michael@0 | 4884 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4885 | } |
michael@0 | 4886 | |
michael@0 | 4887 | mKeys.SetCapacity(std::min<uint32_t>(50, mLimit)); |
michael@0 | 4888 | |
michael@0 | 4889 | bool hasResult; |
michael@0 | 4890 | while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) { |
michael@0 | 4891 | if (mKeys.Capacity() == mKeys.Length()) { |
michael@0 | 4892 | mKeys.SetCapacity(mKeys.Capacity() * 2); |
michael@0 | 4893 | } |
michael@0 | 4894 | |
michael@0 | 4895 | Key* key = mKeys.AppendElement(); |
michael@0 | 4896 | NS_ASSERTION(key, "This shouldn't fail!"); |
michael@0 | 4897 | |
michael@0 | 4898 | rv = key->SetFromStatement(stmt, 0); |
michael@0 | 4899 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 4900 | } |
michael@0 | 4901 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 4902 | |
michael@0 | 4903 | return NS_OK; |
michael@0 | 4904 | } |
michael@0 | 4905 | |
michael@0 | 4906 | nsresult |
michael@0 | 4907 | GetAllKeysHelper::GetSuccessResult(JSContext* aCx, |
michael@0 | 4908 | JS::MutableHandle<JS::Value> aVal) |
michael@0 | 4909 | { |
michael@0 | 4910 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4911 | MOZ_ASSERT(mKeys.Length() <= mLimit); |
michael@0 | 4912 | |
michael@0 | 4913 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 4914 | "GetAllKeysHelper::GetSuccessResult " |
michael@0 | 4915 | "[IDBObjectStore.cpp]"); |
michael@0 | 4916 | |
michael@0 | 4917 | nsTArray<Key> keys; |
michael@0 | 4918 | mKeys.SwapElements(keys); |
michael@0 | 4919 | |
michael@0 | 4920 | JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0)); |
michael@0 | 4921 | if (!array) { |
michael@0 | 4922 | IDB_WARNING("Failed to make array!"); |
michael@0 | 4923 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 4924 | } |
michael@0 | 4925 | |
michael@0 | 4926 | if (!keys.IsEmpty()) { |
michael@0 | 4927 | if (!JS_SetArrayLength(aCx, array, keys.Length())) { |
michael@0 | 4928 | IDB_WARNING("Failed to set array length!"); |
michael@0 | 4929 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 4930 | } |
michael@0 | 4931 | |
michael@0 | 4932 | for (uint32_t index = 0, count = keys.Length(); index < count; index++) { |
michael@0 | 4933 | const Key& key = keys[index]; |
michael@0 | 4934 | MOZ_ASSERT(!key.IsUnset()); |
michael@0 | 4935 | |
michael@0 | 4936 | JS::Rooted<JS::Value> value(aCx); |
michael@0 | 4937 | nsresult rv = key.ToJSVal(aCx, &value); |
michael@0 | 4938 | if (NS_FAILED(rv)) { |
michael@0 | 4939 | NS_WARNING("Failed to get jsval for key!"); |
michael@0 | 4940 | return rv; |
michael@0 | 4941 | } |
michael@0 | 4942 | |
michael@0 | 4943 | if (!JS_SetElement(aCx, array, index, value)) { |
michael@0 | 4944 | IDB_WARNING("Failed to set array element!"); |
michael@0 | 4945 | return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR; |
michael@0 | 4946 | } |
michael@0 | 4947 | } |
michael@0 | 4948 | } |
michael@0 | 4949 | |
michael@0 | 4950 | aVal.setObject(*array); |
michael@0 | 4951 | return NS_OK; |
michael@0 | 4952 | } |
michael@0 | 4953 | |
michael@0 | 4954 | void |
michael@0 | 4955 | GetAllKeysHelper::ReleaseMainThreadObjects() |
michael@0 | 4956 | { |
michael@0 | 4957 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4958 | |
michael@0 | 4959 | mKeyRange = nullptr; |
michael@0 | 4960 | |
michael@0 | 4961 | ObjectStoreHelper::ReleaseMainThreadObjects(); |
michael@0 | 4962 | } |
michael@0 | 4963 | |
michael@0 | 4964 | nsresult |
michael@0 | 4965 | GetAllKeysHelper::PackArgumentsForParentProcess( |
michael@0 | 4966 | ObjectStoreRequestParams& aParams) |
michael@0 | 4967 | { |
michael@0 | 4968 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4969 | MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess()); |
michael@0 | 4970 | |
michael@0 | 4971 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 4972 | "GetAllKeysHelper::PackArgumentsForParentProcess " |
michael@0 | 4973 | "[IDBObjectStore.cpp]"); |
michael@0 | 4974 | |
michael@0 | 4975 | GetAllKeysParams params; |
michael@0 | 4976 | |
michael@0 | 4977 | if (mKeyRange) { |
michael@0 | 4978 | KeyRange keyRange; |
michael@0 | 4979 | mKeyRange->ToSerializedKeyRange(keyRange); |
michael@0 | 4980 | params.optionalKeyRange() = keyRange; |
michael@0 | 4981 | } else { |
michael@0 | 4982 | params.optionalKeyRange() = mozilla::void_t(); |
michael@0 | 4983 | } |
michael@0 | 4984 | |
michael@0 | 4985 | params.limit() = mLimit; |
michael@0 | 4986 | |
michael@0 | 4987 | aParams = params; |
michael@0 | 4988 | return NS_OK; |
michael@0 | 4989 | } |
michael@0 | 4990 | |
michael@0 | 4991 | AsyncConnectionHelper::ChildProcessSendResult |
michael@0 | 4992 | GetAllKeysHelper::SendResponseToChildProcess(nsresult aResultCode) |
michael@0 | 4993 | { |
michael@0 | 4994 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 4995 | MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess()); |
michael@0 | 4996 | |
michael@0 | 4997 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 4998 | "GetAllKeysHelper::SendResponseToChildProcess " |
michael@0 | 4999 | "[IDBObjectStore.cpp]"); |
michael@0 | 5000 | |
michael@0 | 5001 | IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); |
michael@0 | 5002 | MOZ_ASSERT(actor); |
michael@0 | 5003 | |
michael@0 | 5004 | ResponseValue response; |
michael@0 | 5005 | if (NS_FAILED(aResultCode)) { |
michael@0 | 5006 | response = aResultCode; |
michael@0 | 5007 | } |
michael@0 | 5008 | else { |
michael@0 | 5009 | GetAllKeysResponse getAllKeysResponse; |
michael@0 | 5010 | getAllKeysResponse.keys().AppendElements(mKeys); |
michael@0 | 5011 | response = getAllKeysResponse; |
michael@0 | 5012 | } |
michael@0 | 5013 | |
michael@0 | 5014 | if (!actor->SendResponse(response)) { |
michael@0 | 5015 | return Error; |
michael@0 | 5016 | } |
michael@0 | 5017 | |
michael@0 | 5018 | return Success_Sent; |
michael@0 | 5019 | } |
michael@0 | 5020 | |
michael@0 | 5021 | nsresult |
michael@0 | 5022 | GetAllKeysHelper::UnpackResponseFromParentProcess( |
michael@0 | 5023 | const ResponseValue& aResponseValue) |
michael@0 | 5024 | { |
michael@0 | 5025 | MOZ_ASSERT(NS_IsMainThread()); |
michael@0 | 5026 | MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess()); |
michael@0 | 5027 | MOZ_ASSERT(aResponseValue.type() == ResponseValue::TGetAllKeysResponse); |
michael@0 | 5028 | |
michael@0 | 5029 | mKeys.AppendElements(aResponseValue.get_GetAllKeysResponse().keys()); |
michael@0 | 5030 | return NS_OK; |
michael@0 | 5031 | } |
michael@0 | 5032 | |
michael@0 | 5033 | nsresult |
michael@0 | 5034 | CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection) |
michael@0 | 5035 | { |
michael@0 | 5036 | NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 5037 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 5038 | |
michael@0 | 5039 | PROFILER_LABEL("IndexedDB", |
michael@0 | 5040 | "CountHelper::DoDatabaseWork [IDBObjectStore.cpp]"); |
michael@0 | 5041 | |
michael@0 | 5042 | NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key"); |
michael@0 | 5043 | NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key"); |
michael@0 | 5044 | |
michael@0 | 5045 | nsAutoCString keyRangeClause; |
michael@0 | 5046 | if (mKeyRange) { |
michael@0 | 5047 | if (!mKeyRange->Lower().IsUnset()) { |
michael@0 | 5048 | keyRangeClause = NS_LITERAL_CSTRING(" AND key_value"); |
michael@0 | 5049 | if (mKeyRange->IsLowerOpen()) { |
michael@0 | 5050 | keyRangeClause.AppendLiteral(" > :"); |
michael@0 | 5051 | } |
michael@0 | 5052 | else { |
michael@0 | 5053 | keyRangeClause.AppendLiteral(" >= :"); |
michael@0 | 5054 | } |
michael@0 | 5055 | keyRangeClause.Append(lowerKeyName); |
michael@0 | 5056 | } |
michael@0 | 5057 | |
michael@0 | 5058 | if (!mKeyRange->Upper().IsUnset()) { |
michael@0 | 5059 | keyRangeClause += NS_LITERAL_CSTRING(" AND key_value"); |
michael@0 | 5060 | if (mKeyRange->IsUpperOpen()) { |
michael@0 | 5061 | keyRangeClause.AppendLiteral(" < :"); |
michael@0 | 5062 | } |
michael@0 | 5063 | else { |
michael@0 | 5064 | keyRangeClause.AppendLiteral(" <= :"); |
michael@0 | 5065 | } |
michael@0 | 5066 | keyRangeClause.Append(upperKeyName); |
michael@0 | 5067 | } |
michael@0 | 5068 | } |
michael@0 | 5069 | |
michael@0 | 5070 | nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM object_data " |
michael@0 | 5071 | "WHERE object_store_id = :osid") + |
michael@0 | 5072 | keyRangeClause; |
michael@0 | 5073 | |
michael@0 | 5074 | nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query); |
michael@0 | 5075 | IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 5076 | |
michael@0 | 5077 | mozStorageStatementScoper scoper(stmt); |
michael@0 | 5078 | |
michael@0 | 5079 | nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("osid"), |
michael@0 | 5080 | mObjectStore->Id()); |
michael@0 | 5081 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 5082 | |
michael@0 | 5083 | if (mKeyRange) { |
michael@0 | 5084 | if (!mKeyRange->Lower().IsUnset()) { |
michael@0 | 5085 | rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName); |
michael@0 | 5086 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 5087 | } |
michael@0 | 5088 | if (!mKeyRange->Upper().IsUnset()) { |
michael@0 | 5089 | rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName); |
michael@0 | 5090 | NS_ENSURE_SUCCESS(rv, rv); |
michael@0 | 5091 | } |
michael@0 | 5092 | } |
michael@0 | 5093 | |
michael@0 | 5094 | bool hasResult; |
michael@0 | 5095 | rv = stmt->ExecuteStep(&hasResult); |
michael@0 | 5096 | IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 5097 | IDB_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR); |
michael@0 | 5098 | |
michael@0 | 5099 | mCount = stmt->AsInt64(0); |
michael@0 | 5100 | return NS_OK; |
michael@0 | 5101 | } |
michael@0 | 5102 | |
michael@0 | 5103 | nsresult |
michael@0 | 5104 | CountHelper::GetSuccessResult(JSContext* aCx, |
michael@0 | 5105 | JS::MutableHandle<JS::Value> aVal) |
michael@0 | 5106 | { |
michael@0 | 5107 | aVal.setNumber(static_cast<double>(mCount)); |
michael@0 | 5108 | return NS_OK; |
michael@0 | 5109 | } |
michael@0 | 5110 | |
michael@0 | 5111 | void |
michael@0 | 5112 | CountHelper::ReleaseMainThreadObjects() |
michael@0 | 5113 | { |
michael@0 | 5114 | mKeyRange = nullptr; |
michael@0 | 5115 | ObjectStoreHelper::ReleaseMainThreadObjects(); |
michael@0 | 5116 | } |
michael@0 | 5117 | |
michael@0 | 5118 | nsresult |
michael@0 | 5119 | CountHelper::PackArgumentsForParentProcess(ObjectStoreRequestParams& aParams) |
michael@0 | 5120 | { |
michael@0 | 5121 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 5122 | NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 5123 | |
michael@0 | 5124 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 5125 | "CountHelper::PackArgumentsForParentProcess " |
michael@0 | 5126 | "[IDBObjectStore.cpp]"); |
michael@0 | 5127 | |
michael@0 | 5128 | CountParams params; |
michael@0 | 5129 | |
michael@0 | 5130 | if (mKeyRange) { |
michael@0 | 5131 | KeyRange keyRange; |
michael@0 | 5132 | mKeyRange->ToSerializedKeyRange(keyRange); |
michael@0 | 5133 | params.optionalKeyRange() = keyRange; |
michael@0 | 5134 | } |
michael@0 | 5135 | else { |
michael@0 | 5136 | params.optionalKeyRange() = mozilla::void_t(); |
michael@0 | 5137 | } |
michael@0 | 5138 | |
michael@0 | 5139 | aParams = params; |
michael@0 | 5140 | return NS_OK; |
michael@0 | 5141 | } |
michael@0 | 5142 | |
michael@0 | 5143 | AsyncConnectionHelper::ChildProcessSendResult |
michael@0 | 5144 | CountHelper::SendResponseToChildProcess(nsresult aResultCode) |
michael@0 | 5145 | { |
michael@0 | 5146 | NS_ASSERTION(NS_IsMainThread(), "Wrong thread!"); |
michael@0 | 5147 | NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!"); |
michael@0 | 5148 | |
michael@0 | 5149 | PROFILER_MAIN_THREAD_LABEL("IndexedDB", |
michael@0 | 5150 | "CountHelper::SendResponseToChildProcess " |
michael@0 | 5151 | "[IDBObjectStore.cpp]"); |
michael@0 | 5152 | |
michael@0 | 5153 | IndexedDBRequestParentBase* actor = mRequest->GetActorParent(); |
michael@0 | 5154 | NS_ASSERTION(actor, "How did we get this far without an actor?"); |
michael@0 | 5155 | |
michael@0 | 5156 | ResponseValue response; |
michael@0 | 5157 | if (NS_FAILED(aResultCode)) { |
michael@0 | 5158 | response = aResultCode; |
michael@0 | 5159 | } |
michael@0 | 5160 | else { |
michael@0 | 5161 | CountResponse countResponse = mCount; |
michael@0 | 5162 | response = countResponse; |
michael@0 | 5163 | } |
michael@0 | 5164 | |
michael@0 | 5165 | if (!actor->SendResponse(response)) { |
michael@0 | 5166 | return Error; |
michael@0 | 5167 | } |
michael@0 | 5168 | |
michael@0 | 5169 | return Success_Sent; |
michael@0 | 5170 | } |
michael@0 | 5171 | |
michael@0 | 5172 | nsresult |
michael@0 | 5173 | CountHelper::UnpackResponseFromParentProcess( |
michael@0 | 5174 | const ResponseValue& aResponseValue) |
michael@0 | 5175 | { |
michael@0 | 5176 | NS_ASSERTION(aResponseValue.type() == ResponseValue::TCountResponse, |
michael@0 | 5177 | "Bad response type!"); |
michael@0 | 5178 | |
michael@0 | 5179 | mCount = aResponseValue.get_CountResponse().count(); |
michael@0 | 5180 | return NS_OK; |
michael@0 | 5181 | } |