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