Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "base/basictypes.h"
9 #include "IDBIndex.h"
11 #include <algorithm>
12 #include "mozilla/dom/ContentChild.h"
13 #include "mozilla/dom/ContentParent.h"
14 #include "mozilla/dom/ipc/Blob.h"
15 #include "mozilla/storage.h"
16 #include "nsThreadUtils.h"
17 #include "xpcpublic.h"
19 #include "AsyncConnectionHelper.h"
20 #include "DatabaseInfo.h"
21 #include "IDBCursor.h"
22 #include "IDBEvents.h"
23 #include "IDBKeyRange.h"
24 #include "IDBObjectStore.h"
25 #include "IDBTransaction.h"
26 #include "ProfilerHelpers.h"
27 #include "ReportInternalError.h"
29 #include "ipc/IndexedDBChild.h"
30 #include "ipc/IndexedDBParent.h"
32 #include "IndexedDatabaseInlines.h"
34 USING_INDEXEDDB_NAMESPACE
35 using namespace mozilla::dom;
36 using namespace mozilla::dom::indexedDB::ipc;
37 using mozilla::ErrorResult;
38 using mozilla::Move;
40 namespace {
42 class IndexHelper : public AsyncConnectionHelper
43 {
44 public:
45 IndexHelper(IDBTransaction* aTransaction,
46 IDBRequest* aRequest,
47 IDBIndex* aIndex)
48 : AsyncConnectionHelper(aTransaction, aRequest), mIndex(aIndex),
49 mActor(nullptr)
50 {
51 NS_ASSERTION(aTransaction, "Null transaction!");
52 NS_ASSERTION(aRequest, "Null request!");
53 NS_ASSERTION(aIndex, "Null index!");
54 }
56 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
58 virtual nsresult Dispatch(nsIEventTarget* aDatabaseThread) MOZ_OVERRIDE;
60 virtual nsresult
61 PackArgumentsForParentProcess(IndexRequestParams& aParams) = 0;
63 virtual nsresult
64 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue) = 0;
66 protected:
67 nsRefPtr<IDBIndex> mIndex;
69 private:
70 IndexedDBIndexRequestChild* mActor;
71 };
73 class GetKeyHelper : public IndexHelper
74 {
75 public:
76 GetKeyHelper(IDBTransaction* aTransaction,
77 IDBRequest* aRequest,
78 IDBIndex* aIndex,
79 IDBKeyRange* aKeyRange)
80 : IndexHelper(aTransaction, aRequest, aIndex), mKeyRange(aKeyRange)
81 { }
83 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
84 MOZ_OVERRIDE;
86 virtual nsresult GetSuccessResult(JSContext* aCx,
87 JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
89 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
91 virtual nsresult
92 PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
94 virtual ChildProcessSendResult
95 SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
97 virtual nsresult
98 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
99 MOZ_OVERRIDE;
101 protected:
102 // In-params.
103 nsRefPtr<IDBKeyRange> mKeyRange;
105 // Out-params.
106 Key mKey;
107 };
109 class GetHelper : public GetKeyHelper
110 {
111 public:
112 GetHelper(IDBTransaction* aTransaction,
113 IDBRequest* aRequest,
114 IDBIndex* aIndex,
115 IDBKeyRange* aKeyRange)
116 : GetKeyHelper(aTransaction, aRequest, aIndex, aKeyRange)
117 { }
119 ~GetHelper()
120 {
121 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
122 }
124 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
125 MOZ_OVERRIDE;
127 virtual nsresult GetSuccessResult(JSContext* aCx,
128 JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
130 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
132 virtual nsresult
133 PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
135 virtual ChildProcessSendResult
136 SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
138 virtual nsresult
139 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
140 MOZ_OVERRIDE;
142 protected:
143 StructuredCloneReadInfo mCloneReadInfo;
144 };
146 class GetAllKeysHelper : public GetKeyHelper
147 {
148 public:
149 GetAllKeysHelper(IDBTransaction* aTransaction,
150 IDBRequest* aRequest,
151 IDBIndex* aIndex,
152 IDBKeyRange* aKeyRange,
153 const uint32_t aLimit)
154 : GetKeyHelper(aTransaction, aRequest, aIndex, aKeyRange), mLimit(aLimit)
155 { }
157 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
158 MOZ_OVERRIDE;
160 virtual nsresult GetSuccessResult(JSContext* aCx,
161 JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
163 virtual nsresult
164 PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
166 virtual ChildProcessSendResult
167 SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
169 virtual nsresult
170 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
171 MOZ_OVERRIDE;
173 protected:
174 const uint32_t mLimit;
175 nsTArray<Key> mKeys;
176 };
178 class GetAllHelper : public GetKeyHelper
179 {
180 public:
181 GetAllHelper(IDBTransaction* aTransaction,
182 IDBRequest* aRequest,
183 IDBIndex* aIndex,
184 IDBKeyRange* aKeyRange,
185 const uint32_t aLimit)
186 : GetKeyHelper(aTransaction, aRequest, aIndex, aKeyRange), mLimit(aLimit)
187 { }
189 ~GetAllHelper()
190 {
191 for (uint32_t index = 0; index < mCloneReadInfos.Length(); index++) {
192 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos[index]);
193 }
194 }
196 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
197 MOZ_OVERRIDE;
199 virtual nsresult GetSuccessResult(JSContext* aCx,
200 JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
202 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
204 virtual nsresult
205 PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
207 virtual ChildProcessSendResult
208 SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
210 virtual nsresult
211 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
212 MOZ_OVERRIDE;
214 protected:
215 const uint32_t mLimit;
216 nsTArray<StructuredCloneReadInfo> mCloneReadInfos;
217 };
219 class OpenKeyCursorHelper : public IndexHelper
220 {
221 public:
222 OpenKeyCursorHelper(IDBTransaction* aTransaction,
223 IDBRequest* aRequest,
224 IDBIndex* aIndex,
225 IDBKeyRange* aKeyRange,
226 IDBCursor::Direction aDirection)
227 : IndexHelper(aTransaction, aRequest, aIndex), mKeyRange(aKeyRange),
228 mDirection(aDirection)
229 { }
231 ~OpenKeyCursorHelper()
232 {
233 NS_ASSERTION(true, "bas");
234 }
236 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
237 MOZ_OVERRIDE;
239 virtual nsresult GetSuccessResult(JSContext* aCx,
240 JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
242 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
244 virtual nsresult
245 PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
247 virtual ChildProcessSendResult
248 SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
250 virtual nsresult
251 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
252 MOZ_OVERRIDE;
254 protected:
255 virtual nsresult EnsureCursor();
257 // In-params.
258 nsRefPtr<IDBKeyRange> mKeyRange;
259 const IDBCursor::Direction mDirection;
261 // Out-params.
262 Key mKey;
263 Key mObjectKey;
264 nsCString mContinueQuery;
265 nsCString mContinueToQuery;
266 Key mRangeKey;
268 // Only used in the parent process.
269 nsRefPtr<IDBCursor> mCursor;
270 };
272 class OpenCursorHelper : public OpenKeyCursorHelper
273 {
274 public:
275 OpenCursorHelper(IDBTransaction* aTransaction,
276 IDBRequest* aRequest,
277 IDBIndex* aIndex,
278 IDBKeyRange* aKeyRange,
279 IDBCursor::Direction aDirection)
280 : OpenKeyCursorHelper(aTransaction, aRequest, aIndex, aKeyRange, aDirection)
281 { }
283 ~OpenCursorHelper()
284 {
285 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
286 }
288 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
289 MOZ_OVERRIDE;
291 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
293 virtual nsresult
294 PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
296 virtual ChildProcessSendResult
297 SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
299 private:
300 virtual nsresult EnsureCursor();
302 StructuredCloneReadInfo mCloneReadInfo;
304 // Only used in the parent process.
305 SerializedStructuredCloneReadInfo mSerializedCloneReadInfo;
306 };
308 class CountHelper : public IndexHelper
309 {
310 public:
311 CountHelper(IDBTransaction* aTransaction,
312 IDBRequest* aRequest,
313 IDBIndex* aIndex,
314 IDBKeyRange* aKeyRange)
315 : IndexHelper(aTransaction, aRequest, aIndex), mKeyRange(aKeyRange), mCount(0)
316 { }
318 virtual nsresult DoDatabaseWork(mozIStorageConnection* aConnection)
319 MOZ_OVERRIDE;
321 virtual nsresult GetSuccessResult(JSContext* aCx,
322 JS::MutableHandle<JS::Value> aVal) MOZ_OVERRIDE;
324 virtual void ReleaseMainThreadObjects() MOZ_OVERRIDE;
326 virtual nsresult
327 PackArgumentsForParentProcess(IndexRequestParams& aParams) MOZ_OVERRIDE;
329 virtual ChildProcessSendResult
330 SendResponseToChildProcess(nsresult aResultCode) MOZ_OVERRIDE;
332 virtual nsresult
333 UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
334 MOZ_OVERRIDE;
336 private:
337 nsRefPtr<IDBKeyRange> mKeyRange;
338 uint64_t mCount;
339 };
341 inline
342 already_AddRefed<IDBRequest>
343 GenerateRequest(IDBIndex* aIndex)
344 {
345 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
346 IDBTransaction* transaction = aIndex->ObjectStore()->Transaction();
347 IDBDatabase* database = transaction->Database();
348 return IDBRequest::Create(aIndex, database, transaction);
349 }
351 } // anonymous namespace
353 // static
354 already_AddRefed<IDBIndex>
355 IDBIndex::Create(IDBObjectStore* aObjectStore,
356 const IndexInfo* aIndexInfo,
357 bool aCreating)
358 {
359 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
360 NS_ASSERTION(aObjectStore, "Null pointer!");
361 NS_ASSERTION(aIndexInfo, "Null pointer!");
363 nsRefPtr<IDBIndex> index = new IDBIndex();
365 index->mObjectStore = aObjectStore;
366 index->mId = aIndexInfo->id;
367 index->mName = aIndexInfo->name;
368 index->mKeyPath = aIndexInfo->keyPath;
369 index->mUnique = aIndexInfo->unique;
370 index->mMultiEntry = aIndexInfo->multiEntry;
372 if (!IndexedDatabaseManager::IsMainProcess()) {
373 IndexedDBObjectStoreChild* objectStoreActor = aObjectStore->GetActorChild();
374 NS_ASSERTION(objectStoreActor, "Must have an actor here!");
376 nsAutoPtr<IndexedDBIndexChild> actor(new IndexedDBIndexChild(index));
378 IndexConstructorParams params;
380 if (aCreating) {
381 CreateIndexParams createParams;
382 createParams.info() = *aIndexInfo;
383 params = createParams;
384 }
385 else {
386 GetIndexParams getParams;
387 getParams.name() = aIndexInfo->name;
388 params = getParams;
389 }
391 objectStoreActor->SendPIndexedDBIndexConstructor(actor.forget(), params);
392 }
394 return index.forget();
395 }
397 IDBIndex::IDBIndex()
398 : mId(INT64_MIN),
399 mKeyPath(0),
400 mCachedKeyPath(JSVAL_VOID),
401 mActorChild(nullptr),
402 mActorParent(nullptr),
403 mUnique(false),
404 mMultiEntry(false),
405 mRooted(false)
406 {
407 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
409 SetIsDOMBinding();
410 }
412 IDBIndex::~IDBIndex()
413 {
414 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
415 NS_ASSERTION(!mActorParent, "Actor parent owns us, how can we be dying?!");
417 if (mRooted) {
418 mCachedKeyPath = JSVAL_VOID;
419 mozilla::DropJSObjects(this);
420 }
422 if (mActorChild) {
423 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
424 mActorChild->Send__delete__(mActorChild);
425 NS_ASSERTION(!mActorChild, "Should have cleared in Send__delete__!");
426 }
427 }
429 already_AddRefed<IDBRequest>
430 IDBIndex::GetInternal(IDBKeyRange* aKeyRange, ErrorResult& aRv)
431 {
432 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
434 IDBTransaction* transaction = mObjectStore->Transaction();
435 if (!transaction->IsOpen()) {
436 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
437 return nullptr;
438 }
440 nsRefPtr<IDBRequest> request = GenerateRequest(this);
441 if (!request) {
442 IDB_WARNING("Failed to generate request!");
443 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
444 return nullptr;
445 }
447 nsRefPtr<GetHelper> helper =
448 new GetHelper(transaction, request, this, aKeyRange);
450 nsresult rv = helper->DispatchToTransactionPool();
451 if (NS_FAILED(rv)) {
452 IDB_WARNING("Failed to dispatch!");
453 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
454 return nullptr;
455 }
457 IDB_PROFILER_MARK("IndexedDB Request %llu: "
458 "database(%s).transaction(%s).objectStore(%s).index(%s)."
459 "get(%s)",
460 "IDBRequest[%llu] MT IDBIndex.get()",
461 request->GetSerialNumber(),
462 IDB_PROFILER_STRING(ObjectStore()->Transaction()->
463 Database()),
464 IDB_PROFILER_STRING(ObjectStore()->Transaction()),
465 IDB_PROFILER_STRING(ObjectStore()),
466 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
468 return request.forget();
469 }
471 already_AddRefed<IDBRequest>
472 IDBIndex::GetKeyInternal(IDBKeyRange* aKeyRange, ErrorResult& aRv)
473 {
474 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
476 IDBTransaction* transaction = mObjectStore->Transaction();
477 if (!transaction->IsOpen()) {
478 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
479 return nullptr;
480 }
482 nsRefPtr<IDBRequest> request = GenerateRequest(this);
483 if (!request) {
484 IDB_WARNING("Failed to generate request!");
485 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
486 return nullptr;
487 }
489 nsRefPtr<GetKeyHelper> helper =
490 new GetKeyHelper(transaction, request, this, aKeyRange);
492 nsresult rv = helper->DispatchToTransactionPool();
493 if (NS_FAILED(rv)) {
494 IDB_WARNING("Failed to dispatch!");
495 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
496 return nullptr;
497 }
499 IDB_PROFILER_MARK("IndexedDB Request %llu: "
500 "database(%s).transaction(%s).objectStore(%s).index(%s)."
501 "getKey(%s)",
502 "IDBRequest[%llu] MT IDBIndex.getKey()",
503 request->GetSerialNumber(),
504 IDB_PROFILER_STRING(ObjectStore()->Transaction()->
505 Database()),
506 IDB_PROFILER_STRING(ObjectStore()->Transaction()),
507 IDB_PROFILER_STRING(ObjectStore()),
508 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
510 return request.forget();
511 }
513 already_AddRefed<IDBRequest>
514 IDBIndex::GetAllInternal(IDBKeyRange* aKeyRange, uint32_t aLimit,
515 ErrorResult& aRv)
516 {
517 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
519 IDBTransaction* transaction = mObjectStore->Transaction();
520 if (!transaction->IsOpen()) {
521 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
522 return nullptr;
523 }
525 nsRefPtr<IDBRequest> request = GenerateRequest(this);
526 if (!request) {
527 IDB_WARNING("Failed to generate request!");
528 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
529 return nullptr;
530 }
532 nsRefPtr<GetAllHelper> helper =
533 new GetAllHelper(transaction, request, this, aKeyRange, aLimit);
535 nsresult rv = helper->DispatchToTransactionPool();
536 if (NS_FAILED(rv)) {
537 IDB_WARNING("Failed to dispatch!");
538 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
539 return nullptr;
540 }
542 IDB_PROFILER_MARK("IndexedDB Request %llu: "
543 "database(%s).transaction(%s).objectStore(%s).index(%s)."
544 "getAll(%s, %lu)",
545 "IDBRequest[%llu] MT IDBIndex.getAll()",
546 request->GetSerialNumber(),
547 IDB_PROFILER_STRING(ObjectStore()->Transaction()->
548 Database()),
549 IDB_PROFILER_STRING(ObjectStore()->Transaction()),
550 IDB_PROFILER_STRING(ObjectStore()),
551 IDB_PROFILER_STRING(this),
552 IDB_PROFILER_STRING(aKeyRange), aLimit);
554 return request.forget();
555 }
557 already_AddRefed<IDBRequest>
558 IDBIndex::GetAllKeysInternal(IDBKeyRange* aKeyRange, uint32_t aLimit,
559 ErrorResult& aRv)
560 {
561 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
563 IDBTransaction* transaction = mObjectStore->Transaction();
564 if (!transaction->IsOpen()) {
565 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
566 return nullptr;
567 }
569 nsRefPtr<IDBRequest> request = GenerateRequest(this);
570 if (!request) {
571 IDB_WARNING("Failed to generate request!");
572 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
573 return nullptr;
574 }
576 nsRefPtr<GetAllKeysHelper> helper =
577 new GetAllKeysHelper(transaction, request, this, aKeyRange, aLimit);
579 nsresult rv = helper->DispatchToTransactionPool();
580 if (NS_FAILED(rv)) {
581 IDB_WARNING("Failed to dispatch!");
582 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
583 return nullptr;
584 }
586 IDB_PROFILER_MARK("IndexedDB Request %llu: "
587 "database(%s).transaction(%s).objectStore(%s).index(%s)."
588 "getAllKeys(%s, %lu)",
589 "IDBRequest[%llu] MT IDBIndex.getAllKeys()",
590 request->GetSerialNumber(),
591 IDB_PROFILER_STRING(ObjectStore()->Transaction()->
592 Database()),
593 IDB_PROFILER_STRING(ObjectStore()->Transaction()),
594 IDB_PROFILER_STRING(ObjectStore()),
595 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
596 aLimit);
598 return request.forget();
599 }
601 already_AddRefed<IDBRequest>
602 IDBIndex::CountInternal(IDBKeyRange* aKeyRange, ErrorResult& aRv)
603 {
604 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
606 IDBTransaction* transaction = mObjectStore->Transaction();
607 if (!transaction->IsOpen()) {
608 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
609 return nullptr;
610 }
612 nsRefPtr<IDBRequest> request = GenerateRequest(this);
613 if (!request) {
614 IDB_WARNING("Failed to generate request!");
615 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
616 return nullptr;
617 }
619 nsRefPtr<CountHelper> helper =
620 new CountHelper(transaction, request, this, aKeyRange);
622 nsresult rv = helper->DispatchToTransactionPool();
623 if (NS_FAILED(rv)) {
624 IDB_WARNING("Failed to dispatch!");
625 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
626 return nullptr;
627 }
629 IDB_PROFILER_MARK("IndexedDB Request %llu: "
630 "database(%s).transaction(%s).objectStore(%s).index(%s)."
631 "count(%s)",
632 "IDBRequest[%llu] MT IDBIndex.count()",
633 request->GetSerialNumber(),
634 IDB_PROFILER_STRING(ObjectStore()->Transaction()->
635 Database()),
636 IDB_PROFILER_STRING(ObjectStore()->Transaction()),
637 IDB_PROFILER_STRING(ObjectStore()),
638 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange));
640 return request.forget();
641 }
643 already_AddRefed<IDBRequest>
644 IDBIndex::OpenKeyCursorInternal(IDBKeyRange* aKeyRange, size_t aDirection,
645 ErrorResult& aRv)
646 {
647 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
649 IDBTransaction* transaction = mObjectStore->Transaction();
650 if (!transaction->IsOpen()) {
651 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
652 return nullptr;
653 }
655 IDBCursor::Direction direction =
656 static_cast<IDBCursor::Direction>(aDirection);
658 nsRefPtr<IDBRequest> request = GenerateRequest(this);
659 if (!request) {
660 IDB_WARNING("Failed to generate request!");
661 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
662 return nullptr;
663 }
665 nsRefPtr<OpenKeyCursorHelper> helper =
666 new OpenKeyCursorHelper(transaction, request, this, aKeyRange, direction);
668 nsresult rv = helper->DispatchToTransactionPool();
669 if (NS_FAILED(rv)) {
670 IDB_WARNING("Failed to dispatch!");
671 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
672 return nullptr;
673 }
675 IDB_PROFILER_MARK("IndexedDB Request %llu: "
676 "database(%s).transaction(%s).objectStore(%s).index(%s)."
677 "openKeyCursor(%s)",
678 "IDBRequest[%llu] MT IDBIndex.openKeyCursor()",
679 request->GetSerialNumber(),
680 IDB_PROFILER_STRING(ObjectStore()->Transaction()->
681 Database()),
682 IDB_PROFILER_STRING(ObjectStore()->Transaction()),
683 IDB_PROFILER_STRING(ObjectStore()),
684 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
685 IDB_PROFILER_STRING(direction));
687 return request.forget();
688 }
690 nsresult
691 IDBIndex::OpenCursorInternal(IDBKeyRange* aKeyRange,
692 size_t aDirection,
693 IDBRequest** _retval)
694 {
695 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
697 IDBTransaction* transaction = mObjectStore->Transaction();
698 if (!transaction->IsOpen()) {
699 return NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR;
700 }
702 IDBCursor::Direction direction =
703 static_cast<IDBCursor::Direction>(aDirection);
705 nsRefPtr<IDBRequest> request = GenerateRequest(this);
706 IDB_ENSURE_TRUE(request, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
708 nsRefPtr<OpenCursorHelper> helper =
709 new OpenCursorHelper(transaction, request, this, aKeyRange, direction);
711 nsresult rv = helper->DispatchToTransactionPool();
712 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
714 IDB_PROFILER_MARK("IndexedDB Request %llu: "
715 "database(%s).transaction(%s).objectStore(%s).index(%s)."
716 "openCursor(%s)",
717 "IDBRequest[%llu] MT IDBIndex.openCursor()",
718 request->GetSerialNumber(),
719 IDB_PROFILER_STRING(ObjectStore()->Transaction()->
720 Database()),
721 IDB_PROFILER_STRING(ObjectStore()->Transaction()),
722 IDB_PROFILER_STRING(ObjectStore()),
723 IDB_PROFILER_STRING(this), IDB_PROFILER_STRING(aKeyRange),
724 IDB_PROFILER_STRING(direction));
726 request.forget(_retval);
727 return NS_OK;
728 }
730 nsresult
731 IDBIndex::OpenCursorFromChildProcess(IDBRequest* aRequest,
732 size_t aDirection,
733 const Key& aKey,
734 const Key& aObjectKey,
735 IDBCursor** _retval)
736 {
737 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
739 IDBCursor::Direction direction =
740 static_cast<IDBCursor::Direction>(aDirection);
742 nsRefPtr<IDBCursor> cursor =
743 IDBCursor::Create(aRequest, mObjectStore->Transaction(), this, direction,
744 Key(), EmptyCString(), EmptyCString(), aKey, aObjectKey);
745 IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
747 cursor.forget(_retval);
748 return NS_OK;
749 }
751 nsresult
752 IDBIndex::OpenCursorFromChildProcess(
753 IDBRequest* aRequest,
754 size_t aDirection,
755 const Key& aKey,
756 const Key& aObjectKey,
757 const SerializedStructuredCloneReadInfo& aCloneInfo,
758 nsTArray<StructuredCloneFile>& aBlobs,
759 IDBCursor** _retval)
760 {
761 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
762 NS_ASSERTION((!aCloneInfo.dataLength && !aCloneInfo.data) ||
763 (aCloneInfo.dataLength && aCloneInfo.data),
764 "Inconsistent clone info!");
766 IDBCursor::Direction direction =
767 static_cast<IDBCursor::Direction>(aDirection);
769 StructuredCloneReadInfo cloneInfo;
771 if (!cloneInfo.SetFromSerialized(aCloneInfo)) {
772 IDB_WARNING("Failed to copy clone buffer!");
773 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
774 }
776 cloneInfo.mFiles.SwapElements(aBlobs);
778 nsRefPtr<IDBCursor> cursor =
779 IDBCursor::Create(aRequest, mObjectStore->Transaction(), this, direction,
780 Key(), EmptyCString(), EmptyCString(), aKey, aObjectKey,
781 Move(cloneInfo));
782 IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
784 NS_ASSERTION(!cloneInfo.mCloneBuffer.data(), "Should have swapped!");
786 cursor.forget(_retval);
787 return NS_OK;
788 }
790 NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex)
792 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBIndex)
793 NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER
794 NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mCachedKeyPath)
795 NS_IMPL_CYCLE_COLLECTION_TRACE_END
797 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex)
798 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
799 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore)
800 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
802 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBIndex)
803 NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER
805 // Don't unlink mObjectStore!
807 tmp->mCachedKeyPath = JSVAL_VOID;
809 if (tmp->mRooted) {
810 mozilla::DropJSObjects(tmp);
811 tmp->mRooted = false;
812 }
813 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
815 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBIndex)
816 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
817 NS_INTERFACE_MAP_ENTRY(nsISupports)
818 NS_INTERFACE_MAP_END
820 NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBIndex)
821 NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBIndex)
823 JSObject*
824 IDBIndex::WrapObject(JSContext* aCx)
825 {
826 return IDBIndexBinding::Wrap(aCx, this);
827 }
829 void
830 IDBIndex::GetKeyPath(JSContext* aCx, JS::MutableHandle<JS::Value> aResult,
831 ErrorResult& aRv)
832 {
833 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
835 if (!JSVAL_IS_VOID(mCachedKeyPath)) {
836 JS::ExposeValueToActiveJS(mCachedKeyPath);
837 aResult.set(mCachedKeyPath);
838 return;
839 }
841 aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
842 if (NS_WARN_IF(aRv.Failed())) {
843 return;
844 }
846 if (JSVAL_IS_GCTHING(mCachedKeyPath)) {
847 mozilla::HoldJSObjects(this);
848 mRooted = true;
849 }
851 JS::ExposeValueToActiveJS(mCachedKeyPath);
852 aResult.set(mCachedKeyPath);
853 }
855 already_AddRefed<IDBRequest>
856 IDBIndex::Get(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv)
857 {
858 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
860 IDBTransaction* transaction = mObjectStore->Transaction();
861 if (!transaction->IsOpen()) {
862 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
863 return nullptr;
864 }
866 nsRefPtr<IDBKeyRange> keyRange;
867 aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
868 ENSURE_SUCCESS(aRv, nullptr);
870 if (!keyRange) {
871 // Must specify a key or keyRange for getKey().
872 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
873 return nullptr;
874 }
876 return GetInternal(keyRange, aRv);
877 }
879 already_AddRefed<IDBRequest>
880 IDBIndex::GetKey(JSContext* aCx, JS::Handle<JS::Value> aKey, ErrorResult& aRv)
881 {
882 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
884 IDBTransaction* transaction = mObjectStore->Transaction();
885 if (!transaction->IsOpen()) {
886 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
887 return nullptr;
888 }
890 nsRefPtr<IDBKeyRange> keyRange;
891 aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
892 ENSURE_SUCCESS(aRv, nullptr);
894 if (!keyRange) {
895 // Must specify a key or keyRange for get().
896 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
897 return nullptr;
898 }
900 return GetKeyInternal(keyRange, aRv);
901 }
903 already_AddRefed<IDBRequest>
904 IDBIndex::GetAll(JSContext* aCx, JS::Handle<JS::Value> aKey,
905 const Optional<uint32_t>& aLimit, ErrorResult& aRv)
906 {
907 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
909 IDBTransaction* transaction = mObjectStore->Transaction();
910 if (!transaction->IsOpen()) {
911 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
912 return nullptr;
913 }
915 nsRefPtr<IDBKeyRange> keyRange;
916 aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
917 ENSURE_SUCCESS(aRv, nullptr);
919 uint32_t limit = UINT32_MAX;
920 if (aLimit.WasPassed() && aLimit.Value() > 0) {
921 limit = aLimit.Value();
922 }
924 return GetAllInternal(keyRange, limit, aRv);
925 }
927 already_AddRefed<IDBRequest>
928 IDBIndex::GetAllKeys(JSContext* aCx,
929 JS::Handle<JS::Value> aKey,
930 const Optional<uint32_t>& aLimit, ErrorResult& aRv)
931 {
932 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
934 IDBTransaction* transaction = mObjectStore->Transaction();
935 if (!transaction->IsOpen()) {
936 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
937 return nullptr;
938 }
940 nsRefPtr<IDBKeyRange> keyRange;
941 aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
942 ENSURE_SUCCESS(aRv, nullptr);
944 uint32_t limit = UINT32_MAX;
945 if (aLimit.WasPassed() && aLimit.Value() > 0) {
946 limit = aLimit.Value();
947 }
949 return GetAllKeysInternal(keyRange, limit, aRv);
950 }
952 already_AddRefed<IDBRequest>
953 IDBIndex::OpenCursor(JSContext* aCx,
954 JS::Handle<JS::Value> aRange,
955 IDBCursorDirection aDirection, ErrorResult& aRv)
956 {
957 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
959 IDBTransaction* transaction = mObjectStore->Transaction();
960 if (!transaction->IsOpen()) {
961 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
962 return nullptr;
963 }
965 nsRefPtr<IDBKeyRange> keyRange;
966 aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
967 ENSURE_SUCCESS(aRv, nullptr);
969 IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
971 nsRefPtr<IDBRequest> request = GenerateRequest(this);
972 if (!request) {
973 IDB_WARNING("Failed to generate request!");
974 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
975 return nullptr;
976 }
978 nsRefPtr<OpenCursorHelper> helper =
979 new OpenCursorHelper(transaction, request, this, keyRange, direction);
981 nsresult rv = helper->DispatchToTransactionPool();
982 if (NS_FAILED(rv)) {
983 IDB_WARNING("Failed to dispatch!");
984 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
985 return nullptr;
986 }
988 return request.forget();
989 }
991 already_AddRefed<IDBRequest>
992 IDBIndex::OpenKeyCursor(JSContext* aCx,
993 JS::Handle<JS::Value> aRange,
994 IDBCursorDirection aDirection, ErrorResult& aRv)
995 {
996 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
998 IDBTransaction* transaction = mObjectStore->Transaction();
999 if (!transaction->IsOpen()) {
1000 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
1001 return nullptr;
1002 }
1004 nsRefPtr<IDBKeyRange> keyRange;
1005 aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange));
1006 ENSURE_SUCCESS(aRv, nullptr);
1008 IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection);
1010 return OpenKeyCursorInternal(keyRange, direction, aRv);
1011 }
1013 already_AddRefed<IDBRequest>
1014 IDBIndex::Count(JSContext* aCx, JS::Handle<JS::Value> aKey,
1015 ErrorResult& aRv)
1016 {
1017 IDBTransaction* transaction = mObjectStore->Transaction();
1018 if (!transaction->IsOpen()) {
1019 aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR);
1020 return nullptr;
1021 }
1023 nsRefPtr<IDBKeyRange> keyRange;
1024 aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange));
1025 ENSURE_SUCCESS(aRv, nullptr);
1027 return CountInternal(keyRange, aRv);
1028 }
1030 void
1031 IndexHelper::ReleaseMainThreadObjects()
1032 {
1033 mIndex = nullptr;
1034 AsyncConnectionHelper::ReleaseMainThreadObjects();
1035 }
1037 nsresult
1038 IndexHelper::Dispatch(nsIEventTarget* aDatabaseThread)
1039 {
1040 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1042 PROFILER_MAIN_THREAD_LABEL("IndexedDB", "IndexHelper::Dispatch");
1044 if (IndexedDatabaseManager::IsMainProcess()) {
1045 return AsyncConnectionHelper::Dispatch(aDatabaseThread);
1046 }
1048 // If we've been invalidated then there's no point sending anything to the
1049 // parent process.
1050 if (mIndex->ObjectStore()->Transaction()->Database()->IsInvalidated()) {
1051 IDB_REPORT_INTERNAL_ERR();
1052 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1053 }
1055 IndexedDBIndexChild* indexActor = mIndex->GetActorChild();
1056 NS_ASSERTION(indexActor, "Must have an actor here!");
1058 IndexRequestParams params;
1059 nsresult rv = PackArgumentsForParentProcess(params);
1060 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1062 NoDispatchEventTarget target;
1063 rv = AsyncConnectionHelper::Dispatch(&target);
1064 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1066 mActor = new IndexedDBIndexRequestChild(this, mIndex, params.type());
1067 indexActor->SendPIndexedDBRequestConstructor(mActor, params);
1069 return NS_OK;
1070 }
1072 nsresult
1073 GetKeyHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
1074 {
1075 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
1076 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1077 NS_ASSERTION(mKeyRange, "Must have a key range here!");
1079 PROFILER_LABEL("IndexedDB", "GetKeyHelper::DoDatabaseWork");
1081 nsCString indexTable;
1082 if (mIndex->IsUnique()) {
1083 indexTable.AssignLiteral("unique_index_data");
1084 }
1085 else {
1086 indexTable.AssignLiteral("index_data");
1087 }
1089 nsCString keyRangeClause;
1090 mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause);
1092 NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
1094 nsCString query = NS_LITERAL_CSTRING("SELECT object_data_key FROM ") +
1095 indexTable +
1096 NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
1097 keyRangeClause +
1098 NS_LITERAL_CSTRING(" LIMIT 1");
1100 nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
1101 IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1103 mozStorageStatementScoper scoper(stmt);
1105 nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
1106 mIndex->Id());
1107 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1109 rv = mKeyRange->BindToStatement(stmt);
1110 NS_ENSURE_SUCCESS(rv, rv);
1112 bool hasResult;
1113 rv = stmt->ExecuteStep(&hasResult);
1114 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1116 if (hasResult) {
1117 rv = mKey.SetFromStatement(stmt, 0);
1118 NS_ENSURE_SUCCESS(rv, rv);
1119 }
1121 return NS_OK;
1122 }
1124 nsresult
1125 GetKeyHelper::GetSuccessResult(JSContext* aCx,
1126 JS::MutableHandle<JS::Value> aVal)
1127 {
1128 return mKey.ToJSVal(aCx, aVal);
1129 }
1131 void
1132 GetKeyHelper::ReleaseMainThreadObjects()
1133 {
1134 mKeyRange = nullptr;
1135 IndexHelper::ReleaseMainThreadObjects();
1136 }
1138 nsresult
1139 GetKeyHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
1140 {
1141 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1142 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1143 NS_ASSERTION(mKeyRange, "This should never be null!");
1145 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1146 "GetKeyHelper::PackArgumentsForParentProcess");
1148 GetKeyParams params;
1150 mKeyRange->ToSerializedKeyRange(params.keyRange());
1152 aParams = params;
1153 return NS_OK;
1154 }
1156 AsyncConnectionHelper::ChildProcessSendResult
1157 GetKeyHelper::SendResponseToChildProcess(nsresult aResultCode)
1158 {
1159 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1160 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1162 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1163 "GetKeyHelper::SendResponseToChildProcess");
1165 IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
1166 NS_ASSERTION(actor, "How did we get this far without an actor?");
1168 ResponseValue response;
1169 if (NS_FAILED(aResultCode)) {
1170 response = aResultCode;
1171 }
1172 else {
1173 GetKeyResponse getKeyResponse;
1174 getKeyResponse.key() = mKey;
1175 response = getKeyResponse;
1176 }
1178 if (!actor->SendResponse(response)) {
1179 return Error;
1180 }
1182 return Success_Sent;
1183 }
1185 nsresult
1186 GetKeyHelper::UnpackResponseFromParentProcess(
1187 const ResponseValue& aResponseValue)
1188 {
1189 NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetKeyResponse,
1190 "Bad response type!");
1192 mKey = aResponseValue.get_GetKeyResponse().key();
1193 return NS_OK;
1194 }
1196 nsresult
1197 GetHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
1198 {
1199 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
1200 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1201 NS_ASSERTION(mKeyRange, "Must have a key range here!");
1203 PROFILER_LABEL("IndexedDB", "GetHelper::DoDatabaseWork [IDBIndex.cpp]");
1205 nsCString indexTable;
1206 if (mIndex->IsUnique()) {
1207 indexTable.AssignLiteral("unique_index_data");
1208 }
1209 else {
1210 indexTable.AssignLiteral("index_data");
1211 }
1213 nsCString keyRangeClause;
1214 mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause);
1216 NS_ASSERTION(!keyRangeClause.IsEmpty(), "Huh?!");
1218 nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
1219 "INNER JOIN ") + indexTable +
1220 NS_LITERAL_CSTRING(" AS index_table ON object_data.id = ") +
1221 NS_LITERAL_CSTRING("index_table.object_data_id WHERE "
1222 "index_id = :index_id") +
1223 keyRangeClause +
1224 NS_LITERAL_CSTRING(" LIMIT 1");
1226 nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
1227 IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1229 mozStorageStatementScoper scoper(stmt);
1231 nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
1232 mIndex->Id());
1233 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1235 rv = mKeyRange->BindToStatement(stmt);
1236 NS_ENSURE_SUCCESS(rv, rv);
1238 bool hasResult;
1239 rv = stmt->ExecuteStep(&hasResult);
1240 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1242 if (hasResult) {
1243 rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
1244 mDatabase, mCloneReadInfo);
1245 NS_ENSURE_SUCCESS(rv, rv);
1246 }
1248 return NS_OK;
1249 }
1251 nsresult
1252 GetHelper::GetSuccessResult(JSContext* aCx,
1253 JS::MutableHandle<JS::Value> aVal)
1254 {
1255 bool result = IDBObjectStore::DeserializeValue(aCx, mCloneReadInfo, aVal);
1257 mCloneReadInfo.mCloneBuffer.clear();
1259 NS_ENSURE_TRUE(result, NS_ERROR_FAILURE);
1260 return NS_OK;
1261 }
1263 void
1264 GetHelper::ReleaseMainThreadObjects()
1265 {
1266 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
1267 GetKeyHelper::ReleaseMainThreadObjects();
1268 }
1270 nsresult
1271 GetHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
1272 {
1273 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1274 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1275 NS_ASSERTION(mKeyRange, "This should never be null!");
1277 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1278 "GetHelper::PackArgumentsForParentProcess "
1279 "[IDBIndex.cpp]");
1281 GetParams params;
1283 mKeyRange->ToSerializedKeyRange(params.keyRange());
1285 aParams = params;
1286 return NS_OK;
1287 }
1289 AsyncConnectionHelper::ChildProcessSendResult
1290 GetHelper::SendResponseToChildProcess(nsresult aResultCode)
1291 {
1292 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1293 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1295 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1296 "GetHelper::SendResponseToChildProcess "
1297 "[IDBIndex.cpp]");
1299 IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
1300 NS_ASSERTION(actor, "How did we get this far without an actor?");
1302 InfallibleTArray<PBlobParent*> blobsParent;
1304 if (NS_SUCCEEDED(aResultCode)) {
1305 IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
1306 NS_ASSERTION(database, "This should never be null!");
1308 ContentParent* contentParent = database->GetContentParent();
1309 NS_ASSERTION(contentParent, "This should never be null!");
1311 FileManager* fileManager = database->Manager();
1312 NS_ASSERTION(fileManager, "This should never be null!");
1314 const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
1316 aResultCode =
1317 IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
1318 blobsParent);
1319 if (NS_FAILED(aResultCode)) {
1320 NS_WARNING("ConvertBlobActors failed!");
1321 }
1322 }
1324 ResponseValue response;
1325 if (NS_FAILED(aResultCode)) {
1326 response = aResultCode;
1327 }
1328 else {
1329 GetResponse getResponse;
1330 getResponse.cloneInfo() = mCloneReadInfo;
1331 getResponse.blobsParent().SwapElements(blobsParent);
1332 response = getResponse;
1333 }
1335 if (!actor->SendResponse(response)) {
1336 return Error;
1337 }
1339 return Success_Sent;
1340 }
1342 nsresult
1343 GetHelper::UnpackResponseFromParentProcess(const ResponseValue& aResponseValue)
1344 {
1345 NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetResponse,
1346 "Bad response type!");
1348 const GetResponse& getResponse = aResponseValue.get_GetResponse();
1349 const SerializedStructuredCloneReadInfo& cloneInfo = getResponse.cloneInfo();
1351 NS_ASSERTION((!cloneInfo.dataLength && !cloneInfo.data) ||
1352 (cloneInfo.dataLength && cloneInfo.data),
1353 "Inconsistent clone info!");
1355 if (!mCloneReadInfo.SetFromSerialized(cloneInfo)) {
1356 IDB_WARNING("Failed to copy clone buffer!");
1357 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1358 }
1360 IDBObjectStore::ConvertActorsToBlobs(getResponse.blobsChild(),
1361 mCloneReadInfo.mFiles);
1362 return NS_OK;
1363 }
1365 nsresult
1366 GetAllKeysHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
1367 {
1368 MOZ_ASSERT(!NS_IsMainThread());
1369 MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
1371 PROFILER_LABEL("IndexedDB",
1372 "GetAllKeysHelper::DoDatabaseWork [IDBIndex.cpp]");
1374 nsCString tableName;
1375 if (mIndex->IsUnique()) {
1376 tableName.AssignLiteral("unique_index_data");
1377 }
1378 else {
1379 tableName.AssignLiteral("index_data");
1380 }
1382 nsCString keyRangeClause;
1383 if (mKeyRange) {
1384 mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause);
1385 }
1387 nsCString limitClause;
1388 if (mLimit != UINT32_MAX) {
1389 limitClause = NS_LITERAL_CSTRING(" LIMIT ");
1390 limitClause.AppendInt(mLimit);
1391 }
1393 nsCString query = NS_LITERAL_CSTRING("SELECT object_data_key FROM ") +
1394 tableName +
1395 NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
1396 keyRangeClause + limitClause;
1398 nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
1399 IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1401 mozStorageStatementScoper scoper(stmt);
1403 nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
1404 mIndex->Id());
1405 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1407 if (mKeyRange) {
1408 rv = mKeyRange->BindToStatement(stmt);
1409 NS_ENSURE_SUCCESS(rv, rv);
1410 }
1412 mKeys.SetCapacity(std::min<uint32_t>(50, mLimit));
1414 bool hasResult;
1415 while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
1416 if (mKeys.Capacity() == mKeys.Length()) {
1417 mKeys.SetCapacity(mKeys.Capacity() * 2);
1418 }
1420 Key* key = mKeys.AppendElement();
1421 NS_ASSERTION(key, "This shouldn't fail!");
1423 rv = key->SetFromStatement(stmt, 0);
1424 NS_ENSURE_SUCCESS(rv, rv);
1425 }
1426 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1428 return NS_OK;
1429 }
1431 nsresult
1432 GetAllKeysHelper::GetSuccessResult(JSContext* aCx,
1433 JS::MutableHandle<JS::Value> aVal)
1434 {
1435 MOZ_ASSERT(NS_IsMainThread());
1436 MOZ_ASSERT(mKeys.Length() <= mLimit);
1438 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1439 "GetAllKeysHelper::GetSuccessResult "
1440 "[IDBIndex.cpp]");
1442 nsTArray<Key> keys;
1443 mKeys.SwapElements(keys);
1445 JS::Rooted<JSObject*> array(aCx, JS_NewArrayObject(aCx, 0));
1446 if (!array) {
1447 IDB_WARNING("Failed to make array!");
1448 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1449 }
1451 if (!keys.IsEmpty()) {
1452 if (!JS_SetArrayLength(aCx, array, uint32_t(keys.Length()))) {
1453 IDB_WARNING("Failed to set array length!");
1454 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1455 }
1457 for (uint32_t index = 0, count = keys.Length(); index < count; index++) {
1458 const Key& key = keys[index];
1459 NS_ASSERTION(!key.IsUnset(), "Bad key!");
1461 JS::Rooted<JS::Value> value(aCx);
1462 nsresult rv = key.ToJSVal(aCx, &value);
1463 if (NS_FAILED(rv)) {
1464 NS_WARNING("Failed to get jsval for key!");
1465 return rv;
1466 }
1468 if (!JS_SetElement(aCx, array, index, value)) {
1469 IDB_WARNING("Failed to set array element!");
1470 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1471 }
1472 }
1473 }
1475 aVal.setObject(*array);
1476 return NS_OK;
1477 }
1479 nsresult
1480 GetAllKeysHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
1481 {
1482 MOZ_ASSERT(NS_IsMainThread());
1483 MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
1485 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1486 "GetAllKeysHelper::PackArgumentsForParentProcess "
1487 "[IDBIndex.cpp]");
1489 GetAllKeysParams params;
1491 if (mKeyRange) {
1492 KeyRange keyRange;
1493 mKeyRange->ToSerializedKeyRange(keyRange);
1494 params.optionalKeyRange() = keyRange;
1495 }
1496 else {
1497 params.optionalKeyRange() = mozilla::void_t();
1498 }
1500 params.limit() = mLimit;
1502 aParams = params;
1503 return NS_OK;
1504 }
1506 AsyncConnectionHelper::ChildProcessSendResult
1507 GetAllKeysHelper::SendResponseToChildProcess(nsresult aResultCode)
1508 {
1509 MOZ_ASSERT(NS_IsMainThread());
1510 MOZ_ASSERT(IndexedDatabaseManager::IsMainProcess());
1512 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1513 "GetAllKeysHelper::SendResponseToChildProcess "
1514 "[IDBIndex.cpp]");
1516 IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
1517 NS_ASSERTION(actor, "How did we get this far without an actor?");
1519 ResponseValue response;
1520 if (NS_FAILED(aResultCode)) {
1521 response = aResultCode;
1522 }
1523 else {
1524 GetAllKeysResponse getAllKeysResponse;
1525 getAllKeysResponse.keys().AppendElements(mKeys);
1526 response = getAllKeysResponse;
1527 }
1529 if (!actor->SendResponse(response)) {
1530 return Error;
1531 }
1533 return Success_Sent;
1534 }
1536 nsresult
1537 GetAllKeysHelper::UnpackResponseFromParentProcess(
1538 const ResponseValue& aResponseValue)
1539 {
1540 MOZ_ASSERT(NS_IsMainThread());
1541 MOZ_ASSERT(!IndexedDatabaseManager::IsMainProcess());
1542 MOZ_ASSERT(aResponseValue.type() == ResponseValue::TGetAllKeysResponse);
1544 mKeys.AppendElements(aResponseValue.get_GetAllKeysResponse().keys());
1545 return NS_OK;
1546 }
1548 nsresult
1549 GetAllHelper::DoDatabaseWork(mozIStorageConnection* /* aConnection */)
1550 {
1551 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
1552 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1554 PROFILER_LABEL("IndexedDB", "GetAllHelper::DoDatabaseWork [IDBIndex.cpp]");
1556 nsCString indexTable;
1557 if (mIndex->IsUnique()) {
1558 indexTable.AssignLiteral("unique_index_data");
1559 }
1560 else {
1561 indexTable.AssignLiteral("index_data");
1562 }
1564 nsCString keyRangeClause;
1565 if (mKeyRange) {
1566 mKeyRange->GetBindingClause(NS_LITERAL_CSTRING("value"), keyRangeClause);
1567 }
1569 nsCString limitClause;
1570 if (mLimit != UINT32_MAX) {
1571 limitClause = NS_LITERAL_CSTRING(" LIMIT ");
1572 limitClause.AppendInt(mLimit);
1573 }
1575 nsCString query = NS_LITERAL_CSTRING("SELECT data, file_ids FROM object_data "
1576 "INNER JOIN ") + indexTable +
1577 NS_LITERAL_CSTRING(" AS index_table ON object_data.id = "
1578 "index_table.object_data_id "
1579 "WHERE index_id = :index_id") +
1580 keyRangeClause + limitClause;
1582 nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
1583 IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1585 mozStorageStatementScoper scoper(stmt);
1587 nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
1588 mIndex->Id());
1589 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1591 if (mKeyRange) {
1592 rv = mKeyRange->BindToStatement(stmt);
1593 NS_ENSURE_SUCCESS(rv, rv);
1594 }
1596 mCloneReadInfos.SetCapacity(50);
1598 bool hasResult;
1599 while(NS_SUCCEEDED((rv = stmt->ExecuteStep(&hasResult))) && hasResult) {
1600 if (mCloneReadInfos.Capacity() == mCloneReadInfos.Length()) {
1601 mCloneReadInfos.SetCapacity(mCloneReadInfos.Capacity() * 2);
1602 }
1604 StructuredCloneReadInfo* readInfo = mCloneReadInfos.AppendElement();
1605 NS_ASSERTION(readInfo, "This shouldn't fail!");
1607 rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 0, 1,
1608 mDatabase, *readInfo);
1609 NS_ENSURE_SUCCESS(rv, rv);
1610 }
1611 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1613 return NS_OK;
1614 }
1616 nsresult
1617 GetAllHelper::GetSuccessResult(JSContext* aCx,
1618 JS::MutableHandle<JS::Value> aVal)
1619 {
1620 NS_ASSERTION(mCloneReadInfos.Length() <= mLimit, "Too many results!");
1622 nsresult rv = ConvertToArrayAndCleanup(aCx, mCloneReadInfos, aVal);
1624 NS_ASSERTION(mCloneReadInfos.IsEmpty(),
1625 "Should have cleared in ConvertToArrayAndCleanup");
1626 NS_ENSURE_SUCCESS(rv, rv);
1628 return NS_OK;
1629 }
1631 void
1632 GetAllHelper::ReleaseMainThreadObjects()
1633 {
1634 for (uint32_t index = 0; index < mCloneReadInfos.Length(); index++) {
1635 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfos[index]);
1636 }
1637 GetKeyHelper::ReleaseMainThreadObjects();
1638 }
1640 nsresult
1641 GetAllHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
1642 {
1643 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1644 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1646 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1647 "GetAllHelper::PackArgumentsForParentProcess "
1648 "[IDBIndex.cpp]");
1650 GetAllParams params;
1652 if (mKeyRange) {
1653 KeyRange keyRange;
1654 mKeyRange->ToSerializedKeyRange(keyRange);
1655 params.optionalKeyRange() = keyRange;
1656 }
1657 else {
1658 params.optionalKeyRange() = mozilla::void_t();
1659 }
1661 params.limit() = mLimit;
1663 aParams = params;
1664 return NS_OK;
1665 }
1667 AsyncConnectionHelper::ChildProcessSendResult
1668 GetAllHelper::SendResponseToChildProcess(nsresult aResultCode)
1669 {
1670 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1671 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1673 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1674 "GetAllHelper::SendResponseToChildProcess "
1675 "[IDBIndex.cpp]");
1677 IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
1678 NS_ASSERTION(actor, "How did we get this far without an actor?");
1680 GetAllResponse getAllResponse;
1682 if (NS_SUCCEEDED(aResultCode) && !mCloneReadInfos.IsEmpty()) {
1683 IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
1684 NS_ASSERTION(database, "This should never be null!");
1686 ContentParent* contentParent = database->GetContentParent();
1687 NS_ASSERTION(contentParent, "This should never be null!");
1689 FileManager* fileManager = database->Manager();
1690 NS_ASSERTION(fileManager, "This should never be null!");
1692 uint32_t length = mCloneReadInfos.Length();
1694 InfallibleTArray<SerializedStructuredCloneReadInfo>& infos =
1695 getAllResponse.cloneInfos();
1696 infos.SetCapacity(length);
1698 InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
1699 blobArrays.SetCapacity(length);
1701 for (uint32_t index = 0;
1702 NS_SUCCEEDED(aResultCode) && index < length;
1703 index++) {
1704 const StructuredCloneReadInfo& clone = mCloneReadInfos[index];
1706 // Append the structured clone data.
1707 SerializedStructuredCloneReadInfo* info = infos.AppendElement();
1708 *info = clone;
1710 const nsTArray<StructuredCloneFile>& files = clone.mFiles;
1712 // Now take care of the files.
1713 BlobArray* blobArray = blobArrays.AppendElement();
1715 InfallibleTArray<PBlobParent*>& blobs = blobArray->blobsParent();
1717 aResultCode =
1718 IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
1719 blobs);
1720 if (NS_FAILED(aResultCode)) {
1721 NS_WARNING("ConvertBlobsToActors failed!");
1722 break;
1723 }
1724 }
1725 }
1727 ResponseValue response;
1728 if (NS_FAILED(aResultCode)) {
1729 response = aResultCode;
1730 }
1731 else {
1732 response = getAllResponse;
1733 }
1735 if (!actor->SendResponse(response)) {
1736 return Error;
1737 }
1739 return Success_Sent;
1740 }
1742 nsresult
1743 GetAllHelper::UnpackResponseFromParentProcess(
1744 const ResponseValue& aResponseValue)
1745 {
1746 NS_ASSERTION(aResponseValue.type() == ResponseValue::TGetAllResponse,
1747 "Bad response type!");
1749 const GetAllResponse& getAllResponse = aResponseValue.get_GetAllResponse();
1750 const InfallibleTArray<SerializedStructuredCloneReadInfo>& cloneInfos =
1751 getAllResponse.cloneInfos();
1752 const InfallibleTArray<BlobArray>& blobArrays = getAllResponse.blobs();
1754 mCloneReadInfos.SetCapacity(cloneInfos.Length());
1756 for (uint32_t index = 0; index < cloneInfos.Length(); index++) {
1757 const SerializedStructuredCloneReadInfo srcInfo = cloneInfos[index];
1758 const InfallibleTArray<PBlobChild*>& blobs = blobArrays[index].blobsChild();
1760 StructuredCloneReadInfo* destInfo = mCloneReadInfos.AppendElement();
1761 if (!destInfo->SetFromSerialized(srcInfo)) {
1762 IDB_WARNING("Failed to copy clone buffer!");
1763 return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
1764 }
1766 IDBObjectStore::ConvertActorsToBlobs(blobs, destInfo->mFiles);
1767 }
1769 return NS_OK;
1770 }
1772 nsresult
1773 OpenKeyCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
1774 {
1775 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
1776 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1777 NS_ASSERTION(aConnection, "Passed a null connection!");
1779 PROFILER_LABEL("IndexedDB", "OpenKeyCursorHelper::DoDatabaseWork");
1781 nsCString table;
1782 if (mIndex->IsUnique()) {
1783 table.AssignLiteral("unique_index_data");
1784 }
1785 else {
1786 table.AssignLiteral("index_data");
1787 }
1789 NS_NAMED_LITERAL_CSTRING(value, "value");
1791 nsCString keyRangeClause;
1792 if (mKeyRange) {
1793 mKeyRange->GetBindingClause(value, keyRangeClause);
1794 }
1796 nsAutoCString directionClause(" ORDER BY value ");
1797 switch (mDirection) {
1798 case IDBCursor::NEXT:
1799 case IDBCursor::NEXT_UNIQUE:
1800 directionClause += NS_LITERAL_CSTRING("ASC, object_data_key ASC");
1801 break;
1803 case IDBCursor::PREV:
1804 directionClause += NS_LITERAL_CSTRING("DESC, object_data_key DESC");
1805 break;
1807 case IDBCursor::PREV_UNIQUE:
1808 directionClause += NS_LITERAL_CSTRING("DESC, object_data_key ASC");
1809 break;
1811 default:
1812 NS_NOTREACHED("Unknown direction!");
1813 }
1814 nsCString firstQuery = NS_LITERAL_CSTRING("SELECT value, object_data_key "
1815 "FROM ") + table +
1816 NS_LITERAL_CSTRING(" WHERE index_id = :index_id") +
1817 keyRangeClause + directionClause +
1818 NS_LITERAL_CSTRING(" LIMIT 1");
1820 nsCOMPtr<mozIStorageStatement> stmt =
1821 mTransaction->GetCachedStatement(firstQuery);
1822 IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1824 mozStorageStatementScoper scoper(stmt);
1826 nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("index_id"),
1827 mIndex->Id());
1828 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1830 if (mKeyRange) {
1831 rv = mKeyRange->BindToStatement(stmt);
1832 NS_ENSURE_SUCCESS(rv, rv);
1833 }
1835 bool hasResult;
1836 rv = stmt->ExecuteStep(&hasResult);
1837 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1839 if (!hasResult) {
1840 mKey.Unset();
1841 return NS_OK;
1842 }
1844 rv = mKey.SetFromStatement(stmt, 0);
1845 NS_ENSURE_SUCCESS(rv, rv);
1847 rv = mObjectKey.SetFromStatement(stmt, 1);
1848 NS_ENSURE_SUCCESS(rv, rv);
1850 // Now we need to make the query to get the next match.
1851 nsAutoCString queryStart = NS_LITERAL_CSTRING("SELECT value, object_data_key"
1852 " FROM ") + table +
1853 NS_LITERAL_CSTRING(" WHERE index_id = :id");
1855 NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
1857 switch (mDirection) {
1858 case IDBCursor::NEXT:
1859 if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
1860 AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
1861 queryStart);
1862 mRangeKey = mKeyRange->Upper();
1863 }
1864 mContinueQuery =
1865 queryStart +
1866 NS_LITERAL_CSTRING(" AND value >= :current_key AND "
1867 "( value > :current_key OR "
1868 " object_data_key > :object_key )") +
1869 directionClause +
1870 NS_LITERAL_CSTRING(" LIMIT ");
1871 mContinueToQuery =
1872 queryStart +
1873 NS_LITERAL_CSTRING(" AND value >= :current_key ") +
1874 directionClause +
1875 NS_LITERAL_CSTRING(" LIMIT ");
1876 break;
1878 case IDBCursor::NEXT_UNIQUE:
1879 if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
1880 AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
1881 queryStart);
1882 mRangeKey = mKeyRange->Upper();
1883 }
1884 mContinueQuery =
1885 queryStart + NS_LITERAL_CSTRING(" AND value > :current_key") +
1886 directionClause +
1887 NS_LITERAL_CSTRING(" LIMIT ");
1888 mContinueToQuery =
1889 queryStart + NS_LITERAL_CSTRING(" AND value >= :current_key") +
1890 directionClause +
1891 NS_LITERAL_CSTRING(" LIMIT ");
1892 break;
1894 case IDBCursor::PREV:
1895 if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
1896 AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
1897 queryStart);
1898 mRangeKey = mKeyRange->Lower();
1899 }
1901 mContinueQuery =
1902 queryStart +
1903 NS_LITERAL_CSTRING(" AND value <= :current_key AND "
1904 "( value < :current_key OR "
1905 " object_data_key < :object_key )") +
1906 directionClause +
1907 NS_LITERAL_CSTRING(" LIMIT ");
1908 mContinueToQuery =
1909 queryStart +
1910 NS_LITERAL_CSTRING(" AND value <= :current_key ") +
1911 directionClause +
1912 NS_LITERAL_CSTRING(" LIMIT ");
1913 break;
1915 case IDBCursor::PREV_UNIQUE:
1916 if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
1917 AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
1918 queryStart);
1919 mRangeKey = mKeyRange->Lower();
1920 }
1921 mContinueQuery =
1922 queryStart +
1923 NS_LITERAL_CSTRING(" AND value < :current_key") +
1924 directionClause +
1925 NS_LITERAL_CSTRING(" LIMIT ");
1926 mContinueToQuery =
1927 queryStart +
1928 NS_LITERAL_CSTRING(" AND value <= :current_key") +
1929 directionClause +
1930 NS_LITERAL_CSTRING(" LIMIT ");
1931 break;
1933 default:
1934 NS_NOTREACHED("Unknown direction type!");
1935 }
1937 return NS_OK;
1938 }
1940 nsresult
1941 OpenKeyCursorHelper::EnsureCursor()
1942 {
1943 if (mCursor || mKey.IsUnset()) {
1944 return NS_OK;
1945 }
1947 nsRefPtr<IDBCursor> cursor =
1948 IDBCursor::Create(mRequest, mTransaction, mIndex, mDirection, mRangeKey,
1949 mContinueQuery, mContinueToQuery, mKey, mObjectKey);
1950 IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1952 mCursor.swap(cursor);
1953 return NS_OK;
1954 }
1956 nsresult
1957 OpenKeyCursorHelper::GetSuccessResult(JSContext* aCx,
1958 JS::MutableHandle<JS::Value> aVal)
1959 {
1960 nsresult rv = EnsureCursor();
1961 NS_ENSURE_SUCCESS(rv, rv);
1963 if (mCursor) {
1964 rv = WrapNative(aCx, mCursor, aVal);
1965 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
1966 }
1967 else {
1968 aVal.setUndefined();
1969 }
1971 return NS_OK;
1972 }
1974 void
1975 OpenKeyCursorHelper::ReleaseMainThreadObjects()
1976 {
1977 mKeyRange = nullptr;
1978 mCursor = nullptr;
1979 IndexHelper::ReleaseMainThreadObjects();
1980 }
1982 nsresult
1983 OpenKeyCursorHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
1984 {
1985 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
1986 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
1988 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
1989 "OpenKeyCursorHelper::"
1990 "PackArgumentsForParentProcess [IDBIndex.cpp]");
1992 OpenKeyCursorParams params;
1994 if (mKeyRange) {
1995 KeyRange keyRange;
1996 mKeyRange->ToSerializedKeyRange(keyRange);
1997 params.optionalKeyRange() = keyRange;
1998 }
1999 else {
2000 params.optionalKeyRange() = mozilla::void_t();
2001 }
2003 params.direction() = mDirection;
2005 aParams = params;
2006 return NS_OK;
2007 }
2009 AsyncConnectionHelper::ChildProcessSendResult
2010 OpenKeyCursorHelper::SendResponseToChildProcess(nsresult aResultCode)
2011 {
2012 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2013 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2014 NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
2016 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
2017 "OpenKeyCursorHelper::SendResponseToChildProcess");
2019 IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
2020 NS_ASSERTION(actor, "How did we get this far without an actor?");
2022 if (NS_SUCCEEDED(aResultCode)) {
2023 nsresult rv = EnsureCursor();
2024 if (NS_FAILED(rv)) {
2025 NS_WARNING("EnsureCursor failed!");
2026 aResultCode = rv;
2027 }
2028 }
2030 ResponseValue response;
2031 if (NS_FAILED(aResultCode)) {
2032 response = aResultCode;
2033 }
2034 else {
2035 OpenCursorResponse openCursorResponse;
2037 if (!mCursor) {
2038 openCursorResponse = mozilla::void_t();
2039 }
2040 else {
2041 IndexedDBIndexParent* indexActor = mIndex->GetActorParent();
2042 NS_ASSERTION(indexActor, "Must have an actor here!");
2044 IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent();
2045 NS_ASSERTION(requestActor, "Must have an actor here!");
2047 IndexCursorConstructorParams params;
2048 params.requestParent() = requestActor;
2049 params.direction() = mDirection;
2050 params.key() = mKey;
2051 params.objectKey() = mObjectKey;
2052 params.optionalCloneInfo() = mozilla::void_t();
2054 if (!indexActor->OpenCursor(mCursor, params, openCursorResponse)) {
2055 return Error;
2056 }
2057 }
2059 response = openCursorResponse;
2060 }
2062 if (!actor->SendResponse(response)) {
2063 return Error;
2064 }
2066 return Success_Sent;
2067 }
2069 nsresult
2070 OpenKeyCursorHelper::UnpackResponseFromParentProcess(
2071 const ResponseValue& aResponseValue)
2072 {
2073 NS_ASSERTION(aResponseValue.type() == ResponseValue::TOpenCursorResponse,
2074 "Bad response type!");
2075 NS_ASSERTION(aResponseValue.get_OpenCursorResponse().type() ==
2076 OpenCursorResponse::Tvoid_t ||
2077 aResponseValue.get_OpenCursorResponse().type() ==
2078 OpenCursorResponse::TPIndexedDBCursorChild,
2079 "Bad response union type!");
2080 NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
2082 const OpenCursorResponse& response =
2083 aResponseValue.get_OpenCursorResponse();
2085 switch (response.type()) {
2086 case OpenCursorResponse::Tvoid_t:
2087 break;
2089 case OpenCursorResponse::TPIndexedDBCursorChild: {
2090 IndexedDBCursorChild* actor =
2091 static_cast<IndexedDBCursorChild*>(
2092 response.get_PIndexedDBCursorChild());
2094 mCursor = actor->ForgetStrongCursor();
2095 NS_ASSERTION(mCursor, "This should never be null!");
2097 } break;
2099 default:
2100 MOZ_CRASH();
2101 }
2103 return NS_OK;
2104 }
2106 nsresult
2107 OpenCursorHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
2108 {
2109 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
2110 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2111 NS_ASSERTION(aConnection, "Passed a null connection!");
2113 PROFILER_LABEL("IndexedDB",
2114 "OpenCursorHelper::DoDatabaseWork [IDBIndex.cpp]");
2116 nsCString indexTable;
2117 if (mIndex->IsUnique()) {
2118 indexTable.AssignLiteral("unique_index_data");
2119 }
2120 else {
2121 indexTable.AssignLiteral("index_data");
2122 }
2124 NS_NAMED_LITERAL_CSTRING(value, "index_table.value");
2126 nsCString keyRangeClause;
2127 if (mKeyRange) {
2128 mKeyRange->GetBindingClause(value, keyRangeClause);
2129 }
2131 nsAutoCString directionClause(" ORDER BY index_table.value ");
2132 switch (mDirection) {
2133 case IDBCursor::NEXT:
2134 case IDBCursor::NEXT_UNIQUE:
2135 directionClause +=
2136 NS_LITERAL_CSTRING("ASC, index_table.object_data_key ASC");
2137 break;
2139 case IDBCursor::PREV:
2140 directionClause +=
2141 NS_LITERAL_CSTRING("DESC, index_table.object_data_key DESC");
2142 break;
2144 case IDBCursor::PREV_UNIQUE:
2145 directionClause +=
2146 NS_LITERAL_CSTRING("DESC, index_table.object_data_key ASC");
2147 break;
2149 default:
2150 NS_NOTREACHED("Unknown direction!");
2151 }
2153 nsCString firstQuery =
2154 NS_LITERAL_CSTRING("SELECT index_table.value, "
2155 "index_table.object_data_key, object_data.data, "
2156 "object_data.file_ids FROM ") +
2157 indexTable +
2158 NS_LITERAL_CSTRING(" AS index_table INNER JOIN object_data ON "
2159 "index_table.object_data_id = object_data.id "
2160 "WHERE index_table.index_id = :id") +
2161 keyRangeClause + directionClause +
2162 NS_LITERAL_CSTRING(" LIMIT 1");
2164 nsCOMPtr<mozIStorageStatement> stmt =
2165 mTransaction->GetCachedStatement(firstQuery);
2166 IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
2168 mozStorageStatementScoper scoper(stmt);
2170 nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id());
2171 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
2173 if (mKeyRange) {
2174 rv = mKeyRange->BindToStatement(stmt);
2175 NS_ENSURE_SUCCESS(rv, rv);
2176 }
2178 bool hasResult;
2179 rv = stmt->ExecuteStep(&hasResult);
2180 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
2182 if (!hasResult) {
2183 mKey.Unset();
2184 return NS_OK;
2185 }
2187 rv = mKey.SetFromStatement(stmt, 0);
2188 NS_ENSURE_SUCCESS(rv, rv);
2190 rv = mObjectKey.SetFromStatement(stmt, 1);
2191 NS_ENSURE_SUCCESS(rv, rv);
2193 rv = IDBObjectStore::GetStructuredCloneReadInfoFromStatement(stmt, 2, 3,
2194 mDatabase, mCloneReadInfo);
2195 NS_ENSURE_SUCCESS(rv, rv);
2197 // Now we need to make the query to get the next match.
2198 nsAutoCString queryStart =
2199 NS_LITERAL_CSTRING("SELECT index_table.value, "
2200 "index_table.object_data_key, object_data.data, "
2201 "object_data.file_ids FROM ") +
2202 indexTable +
2203 NS_LITERAL_CSTRING(" AS index_table INNER JOIN object_data ON "
2204 "index_table.object_data_id = object_data.id "
2205 "WHERE index_table.index_id = :id");
2207 NS_NAMED_LITERAL_CSTRING(rangeKey, "range_key");
2209 NS_NAMED_LITERAL_CSTRING(limit, " LIMIT ");
2211 switch (mDirection) {
2212 case IDBCursor::NEXT:
2213 if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
2214 AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
2215 queryStart);
2216 mRangeKey = mKeyRange->Upper();
2217 }
2218 mContinueQuery =
2219 queryStart +
2220 NS_LITERAL_CSTRING(" AND index_table.value >= :current_key AND "
2221 "( index_table.value > :current_key OR "
2222 " index_table.object_data_key > :object_key ) ") +
2223 directionClause + limit;
2224 mContinueToQuery =
2225 queryStart +
2226 NS_LITERAL_CSTRING(" AND index_table.value >= :current_key") +
2227 directionClause + limit;
2228 break;
2230 case IDBCursor::NEXT_UNIQUE:
2231 if (mKeyRange && !mKeyRange->Upper().IsUnset()) {
2232 AppendConditionClause(value, rangeKey, true, !mKeyRange->IsUpperOpen(),
2233 queryStart);
2234 mRangeKey = mKeyRange->Upper();
2235 }
2236 mContinueQuery =
2237 queryStart +
2238 NS_LITERAL_CSTRING(" AND index_table.value > :current_key") +
2239 directionClause + limit;
2240 mContinueToQuery =
2241 queryStart +
2242 NS_LITERAL_CSTRING(" AND index_table.value >= :current_key") +
2243 directionClause + limit;
2244 break;
2246 case IDBCursor::PREV:
2247 if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
2248 AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
2249 queryStart);
2250 mRangeKey = mKeyRange->Lower();
2251 }
2252 mContinueQuery =
2253 queryStart +
2254 NS_LITERAL_CSTRING(" AND index_table.value <= :current_key AND "
2255 "( index_table.value < :current_key OR "
2256 " index_table.object_data_key < :object_key ) ") +
2257 directionClause + limit;
2258 mContinueToQuery =
2259 queryStart +
2260 NS_LITERAL_CSTRING(" AND index_table.value <= :current_key") +
2261 directionClause + limit;
2262 break;
2264 case IDBCursor::PREV_UNIQUE:
2265 if (mKeyRange && !mKeyRange->Lower().IsUnset()) {
2266 AppendConditionClause(value, rangeKey, false, !mKeyRange->IsLowerOpen(),
2267 queryStart);
2268 mRangeKey = mKeyRange->Lower();
2269 }
2270 mContinueQuery =
2271 queryStart +
2272 NS_LITERAL_CSTRING(" AND index_table.value < :current_key") +
2273 directionClause + limit;
2274 mContinueToQuery =
2275 queryStart +
2276 NS_LITERAL_CSTRING(" AND index_table.value <= :current_key") +
2277 directionClause + limit;
2278 break;
2280 default:
2281 NS_NOTREACHED("Unknown direction type!");
2282 }
2284 return NS_OK;
2285 }
2287 nsresult
2288 OpenCursorHelper::EnsureCursor()
2289 {
2290 if (mCursor || mKey.IsUnset()) {
2291 return NS_OK;
2292 }
2294 mSerializedCloneReadInfo = mCloneReadInfo;
2296 NS_ASSERTION(mSerializedCloneReadInfo.data &&
2297 mSerializedCloneReadInfo.dataLength,
2298 "Shouldn't be possible!");
2300 nsRefPtr<IDBCursor> cursor =
2301 IDBCursor::Create(mRequest, mTransaction, mIndex, mDirection, mRangeKey,
2302 mContinueQuery, mContinueToQuery, mKey, mObjectKey,
2303 Move(mCloneReadInfo));
2304 IDB_ENSURE_TRUE(cursor, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
2306 NS_ASSERTION(!mCloneReadInfo.mCloneBuffer.data(), "Should have swapped!");
2308 mCursor.swap(cursor);
2309 return NS_OK;
2310 }
2312 void
2313 OpenCursorHelper::ReleaseMainThreadObjects()
2314 {
2315 IDBObjectStore::ClearCloneReadInfo(mCloneReadInfo);
2317 // These don't need to be released on the main thread but they're only valid
2318 // as long as mCursor is set.
2319 mSerializedCloneReadInfo.data = nullptr;
2320 mSerializedCloneReadInfo.dataLength = 0;
2322 OpenKeyCursorHelper::ReleaseMainThreadObjects();
2323 }
2325 nsresult
2326 OpenCursorHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
2327 {
2328 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2329 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2331 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
2332 "OpenCursorHelper::PackArgumentsForParentProcess "
2333 "[IDBIndex.cpp]");
2335 OpenCursorParams params;
2337 if (mKeyRange) {
2338 KeyRange keyRange;
2339 mKeyRange->ToSerializedKeyRange(keyRange);
2340 params.optionalKeyRange() = keyRange;
2341 }
2342 else {
2343 params.optionalKeyRange() = mozilla::void_t();
2344 }
2346 params.direction() = mDirection;
2348 aParams = params;
2349 return NS_OK;
2350 }
2352 AsyncConnectionHelper::ChildProcessSendResult
2353 OpenCursorHelper::SendResponseToChildProcess(nsresult aResultCode)
2354 {
2355 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2356 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2357 NS_ASSERTION(!mCursor, "Shouldn't have this yet!");
2359 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
2360 "OpenCursorHelper::SendResponseToChildProcess "
2361 "[IDBIndex.cpp]");
2363 IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
2364 NS_ASSERTION(actor, "How did we get this far without an actor?");
2366 InfallibleTArray<PBlobParent*> blobsParent;
2368 if (NS_SUCCEEDED(aResultCode)) {
2369 IDBDatabase* database = mIndex->ObjectStore()->Transaction()->Database();
2370 NS_ASSERTION(database, "This should never be null!");
2372 ContentParent* contentParent = database->GetContentParent();
2373 NS_ASSERTION(contentParent, "This should never be null!");
2375 FileManager* fileManager = database->Manager();
2376 NS_ASSERTION(fileManager, "This should never be null!");
2378 const nsTArray<StructuredCloneFile>& files = mCloneReadInfo.mFiles;
2380 aResultCode =
2381 IDBObjectStore::ConvertBlobsToActors(contentParent, fileManager, files,
2382 blobsParent);
2383 if (NS_FAILED(aResultCode)) {
2384 NS_WARNING("ConvertBlobsToActors failed!");
2385 }
2386 }
2388 if (NS_SUCCEEDED(aResultCode)) {
2389 nsresult rv = EnsureCursor();
2390 if (NS_FAILED(rv)) {
2391 NS_WARNING("EnsureCursor failed!");
2392 aResultCode = rv;
2393 }
2394 }
2396 ResponseValue response;
2397 if (NS_FAILED(aResultCode)) {
2398 response = aResultCode;
2399 }
2400 else {
2401 OpenCursorResponse openCursorResponse;
2403 if (!mCursor) {
2404 openCursorResponse = mozilla::void_t();
2405 }
2406 else {
2407 IndexedDBIndexParent* indexActor = mIndex->GetActorParent();
2408 NS_ASSERTION(indexActor, "Must have an actor here!");
2410 IndexedDBRequestParentBase* requestActor = mRequest->GetActorParent();
2411 NS_ASSERTION(requestActor, "Must have an actor here!");
2413 NS_ASSERTION(mSerializedCloneReadInfo.data &&
2414 mSerializedCloneReadInfo.dataLength,
2415 "Shouldn't be possible!");
2417 IndexCursorConstructorParams params;
2418 params.requestParent() = requestActor;
2419 params.direction() = mDirection;
2420 params.key() = mKey;
2421 params.objectKey() = mObjectKey;
2422 params.optionalCloneInfo() = mSerializedCloneReadInfo;
2423 params.blobsParent().SwapElements(blobsParent);
2425 if (!indexActor->OpenCursor(mCursor, params, openCursorResponse)) {
2426 return Error;
2427 }
2428 }
2430 response = openCursorResponse;
2431 }
2433 if (!actor->SendResponse(response)) {
2434 return Error;
2435 }
2437 return Success_Sent;
2438 }
2440 nsresult
2441 CountHelper::DoDatabaseWork(mozIStorageConnection* aConnection)
2442 {
2443 NS_ASSERTION(!NS_IsMainThread(), "Wrong thread!");
2444 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2446 PROFILER_LABEL("IndexedDB", "CountHelper::DoDatabaseWork [IDBIndex.cpp]");
2448 nsCString table;
2449 if (mIndex->IsUnique()) {
2450 table.AssignLiteral("unique_index_data");
2451 }
2452 else {
2453 table.AssignLiteral("index_data");
2454 }
2456 NS_NAMED_LITERAL_CSTRING(lowerKeyName, "lower_key");
2457 NS_NAMED_LITERAL_CSTRING(upperKeyName, "upper_key");
2458 NS_NAMED_LITERAL_CSTRING(value, "value");
2460 nsAutoCString keyRangeClause;
2461 if (mKeyRange) {
2462 if (!mKeyRange->Lower().IsUnset()) {
2463 AppendConditionClause(value, lowerKeyName, false,
2464 !mKeyRange->IsLowerOpen(), keyRangeClause);
2465 }
2466 if (!mKeyRange->Upper().IsUnset()) {
2467 AppendConditionClause(value, upperKeyName, true,
2468 !mKeyRange->IsUpperOpen(), keyRangeClause);
2469 }
2470 }
2472 nsCString query = NS_LITERAL_CSTRING("SELECT count(*) FROM ") + table +
2473 NS_LITERAL_CSTRING(" WHERE index_id = :id") +
2474 keyRangeClause;
2476 nsCOMPtr<mozIStorageStatement> stmt = mTransaction->GetCachedStatement(query);
2477 IDB_ENSURE_TRUE(stmt, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
2479 mozStorageStatementScoper scoper(stmt);
2481 nsresult rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("id"), mIndex->Id());
2482 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
2484 if (mKeyRange) {
2485 if (!mKeyRange->Lower().IsUnset()) {
2486 rv = mKeyRange->Lower().BindToStatement(stmt, lowerKeyName);
2487 NS_ENSURE_SUCCESS(rv, rv);
2488 }
2489 if (!mKeyRange->Upper().IsUnset()) {
2490 rv = mKeyRange->Upper().BindToStatement(stmt, upperKeyName);
2491 NS_ENSURE_SUCCESS(rv, rv);
2492 }
2493 }
2495 bool hasResult;
2496 rv = stmt->ExecuteStep(&hasResult);
2497 IDB_ENSURE_SUCCESS(rv, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
2498 IDB_ENSURE_TRUE(hasResult, NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR);
2500 mCount = stmt->AsInt64(0);
2501 return NS_OK;
2502 }
2504 nsresult
2505 CountHelper::GetSuccessResult(JSContext* aCx,
2506 JS::MutableHandle<JS::Value> aVal)
2507 {
2508 aVal.setNumber(static_cast<double>(mCount));
2509 return NS_OK;
2510 }
2512 void
2513 CountHelper::ReleaseMainThreadObjects()
2514 {
2515 mKeyRange = nullptr;
2516 IndexHelper::ReleaseMainThreadObjects();
2517 }
2519 nsresult
2520 CountHelper::PackArgumentsForParentProcess(IndexRequestParams& aParams)
2521 {
2522 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2523 NS_ASSERTION(!IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2525 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
2526 "CountHelper::PackArgumentsForParentProcess "
2527 "[IDBIndex.cpp]");
2529 CountParams params;
2531 if (mKeyRange) {
2532 KeyRange keyRange;
2533 mKeyRange->ToSerializedKeyRange(keyRange);
2534 params.optionalKeyRange() = keyRange;
2535 }
2536 else {
2537 params.optionalKeyRange() = mozilla::void_t();
2538 }
2540 aParams = params;
2541 return NS_OK;
2542 }
2544 AsyncConnectionHelper::ChildProcessSendResult
2545 CountHelper::SendResponseToChildProcess(nsresult aResultCode)
2546 {
2547 NS_ASSERTION(NS_IsMainThread(), "Wrong thread!");
2548 NS_ASSERTION(IndexedDatabaseManager::IsMainProcess(), "Wrong process!");
2550 PROFILER_MAIN_THREAD_LABEL("IndexedDB",
2551 "CountHelper::SendResponseToChildProcess "
2552 "[IDBIndex.cpp]");
2554 IndexedDBRequestParentBase* actor = mRequest->GetActorParent();
2555 NS_ASSERTION(actor, "How did we get this far without an actor?");
2557 ResponseValue response;
2558 if (NS_FAILED(aResultCode)) {
2559 response = aResultCode;
2560 }
2561 else {
2562 CountResponse countResponse = mCount;
2563 response = countResponse;
2564 }
2566 if (!actor->SendResponse(response)) {
2567 return Error;
2568 }
2570 return Success_Sent;
2571 }
2573 nsresult
2574 CountHelper::UnpackResponseFromParentProcess(
2575 const ResponseValue& aResponseValue)
2576 {
2577 NS_ASSERTION(aResponseValue.type() == ResponseValue::TCountResponse,
2578 "Bad response type!");
2580 mCount = aResponseValue.get_CountResponse().count();
2581 return NS_OK;
2582 }