/src/mozilla-central/dom/indexedDB/IDBIndex.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ |
2 | | /* vim: set ts=8 sts=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 "IDBIndex.h" |
8 | | |
9 | | #include "FileInfo.h" |
10 | | #include "IDBCursor.h" |
11 | | #include "IDBEvents.h" |
12 | | #include "IDBKeyRange.h" |
13 | | #include "IDBObjectStore.h" |
14 | | #include "IDBRequest.h" |
15 | | #include "IDBTransaction.h" |
16 | | #include "IndexedDatabase.h" |
17 | | #include "IndexedDatabaseInlines.h" |
18 | | #include "mozilla/ErrorResult.h" |
19 | | #include "mozilla/dom/indexedDB/PBackgroundIDBSharedTypes.h" |
20 | | #include "ProfilerHelpers.h" |
21 | | #include "ReportInternalError.h" |
22 | | |
23 | | // Include this last to avoid path problems on Windows. |
24 | | #include "ActorsChild.h" |
25 | | |
26 | | namespace mozilla { |
27 | | namespace dom { |
28 | | |
29 | | using namespace mozilla::dom::indexedDB; |
30 | | |
31 | | namespace { |
32 | | |
33 | | already_AddRefed<IDBRequest> |
34 | | GenerateRequest(JSContext* aCx, IDBIndex* aIndex) |
35 | 0 | { |
36 | 0 | MOZ_ASSERT(aIndex); |
37 | 0 | aIndex->AssertIsOnOwningThread(); |
38 | 0 |
|
39 | 0 | IDBTransaction* transaction = aIndex->ObjectStore()->Transaction(); |
40 | 0 |
|
41 | 0 | RefPtr<IDBRequest> request = |
42 | 0 | IDBRequest::Create(aCx, aIndex, transaction->Database(), transaction); |
43 | 0 | MOZ_ASSERT(request); |
44 | 0 |
|
45 | 0 | return request.forget(); |
46 | 0 | } |
47 | | |
48 | | } // namespace |
49 | | |
50 | | IDBIndex::IDBIndex(IDBObjectStore* aObjectStore, const IndexMetadata* aMetadata) |
51 | | : mObjectStore(aObjectStore) |
52 | | , mCachedKeyPath(JS::UndefinedValue()) |
53 | | , mMetadata(aMetadata) |
54 | | , mId(aMetadata->id()) |
55 | | , mRooted(false) |
56 | 0 | { |
57 | 0 | MOZ_ASSERT(aObjectStore); |
58 | 0 | aObjectStore->AssertIsOnOwningThread(); |
59 | 0 | MOZ_ASSERT(aMetadata); |
60 | 0 | } |
61 | | |
62 | | IDBIndex::~IDBIndex() |
63 | 0 | { |
64 | 0 | AssertIsOnOwningThread(); |
65 | 0 |
|
66 | 0 | if (mRooted) { |
67 | 0 | mCachedKeyPath.setUndefined(); |
68 | 0 | mozilla::DropJSObjects(this); |
69 | 0 | } |
70 | 0 | } |
71 | | |
72 | | already_AddRefed<IDBIndex> |
73 | | IDBIndex::Create(IDBObjectStore* aObjectStore, |
74 | | const IndexMetadata& aMetadata) |
75 | 0 | { |
76 | 0 | MOZ_ASSERT(aObjectStore); |
77 | 0 | aObjectStore->AssertIsOnOwningThread(); |
78 | 0 |
|
79 | 0 | RefPtr<IDBIndex> index = new IDBIndex(aObjectStore, &aMetadata); |
80 | 0 |
|
81 | 0 | return index.forget(); |
82 | 0 | } |
83 | | |
84 | | #ifdef DEBUG |
85 | | |
86 | | void |
87 | | IDBIndex::AssertIsOnOwningThread() const |
88 | | { |
89 | | MOZ_ASSERT(mObjectStore); |
90 | | mObjectStore->AssertIsOnOwningThread(); |
91 | | } |
92 | | |
93 | | #endif // DEBUG |
94 | | |
95 | | void |
96 | | IDBIndex::RefreshMetadata(bool aMayDelete) |
97 | 0 | { |
98 | 0 | AssertIsOnOwningThread(); |
99 | 0 | MOZ_ASSERT_IF(mDeletedMetadata, mMetadata == mDeletedMetadata); |
100 | 0 |
|
101 | 0 | const nsTArray<IndexMetadata>& indexes = mObjectStore->Spec().indexes(); |
102 | 0 |
|
103 | 0 | bool found = false; |
104 | 0 |
|
105 | 0 | for (uint32_t count = indexes.Length(), index = 0; |
106 | 0 | index < count; |
107 | 0 | index++) { |
108 | 0 | const IndexMetadata& metadata = indexes[index]; |
109 | 0 |
|
110 | 0 | if (metadata.id() == Id()) { |
111 | 0 | mMetadata = &metadata; |
112 | 0 |
|
113 | 0 | found = true; |
114 | 0 | break; |
115 | 0 | } |
116 | 0 | } |
117 | 0 |
|
118 | 0 | MOZ_ASSERT_IF(!aMayDelete && !mDeletedMetadata, found); |
119 | 0 |
|
120 | 0 | if (found) { |
121 | 0 | MOZ_ASSERT(mMetadata != mDeletedMetadata); |
122 | 0 | mDeletedMetadata = nullptr; |
123 | 0 | } else { |
124 | 0 | NoteDeletion(); |
125 | 0 | } |
126 | 0 | } |
127 | | |
128 | | void |
129 | | IDBIndex::NoteDeletion() |
130 | 0 | { |
131 | 0 | AssertIsOnOwningThread(); |
132 | 0 | MOZ_ASSERT(mMetadata); |
133 | 0 | MOZ_ASSERT(Id() == mMetadata->id()); |
134 | 0 |
|
135 | 0 | if (mDeletedMetadata) { |
136 | 0 | MOZ_ASSERT(mMetadata == mDeletedMetadata); |
137 | 0 | return; |
138 | 0 | } |
139 | 0 |
|
140 | 0 | mDeletedMetadata = new IndexMetadata(*mMetadata); |
141 | 0 |
|
142 | 0 | mMetadata = mDeletedMetadata; |
143 | 0 | } |
144 | | |
145 | | const nsString& |
146 | | IDBIndex::Name() const |
147 | 0 | { |
148 | 0 | AssertIsOnOwningThread(); |
149 | 0 | MOZ_ASSERT(mMetadata); |
150 | 0 |
|
151 | 0 | return mMetadata->name(); |
152 | 0 | } |
153 | | |
154 | | void |
155 | | IDBIndex::SetName(const nsAString& aName, ErrorResult& aRv) |
156 | 0 | { |
157 | 0 | AssertIsOnOwningThread(); |
158 | 0 |
|
159 | 0 | IDBTransaction* transaction = mObjectStore->Transaction(); |
160 | 0 |
|
161 | 0 | if (transaction->GetMode() != IDBTransaction::VERSION_CHANGE || |
162 | 0 | mDeletedMetadata) { |
163 | 0 | aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR); |
164 | 0 | return; |
165 | 0 | } |
166 | 0 | |
167 | 0 | if (!transaction->IsOpen()) { |
168 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
169 | 0 | return; |
170 | 0 | } |
171 | 0 | |
172 | 0 | if (aName == mMetadata->name()) { |
173 | 0 | return; |
174 | 0 | } |
175 | 0 | |
176 | 0 | // Cache logging string of this index before renaming. |
177 | 0 | const LoggingString loggingOldIndex(this); |
178 | 0 |
|
179 | 0 | const int64_t indexId = Id(); |
180 | 0 |
|
181 | 0 | nsresult rv = |
182 | 0 | transaction->Database()->RenameIndex(mObjectStore->Id(), |
183 | 0 | indexId, |
184 | 0 | aName); |
185 | 0 |
|
186 | 0 | if (NS_FAILED(rv)) { |
187 | 0 | aRv.Throw(rv); |
188 | 0 | return; |
189 | 0 | } |
190 | 0 | |
191 | 0 | // Don't do this in the macro because we always need to increment the serial |
192 | 0 | // number to keep in sync with the parent. |
193 | 0 | const uint64_t requestSerialNumber = IDBRequest::NextSerialNumber(); |
194 | 0 |
|
195 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " |
196 | 0 | "database(%s).transaction(%s).objectStore(%s).index(%s)." |
197 | 0 | "rename(%s)", |
198 | 0 | "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.rename()", |
199 | 0 | IDB_LOG_ID_STRING(), |
200 | 0 | transaction->LoggingSerialNumber(), |
201 | 0 | requestSerialNumber, |
202 | 0 | IDB_LOG_STRINGIFY(transaction->Database()), |
203 | 0 | IDB_LOG_STRINGIFY(transaction), |
204 | 0 | IDB_LOG_STRINGIFY(mObjectStore), |
205 | 0 | loggingOldIndex.get(), |
206 | 0 | IDB_LOG_STRINGIFY(this)); |
207 | 0 |
|
208 | 0 | transaction->RenameIndex(mObjectStore, indexId, aName); |
209 | 0 | } |
210 | | |
211 | | bool |
212 | | IDBIndex::Unique() const |
213 | 0 | { |
214 | 0 | AssertIsOnOwningThread(); |
215 | 0 | MOZ_ASSERT(mMetadata); |
216 | 0 |
|
217 | 0 | return mMetadata->unique(); |
218 | 0 | } |
219 | | |
220 | | bool |
221 | | IDBIndex::MultiEntry() const |
222 | 0 | { |
223 | 0 | AssertIsOnOwningThread(); |
224 | 0 | MOZ_ASSERT(mMetadata); |
225 | 0 |
|
226 | 0 | return mMetadata->multiEntry(); |
227 | 0 | } |
228 | | |
229 | | bool |
230 | | IDBIndex::LocaleAware() const |
231 | 0 | { |
232 | 0 | AssertIsOnOwningThread(); |
233 | 0 | MOZ_ASSERT(mMetadata); |
234 | 0 |
|
235 | 0 | return mMetadata->locale().IsEmpty(); |
236 | 0 | } |
237 | | |
238 | | const indexedDB::KeyPath& |
239 | | IDBIndex::GetKeyPath() const |
240 | 0 | { |
241 | 0 | AssertIsOnOwningThread(); |
242 | 0 | MOZ_ASSERT(mMetadata); |
243 | 0 |
|
244 | 0 | return mMetadata->keyPath(); |
245 | 0 | } |
246 | | |
247 | | void |
248 | | IDBIndex::GetLocale(nsString& aLocale) const |
249 | 0 | { |
250 | 0 | AssertIsOnOwningThread(); |
251 | 0 | MOZ_ASSERT(mMetadata); |
252 | 0 |
|
253 | 0 | if (mMetadata->locale().IsEmpty()) { |
254 | 0 | SetDOMStringToNull(aLocale); |
255 | 0 | } else { |
256 | 0 | CopyASCIItoUTF16(mMetadata->locale(), aLocale); |
257 | 0 | } |
258 | 0 | } |
259 | | |
260 | | const nsCString& |
261 | | IDBIndex::Locale() const |
262 | 0 | { |
263 | 0 | AssertIsOnOwningThread(); |
264 | 0 | MOZ_ASSERT(mMetadata); |
265 | 0 |
|
266 | 0 | return mMetadata->locale(); |
267 | 0 | } |
268 | | |
269 | | bool |
270 | | IDBIndex::IsAutoLocale() const |
271 | 0 | { |
272 | 0 | AssertIsOnOwningThread(); |
273 | 0 | MOZ_ASSERT(mMetadata); |
274 | 0 |
|
275 | 0 | return mMetadata->autoLocale(); |
276 | 0 | } |
277 | | |
278 | | nsPIDOMWindowInner* |
279 | | IDBIndex::GetParentObject() const |
280 | 0 | { |
281 | 0 | AssertIsOnOwningThread(); |
282 | 0 |
|
283 | 0 | return mObjectStore->GetParentObject(); |
284 | 0 | } |
285 | | |
286 | | void |
287 | | IDBIndex::GetKeyPath(JSContext* aCx, |
288 | | JS::MutableHandle<JS::Value> aResult, |
289 | | ErrorResult& aRv) |
290 | 0 | { |
291 | 0 | AssertIsOnOwningThread(); |
292 | 0 |
|
293 | 0 | if (!mCachedKeyPath.isUndefined()) { |
294 | 0 | MOZ_ASSERT(mRooted); |
295 | 0 | aResult.set(mCachedKeyPath); |
296 | 0 | return; |
297 | 0 | } |
298 | 0 |
|
299 | 0 | MOZ_ASSERT(!mRooted); |
300 | 0 |
|
301 | 0 | aRv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath); |
302 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
303 | 0 | return; |
304 | 0 | } |
305 | 0 | |
306 | 0 | if (mCachedKeyPath.isGCThing()) { |
307 | 0 | mozilla::HoldJSObjects(this); |
308 | 0 | mRooted = true; |
309 | 0 | } |
310 | 0 |
|
311 | 0 | aResult.set(mCachedKeyPath); |
312 | 0 | } |
313 | | |
314 | | already_AddRefed<IDBRequest> |
315 | | IDBIndex::GetInternal(bool aKeyOnly, |
316 | | JSContext* aCx, |
317 | | JS::Handle<JS::Value> aKey, |
318 | | ErrorResult& aRv) |
319 | 0 | { |
320 | 0 | AssertIsOnOwningThread(); |
321 | 0 |
|
322 | 0 | if (mDeletedMetadata) { |
323 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); |
324 | 0 | return nullptr; |
325 | 0 | } |
326 | 0 | |
327 | 0 | IDBTransaction* transaction = mObjectStore->Transaction(); |
328 | 0 | if (!transaction->IsOpen()) { |
329 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
330 | 0 | return nullptr; |
331 | 0 | } |
332 | 0 | |
333 | 0 | RefPtr<IDBKeyRange> keyRange; |
334 | 0 | aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); |
335 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
336 | 0 | return nullptr; |
337 | 0 | } |
338 | 0 | |
339 | 0 | if (!keyRange) { |
340 | 0 | // Must specify a key or keyRange for get() and getKey(). |
341 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_KEY_ERR); |
342 | 0 | return nullptr; |
343 | 0 | } |
344 | 0 | |
345 | 0 | const int64_t objectStoreId = mObjectStore->Id(); |
346 | 0 | const int64_t indexId = Id(); |
347 | 0 |
|
348 | 0 | SerializedKeyRange serializedKeyRange; |
349 | 0 | keyRange->ToSerialized(serializedKeyRange); |
350 | 0 |
|
351 | 0 | RequestParams params; |
352 | 0 |
|
353 | 0 | if (aKeyOnly) { |
354 | 0 | params = IndexGetKeyParams(objectStoreId, indexId, serializedKeyRange); |
355 | 0 | } else { |
356 | 0 | params = IndexGetParams(objectStoreId, indexId, serializedKeyRange); |
357 | 0 | } |
358 | 0 |
|
359 | 0 | RefPtr<IDBRequest> request = GenerateRequest(aCx, this); |
360 | 0 | MOZ_ASSERT(request); |
361 | 0 |
|
362 | 0 | if (aKeyOnly) { |
363 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " |
364 | 0 | "database(%s).transaction(%s).objectStore(%s).index(%s)." |
365 | 0 | "getKey(%s)", |
366 | 0 | "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getKey()", |
367 | 0 | IDB_LOG_ID_STRING(), |
368 | 0 | transaction->LoggingSerialNumber(), |
369 | 0 | request->LoggingSerialNumber(), |
370 | 0 | IDB_LOG_STRINGIFY(transaction->Database()), |
371 | 0 | IDB_LOG_STRINGIFY(transaction), |
372 | 0 | IDB_LOG_STRINGIFY(mObjectStore), |
373 | 0 | IDB_LOG_STRINGIFY(this), |
374 | 0 | IDB_LOG_STRINGIFY(keyRange)); |
375 | 0 | } else { |
376 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " |
377 | 0 | "database(%s).transaction(%s).objectStore(%s).index(%s)." |
378 | 0 | "get(%s)", |
379 | 0 | "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.get()", |
380 | 0 | IDB_LOG_ID_STRING(), |
381 | 0 | transaction->LoggingSerialNumber(), |
382 | 0 | request->LoggingSerialNumber(), |
383 | 0 | IDB_LOG_STRINGIFY(transaction->Database()), |
384 | 0 | IDB_LOG_STRINGIFY(transaction), |
385 | 0 | IDB_LOG_STRINGIFY(mObjectStore), |
386 | 0 | IDB_LOG_STRINGIFY(this), |
387 | 0 | IDB_LOG_STRINGIFY(keyRange)); |
388 | 0 | } |
389 | 0 |
|
390 | 0 | transaction->StartRequest(request, params); |
391 | 0 |
|
392 | 0 | return request.forget(); |
393 | 0 | } |
394 | | |
395 | | already_AddRefed<IDBRequest> |
396 | | IDBIndex::GetAllInternal(bool aKeysOnly, |
397 | | JSContext* aCx, |
398 | | JS::Handle<JS::Value> aKey, |
399 | | const Optional<uint32_t>& aLimit, |
400 | | ErrorResult& aRv) |
401 | 0 | { |
402 | 0 | AssertIsOnOwningThread(); |
403 | 0 |
|
404 | 0 | if (mDeletedMetadata) { |
405 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); |
406 | 0 | return nullptr; |
407 | 0 | } |
408 | 0 | |
409 | 0 | IDBTransaction* transaction = mObjectStore->Transaction(); |
410 | 0 | if (!transaction->IsOpen()) { |
411 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
412 | 0 | return nullptr; |
413 | 0 | } |
414 | 0 | |
415 | 0 | RefPtr<IDBKeyRange> keyRange; |
416 | 0 | aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); |
417 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
418 | 0 | return nullptr; |
419 | 0 | } |
420 | 0 | |
421 | 0 | const int64_t objectStoreId = mObjectStore->Id(); |
422 | 0 | const int64_t indexId = Id(); |
423 | 0 |
|
424 | 0 | OptionalKeyRange optionalKeyRange; |
425 | 0 | if (keyRange) { |
426 | 0 | SerializedKeyRange serializedKeyRange; |
427 | 0 | keyRange->ToSerialized(serializedKeyRange); |
428 | 0 | optionalKeyRange = serializedKeyRange; |
429 | 0 | } else { |
430 | 0 | optionalKeyRange = void_t(); |
431 | 0 | } |
432 | 0 |
|
433 | 0 | const uint32_t limit = aLimit.WasPassed() ? aLimit.Value() : 0; |
434 | 0 |
|
435 | 0 | RequestParams params; |
436 | 0 | if (aKeysOnly) { |
437 | 0 | params = IndexGetAllKeysParams(objectStoreId, indexId, optionalKeyRange, |
438 | 0 | limit); |
439 | 0 | } else { |
440 | 0 | params = IndexGetAllParams(objectStoreId, indexId, optionalKeyRange, limit); |
441 | 0 | } |
442 | 0 |
|
443 | 0 | RefPtr<IDBRequest> request = GenerateRequest(aCx, this); |
444 | 0 | MOZ_ASSERT(request); |
445 | 0 |
|
446 | 0 | if (aKeysOnly) { |
447 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " |
448 | 0 | "database(%s).transaction(%s).objectStore(%s).index(%s)." |
449 | 0 | "getAllKeys(%s, %s)", |
450 | 0 | "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAllKeys()", |
451 | 0 | IDB_LOG_ID_STRING(), |
452 | 0 | transaction->LoggingSerialNumber(), |
453 | 0 | request->LoggingSerialNumber(), |
454 | 0 | IDB_LOG_STRINGIFY(transaction->Database()), |
455 | 0 | IDB_LOG_STRINGIFY(transaction), |
456 | 0 | IDB_LOG_STRINGIFY(mObjectStore), |
457 | 0 | IDB_LOG_STRINGIFY(this), |
458 | 0 | IDB_LOG_STRINGIFY(keyRange), |
459 | 0 | IDB_LOG_STRINGIFY(aLimit)); |
460 | 0 | } else { |
461 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " |
462 | 0 | "database(%s).transaction(%s).objectStore(%s).index(%s)." |
463 | 0 | "getAll(%s, %s)", |
464 | 0 | "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.getAll()", |
465 | 0 | IDB_LOG_ID_STRING(), |
466 | 0 | transaction->LoggingSerialNumber(), |
467 | 0 | request->LoggingSerialNumber(), |
468 | 0 | IDB_LOG_STRINGIFY(transaction->Database()), |
469 | 0 | IDB_LOG_STRINGIFY(transaction), |
470 | 0 | IDB_LOG_STRINGIFY(mObjectStore), |
471 | 0 | IDB_LOG_STRINGIFY(this), |
472 | 0 | IDB_LOG_STRINGIFY(keyRange), |
473 | 0 | IDB_LOG_STRINGIFY(aLimit)); |
474 | 0 | } |
475 | 0 |
|
476 | 0 | transaction->StartRequest(request, params); |
477 | 0 |
|
478 | 0 | return request.forget(); |
479 | 0 | } |
480 | | |
481 | | already_AddRefed<IDBRequest> |
482 | | IDBIndex::OpenCursorInternal(bool aKeysOnly, |
483 | | JSContext* aCx, |
484 | | JS::Handle<JS::Value> aRange, |
485 | | IDBCursorDirection aDirection, |
486 | | ErrorResult& aRv) |
487 | 0 | { |
488 | 0 | AssertIsOnOwningThread(); |
489 | 0 |
|
490 | 0 | if (mDeletedMetadata) { |
491 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); |
492 | 0 | return nullptr; |
493 | 0 | } |
494 | 0 | |
495 | 0 | IDBTransaction* transaction = mObjectStore->Transaction(); |
496 | 0 | if (!transaction->IsOpen()) { |
497 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
498 | 0 | return nullptr; |
499 | 0 | } |
500 | 0 | |
501 | 0 | RefPtr<IDBKeyRange> keyRange; |
502 | 0 | aRv = IDBKeyRange::FromJSVal(aCx, aRange, getter_AddRefs(keyRange)); |
503 | 0 | if (NS_WARN_IF(aRv.Failed())) { |
504 | 0 | return nullptr; |
505 | 0 | } |
506 | 0 | |
507 | 0 | int64_t objectStoreId = mObjectStore->Id(); |
508 | 0 | int64_t indexId = Id(); |
509 | 0 |
|
510 | 0 | OptionalKeyRange optionalKeyRange; |
511 | 0 |
|
512 | 0 | if (keyRange) { |
513 | 0 | SerializedKeyRange serializedKeyRange; |
514 | 0 | keyRange->ToSerialized(serializedKeyRange); |
515 | 0 |
|
516 | 0 | optionalKeyRange = std::move(serializedKeyRange); |
517 | 0 | } else { |
518 | 0 | optionalKeyRange = void_t(); |
519 | 0 | } |
520 | 0 |
|
521 | 0 | IDBCursor::Direction direction = IDBCursor::ConvertDirection(aDirection); |
522 | 0 |
|
523 | 0 | OpenCursorParams params; |
524 | 0 | if (aKeysOnly) { |
525 | 0 | IndexOpenKeyCursorParams openParams; |
526 | 0 | openParams.objectStoreId() = objectStoreId; |
527 | 0 | openParams.indexId() = indexId; |
528 | 0 | openParams.optionalKeyRange() = std::move(optionalKeyRange); |
529 | 0 | openParams.direction() = direction; |
530 | 0 |
|
531 | 0 | params = std::move(openParams); |
532 | 0 | } else { |
533 | 0 | IndexOpenCursorParams openParams; |
534 | 0 | openParams.objectStoreId() = objectStoreId; |
535 | 0 | openParams.indexId() = indexId; |
536 | 0 | openParams.optionalKeyRange() = std::move(optionalKeyRange); |
537 | 0 | openParams.direction() = direction; |
538 | 0 |
|
539 | 0 | params = std::move(openParams); |
540 | 0 | } |
541 | 0 |
|
542 | 0 | RefPtr<IDBRequest> request = GenerateRequest(aCx, this); |
543 | 0 | MOZ_ASSERT(request); |
544 | 0 |
|
545 | 0 | if (aKeysOnly) { |
546 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " |
547 | 0 | "database(%s).transaction(%s).objectStore(%s).index(%s)." |
548 | 0 | "openKeyCursor(%s, %s)", |
549 | 0 | "IndexedDB %s: C T[%lld] R[%llu]: IDBIndex.openKeyCursor()", |
550 | 0 | IDB_LOG_ID_STRING(), |
551 | 0 | transaction->LoggingSerialNumber(), |
552 | 0 | request->LoggingSerialNumber(), |
553 | 0 | IDB_LOG_STRINGIFY(transaction->Database()), |
554 | 0 | IDB_LOG_STRINGIFY(transaction), |
555 | 0 | IDB_LOG_STRINGIFY(mObjectStore), |
556 | 0 | IDB_LOG_STRINGIFY(this), |
557 | 0 | IDB_LOG_STRINGIFY(keyRange), |
558 | 0 | IDB_LOG_STRINGIFY(direction)); |
559 | 0 | } else { |
560 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " |
561 | 0 | "database(%s).transaction(%s).objectStore(%s).index(%s)." |
562 | 0 | "openCursor(%s, %s)", |
563 | 0 | "IndexedDB %s: C T[%lld] R[%llu]: " |
564 | 0 | "IDBObjectStore.openKeyCursor()", |
565 | 0 | IDB_LOG_ID_STRING(), |
566 | 0 | transaction->LoggingSerialNumber(), |
567 | 0 | request->LoggingSerialNumber(), |
568 | 0 | IDB_LOG_STRINGIFY(transaction->Database()), |
569 | 0 | IDB_LOG_STRINGIFY(transaction), |
570 | 0 | IDB_LOG_STRINGIFY(mObjectStore), |
571 | 0 | IDB_LOG_STRINGIFY(this), |
572 | 0 | IDB_LOG_STRINGIFY(keyRange), |
573 | 0 | IDB_LOG_STRINGIFY(direction)); |
574 | 0 | } |
575 | 0 |
|
576 | 0 | BackgroundCursorChild* actor = |
577 | 0 | new BackgroundCursorChild(request, this, direction); |
578 | 0 |
|
579 | 0 | mObjectStore->Transaction()->OpenCursor(actor, params); |
580 | 0 |
|
581 | 0 | return request.forget(); |
582 | 0 | } |
583 | | |
584 | | already_AddRefed<IDBRequest> |
585 | | IDBIndex::Count(JSContext* aCx, |
586 | | JS::Handle<JS::Value> aKey, |
587 | | ErrorResult& aRv) |
588 | 0 | { |
589 | 0 | AssertIsOnOwningThread(); |
590 | 0 |
|
591 | 0 | if (mDeletedMetadata) { |
592 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_NOT_ALLOWED_ERR); |
593 | 0 | return nullptr; |
594 | 0 | } |
595 | 0 | |
596 | 0 | IDBTransaction* transaction = mObjectStore->Transaction(); |
597 | 0 | if (!transaction->IsOpen()) { |
598 | 0 | aRv.Throw(NS_ERROR_DOM_INDEXEDDB_TRANSACTION_INACTIVE_ERR); |
599 | 0 | return nullptr; |
600 | 0 | } |
601 | 0 | |
602 | 0 | RefPtr<IDBKeyRange> keyRange; |
603 | 0 | aRv = IDBKeyRange::FromJSVal(aCx, aKey, getter_AddRefs(keyRange)); |
604 | 0 | if (aRv.Failed()) { |
605 | 0 | return nullptr; |
606 | 0 | } |
607 | 0 | |
608 | 0 | IndexCountParams params; |
609 | 0 | params.objectStoreId() = mObjectStore->Id(); |
610 | 0 | params.indexId() = Id(); |
611 | 0 |
|
612 | 0 | if (keyRange) { |
613 | 0 | SerializedKeyRange serializedKeyRange; |
614 | 0 | keyRange->ToSerialized(serializedKeyRange); |
615 | 0 | params.optionalKeyRange() = serializedKeyRange; |
616 | 0 | } else { |
617 | 0 | params.optionalKeyRange() = void_t(); |
618 | 0 | } |
619 | 0 |
|
620 | 0 | RefPtr<IDBRequest> request = GenerateRequest(aCx, this); |
621 | 0 | MOZ_ASSERT(request); |
622 | 0 |
|
623 | 0 | IDB_LOG_MARK("IndexedDB %s: Child Transaction[%lld] Request[%llu]: " |
624 | 0 | "database(%s).transaction(%s).objectStore(%s).index(%s)." |
625 | 0 | "count(%s)", |
626 | 0 | "IndexedDB %s: C T[%lld] R[%llu]: IDBObjectStore.count()", |
627 | 0 | IDB_LOG_ID_STRING(), |
628 | 0 | transaction->LoggingSerialNumber(), |
629 | 0 | request->LoggingSerialNumber(), |
630 | 0 | IDB_LOG_STRINGIFY(transaction->Database()), |
631 | 0 | IDB_LOG_STRINGIFY(transaction), |
632 | 0 | IDB_LOG_STRINGIFY(mObjectStore), |
633 | 0 | IDB_LOG_STRINGIFY(this), |
634 | 0 | IDB_LOG_STRINGIFY(keyRange)); |
635 | 0 |
|
636 | 0 | transaction->StartRequest(request, params); |
637 | 0 |
|
638 | 0 | return request.forget(); |
639 | 0 | } |
640 | | |
641 | | NS_IMPL_CYCLE_COLLECTING_ADDREF(IDBIndex) |
642 | | NS_IMPL_CYCLE_COLLECTING_RELEASE(IDBIndex) |
643 | | |
644 | 0 | NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(IDBIndex) |
645 | 0 | NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY |
646 | 0 | NS_INTERFACE_MAP_ENTRY(nsISupports) |
647 | 0 | NS_INTERFACE_MAP_END |
648 | | |
649 | | NS_IMPL_CYCLE_COLLECTION_CLASS(IDBIndex) |
650 | | |
651 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(IDBIndex) |
652 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER |
653 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mCachedKeyPath) |
654 | 0 | NS_IMPL_CYCLE_COLLECTION_TRACE_END |
655 | | |
656 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(IDBIndex) |
657 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mObjectStore) |
658 | 0 | NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END |
659 | | |
660 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(IDBIndex) |
661 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER |
662 | 0 |
|
663 | 0 | // Don't unlink mObjectStore! |
664 | 0 |
|
665 | 0 | tmp->mCachedKeyPath.setUndefined(); |
666 | 0 |
|
667 | 0 | if (tmp->mRooted) { |
668 | 0 | mozilla::DropJSObjects(tmp); |
669 | 0 | tmp->mRooted = false; |
670 | 0 | } |
671 | 0 | NS_IMPL_CYCLE_COLLECTION_UNLINK_END |
672 | | |
673 | | JSObject* |
674 | | IDBIndex::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) |
675 | 0 | { |
676 | 0 | return IDBIndex_Binding::Wrap(aCx, this, aGivenProto); |
677 | 0 | } |
678 | | |
679 | | } // namespace dom |
680 | | } // namespace mozilla |