2 * Copyright (C) 2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
29 #if ENABLE(INDEXED_DATABASE)
31 #include "IDBBindingUtilities.h"
32 #include "IDBCursor.h"
33 #include "IDBDatabase.h"
34 #include "IDBKeyRangeData.h"
35 #include "IDBObjectStore.h"
36 #include "IDBRequest.h"
37 #include "IDBTransaction.h"
39 #include <JavaScriptCore/HeapInlines.h>
44 IDBIndex::IDBIndex(ScriptExecutionContext& context, const IDBIndexInfo& info, IDBObjectStore& objectStore)
45 : ActiveDOMObject(&context)
47 , m_originalInfo(info)
48 , m_objectStore(objectStore)
50 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
57 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
60 const char* IDBIndex::activeDOMObjectName() const
65 bool IDBIndex::canSuspendForDocumentSuspension() const
70 bool IDBIndex::hasPendingActivity() const
72 return m_objectStore.transaction().hasPendingActivity();
75 const String& IDBIndex::name() const
77 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
81 ExceptionOr<void> IDBIndex::setName(const String& name)
83 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
86 return Exception { InvalidStateError, "Failed set property 'name' on 'IDBIndex': The index has been deleted."_s };
88 if (m_objectStore.isDeleted())
89 return Exception { InvalidStateError, "Failed set property 'name' on 'IDBIndex': The index's object store has been deleted."_s };
91 if (!m_objectStore.transaction().isVersionChange())
92 return Exception { InvalidStateError, "Failed set property 'name' on 'IDBIndex': The index's transaction is not a version change transaction."_s };
94 if (!m_objectStore.transaction().isActive())
95 return Exception { TransactionInactiveError, "Failed set property 'name' on 'IDBIndex': The index's transaction is not active."_s };
97 if (m_info.name() == name)
100 if (m_objectStore.info().hasIndex(name))
101 return Exception { ConstraintError, makeString("Failed set property 'name' on 'IDBIndex': The owning object store already has an index named '", name, "'.") };
103 m_objectStore.transaction().database().renameIndex(*this, name);
109 IDBObjectStore& IDBIndex::objectStore()
111 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
112 return m_objectStore;
115 const IDBKeyPath& IDBIndex::keyPath() const
117 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
118 return m_info.keyPath();
121 bool IDBIndex::unique() const
123 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
124 return m_info.unique();
127 bool IDBIndex::multiEntry() const
129 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
130 return m_info.multiEntry();
133 void IDBIndex::rollbackInfoForVersionChangeAbort()
135 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
137 // Only rollback to the original info if this index still exists in the rolled-back database info.
138 auto* objectStoreInfo = m_objectStore.transaction().database().info().infoForExistingObjectStore(m_objectStore.info().identifier());
139 if (!objectStoreInfo)
142 if (!objectStoreInfo->hasIndex(m_info.identifier())) {
147 m_info = m_originalInfo;
151 ExceptionOr<Ref<IDBRequest>> IDBIndex::openCursor(ExecState& execState, IDBKeyRange* range, IDBCursorDirection direction)
153 LOG(IndexedDB, "IDBIndex::openCursor");
154 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
156 if (m_deleted || m_objectStore.isDeleted())
157 return Exception { InvalidStateError, "Failed to execute 'openCursor' on 'IDBIndex': The index or its object store has been deleted."_s };
159 if (!m_objectStore.transaction().isActive())
160 return Exception { TransactionInactiveError, "Failed to execute 'openCursor' on 'IDBIndex': The transaction is inactive or finished."_s };
162 IDBKeyRangeData rangeData = range;
163 if (rangeData.lowerKey.isNull())
164 rangeData.lowerKey = IDBKeyData::minimum();
165 if (rangeData.upperKey.isNull())
166 rangeData.upperKey = IDBKeyData::maximum();
168 auto info = IDBCursorInfo::indexCursor(m_objectStore.transaction(), m_objectStore.info().identifier(), m_info.identifier(), rangeData, direction, IndexedDB::CursorType::KeyAndValue);
169 return m_objectStore.transaction().requestOpenCursor(execState, *this, info);
172 ExceptionOr<Ref<IDBRequest>> IDBIndex::openCursor(ExecState& execState, JSValue key, IDBCursorDirection direction)
174 LOG(IndexedDB, "IDBIndex::openCursor");
175 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
177 auto keyRange = IDBKeyRange::only(execState, key);
178 if (keyRange.hasException())
179 return Exception { DataError, "Failed to execute 'openCursor' on 'IDBIndex': The parameter is not a valid key."_s };
181 return openCursor(execState, keyRange.releaseReturnValue().ptr(), direction);
184 ExceptionOr<Ref<IDBRequest>> IDBIndex::openKeyCursor(ExecState& execState, IDBKeyRange* range, IDBCursorDirection direction)
186 LOG(IndexedDB, "IDBIndex::openKeyCursor");
187 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
189 if (m_deleted || m_objectStore.isDeleted())
190 return Exception { InvalidStateError, "Failed to execute 'openKeyCursor' on 'IDBIndex': The index or its object store has been deleted."_s };
192 if (!m_objectStore.transaction().isActive())
193 return Exception { TransactionInactiveError, "Failed to execute 'openKeyCursor' on 'IDBIndex': The transaction is inactive or finished."_s };
195 auto info = IDBCursorInfo::indexCursor(m_objectStore.transaction(), m_objectStore.info().identifier(), m_info.identifier(), range, direction, IndexedDB::CursorType::KeyOnly);
196 return m_objectStore.transaction().requestOpenCursor(execState, *this, info);
199 ExceptionOr<Ref<IDBRequest>> IDBIndex::openKeyCursor(ExecState& execState, JSValue key, IDBCursorDirection direction)
201 LOG(IndexedDB, "IDBIndex::openKeyCursor");
203 auto keyRange = IDBKeyRange::only(execState, key);
204 if (keyRange.hasException())
205 return Exception { DataError, "Failed to execute 'openKeyCursor' on 'IDBIndex': The parameter is not a valid key."_s };
206 return openKeyCursor(execState, keyRange.releaseReturnValue().ptr(), direction);
209 ExceptionOr<Ref<IDBRequest>> IDBIndex::count(ExecState& execState, IDBKeyRange* range)
211 LOG(IndexedDB, "IDBIndex::count");
213 return doCount(execState, range ? IDBKeyRangeData(range) : IDBKeyRangeData::allKeys());
216 ExceptionOr<Ref<IDBRequest>> IDBIndex::count(ExecState& execState, JSValue key)
218 LOG(IndexedDB, "IDBIndex::count");
220 auto idbKey = scriptValueToIDBKey(execState, key);
221 if (!idbKey->isValid())
222 return Exception { DataError, "Failed to execute 'count' on 'IDBIndex': The parameter is not a valid key."_s };
224 return doCount(execState, IDBKeyRangeData(idbKey.ptr()));
227 ExceptionOr<Ref<IDBRequest>> IDBIndex::doCount(ExecState& execState, const IDBKeyRangeData& range)
229 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
231 if (m_deleted || m_objectStore.isDeleted())
232 return Exception { InvalidStateError, "Failed to execute 'count' on 'IDBIndex': The index or its object store has been deleted."_s };
234 if (!range.isValid())
235 return Exception { DataError };
237 auto& transaction = m_objectStore.transaction();
238 if (!transaction.isActive())
239 return Exception { TransactionInactiveError, "Failed to execute 'count' on 'IDBIndex': The transaction is inactive or finished."_s };
241 return transaction.requestCount(execState, *this, range);
244 ExceptionOr<Ref<IDBRequest>> IDBIndex::get(ExecState& execState, IDBKeyRange* range)
246 LOG(IndexedDB, "IDBIndex::get");
248 return doGet(execState, IDBKeyRangeData(range));
251 ExceptionOr<Ref<IDBRequest>> IDBIndex::get(ExecState& execState, JSValue key)
253 LOG(IndexedDB, "IDBIndex::get");
255 auto idbKey = scriptValueToIDBKey(execState, key);
256 if (!idbKey->isValid())
257 return Exception { DataError, "Failed to execute 'get' on 'IDBIndex': The parameter is not a valid key."_s };
259 return doGet(execState, IDBKeyRangeData(idbKey.ptr()));
262 ExceptionOr<Ref<IDBRequest>> IDBIndex::doGet(ExecState& execState, const IDBKeyRangeData& range)
264 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
266 if (m_deleted || m_objectStore.isDeleted())
267 return Exception { InvalidStateError, "Failed to execute 'get' on 'IDBIndex': The index or its object store has been deleted."_s };
270 return Exception { DataError };
272 auto& transaction = m_objectStore.transaction();
273 if (!transaction.isActive())
274 return Exception { TransactionInactiveError, "Failed to execute 'get' on 'IDBIndex': The transaction is inactive or finished."_s };
276 return transaction.requestGetValue(execState, *this, range);
279 ExceptionOr<Ref<IDBRequest>> IDBIndex::getKey(ExecState& execState, IDBKeyRange* range)
281 LOG(IndexedDB, "IDBIndex::getKey");
283 return doGetKey(execState, IDBKeyRangeData(range));
286 ExceptionOr<Ref<IDBRequest>> IDBIndex::getKey(ExecState& execState, JSValue key)
288 LOG(IndexedDB, "IDBIndex::getKey");
290 auto idbKey = scriptValueToIDBKey(execState, key);
291 if (!idbKey->isValid())
292 return Exception { DataError, "Failed to execute 'getKey' on 'IDBIndex': The parameter is not a valid key."_s };
294 return doGetKey(execState, IDBKeyRangeData(idbKey.ptr()));
297 ExceptionOr<Ref<IDBRequest>> IDBIndex::doGetKey(ExecState& execState, const IDBKeyRangeData& range)
299 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
301 if (m_deleted || m_objectStore.isDeleted())
302 return Exception { InvalidStateError, "Failed to execute 'getKey' on 'IDBIndex': The index or its object store has been deleted."_s };
305 return Exception { DataError };
307 auto& transaction = m_objectStore.transaction();
308 if (!transaction.isActive())
309 return Exception { TransactionInactiveError, "Failed to execute 'getKey' on 'IDBIndex': The transaction is inactive or finished."_s };
311 return transaction.requestGetKey(execState, *this, range);
314 ExceptionOr<Ref<IDBRequest>> IDBIndex::getAll(ExecState& execState, RefPtr<IDBKeyRange> range, Optional<uint32_t> count)
316 LOG(IndexedDB, "IDBIndex::getAll");
317 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
319 if (m_deleted || m_objectStore.isDeleted())
320 return Exception { InvalidStateError, "Failed to execute 'getAll' on 'IDBIndex': The index or its object store has been deleted."_s };
322 if (!m_objectStore.transaction().isActive())
323 return Exception { TransactionInactiveError, "Failed to execute 'getAll' on 'IDBIndex': The transaction is inactive or finished."_s };
325 return m_objectStore.transaction().requestGetAllIndexRecords(execState, *this, range.get(), IndexedDB::GetAllType::Values, count);
328 ExceptionOr<Ref<IDBRequest>> IDBIndex::getAll(ExecState& execState, JSValue key, Optional<uint32_t> count)
330 auto onlyResult = IDBKeyRange::only(execState, key);
331 if (onlyResult.hasException())
332 return Exception { DataError, "Failed to execute 'getAll' on 'IDBIndex': The parameter is not a valid key."_s };
334 return getAll(execState, onlyResult.releaseReturnValue(), count);
337 ExceptionOr<Ref<IDBRequest>> IDBIndex::getAllKeys(ExecState& execState, RefPtr<IDBKeyRange> range, Optional<uint32_t> count)
339 LOG(IndexedDB, "IDBIndex::getAllKeys");
340 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
342 if (m_deleted || m_objectStore.isDeleted())
343 return Exception { InvalidStateError, "Failed to execute 'getAllKeys' on 'IDBIndex': The index or its object store has been deleted."_s };
345 if (!m_objectStore.transaction().isActive())
346 return Exception { TransactionInactiveError, "Failed to execute 'getAllKeys' on 'IDBIndex': The transaction is inactive or finished."_s };
348 return m_objectStore.transaction().requestGetAllIndexRecords(execState, *this, range.get(), IndexedDB::GetAllType::Keys, count);
351 ExceptionOr<Ref<IDBRequest>> IDBIndex::getAllKeys(ExecState& execState, JSValue key, Optional<uint32_t> count)
353 auto onlyResult = IDBKeyRange::only(execState, key);
354 if (onlyResult.hasException())
355 return Exception { DataError, "Failed to execute 'getAllKeys' on 'IDBIndex': The parameter is not a valid key."_s };
357 return getAllKeys(execState, onlyResult.releaseReturnValue(), count);
360 void IDBIndex::markAsDeleted()
362 ASSERT(&m_objectStore.transaction().database().originThread() == &Thread::current());
373 void IDBIndex::deref()
375 m_objectStore.deref();
378 } // namespace WebCore
380 #endif // ENABLE(INDEXED_DATABASE)