dom/indexedDB/IDBObjectStore.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

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 }

mercurial