2 * Copyright (C) 2010 Google 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
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "IDBObjectStore.h"
29 #if ENABLE(INDEXED_DATABASE)
31 #include "DOMStringList.h"
33 #include "IDBDatabase.h"
34 #include "IDBDatabaseException.h"
37 #include "IDBKeyPath.h"
38 #include "IDBKeyRange.h"
39 #include "IDBTracing.h"
40 #include "IDBTransaction.h"
41 #include "SerializedScriptValue.h"
42 #include <wtf/UnusedParam.h>
46 static const unsigned short defaultDirection = IDBCursor::NEXT;
48 IDBObjectStore::IDBObjectStore(const IDBObjectStoreMetadata& metadata, PassRefPtr<IDBObjectStoreBackendInterface> idbObjectStore, IDBTransaction* transaction)
49 : m_metadata(metadata)
50 , m_backend(idbObjectStore)
51 , m_transaction(transaction)
55 ASSERT(m_transaction);
56 // We pass a reference to this object before it can be adopted.
57 relaxAdoptionRequirement();
60 PassRefPtr<DOMStringList> IDBObjectStore::indexNames() const
62 IDB_TRACE("IDBObjectStore::indexNames");
63 RefPtr<DOMStringList> indexNames = DOMStringList::create();
64 for (IDBObjectStoreMetadata::IndexMap::const_iterator it = m_metadata.indexes.begin(); it != m_metadata.indexes.end(); ++it)
65 indexNames->append(it->first);
67 return indexNames.release();
70 PassRefPtr<IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec)
72 IDB_TRACE("IDBObjectStore::get");
74 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
78 ec = IDBDatabaseException::DATA_ERR;
81 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
82 m_backend->get(keyRange, request, m_transaction->backend(), ec);
84 request->markEarlyDeath();
87 return request.release();
90 PassRefPtr<IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
92 IDB_TRACE("IDBObjectStore::get");
93 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
96 return get(context, keyRange.release(), ec);
99 PassRefPtr<IDBRequest> IDBObjectStore::add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> key, ExceptionCode& ec)
101 IDB_TRACE("IDBObjectStore::add");
103 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
106 if (m_transaction->isReadOnly()) {
107 ec = IDBDatabaseException::READ_ONLY_ERR;
111 if (key && !key->isValid()) {
112 ec = IDBDatabaseException::DATA_ERR;
116 RefPtr<SerializedScriptValue> value = prpValue;
117 if (value->blobURLs().size() > 0) {
118 // FIXME: Add Blob/File/FileList support
119 ec = IDBDatabaseException::IDB_DATA_CLONE_ERR;
123 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
124 m_backend->put(value, key, IDBObjectStoreBackendInterface::AddOnly, request, m_transaction->backend(), ec);
126 request->markEarlyDeath();
129 return request.release();
132 PassRefPtr<IDBRequest> IDBObjectStore::put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> key, ExceptionCode& ec)
134 IDB_TRACE("IDBObjectStore::put");
136 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
139 if (m_transaction->isReadOnly()) {
140 ec = IDBDatabaseException::READ_ONLY_ERR;
144 if (key && !key->isValid()) {
145 ec = IDBDatabaseException::DATA_ERR;
149 RefPtr<SerializedScriptValue> value = prpValue;
150 if (value->blobURLs().size() > 0) {
151 // FIXME: Add Blob/File/FileList support
152 ec = IDBDatabaseException::IDB_DATA_CLONE_ERR;
156 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
157 m_backend->put(value, key, IDBObjectStoreBackendInterface::AddOrUpdate, request, m_transaction->backend(), ec);
159 request->markEarlyDeath();
162 return request.release();
165 PassRefPtr<IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec)
167 IDB_TRACE("IDBObjectStore::delete");
169 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
172 if (m_transaction->isReadOnly()) {
173 ec = IDBDatabaseException::READ_ONLY_ERR;
178 ec = IDBDatabaseException::DATA_ERR;
182 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
183 m_backend->deleteFunction(keyRange, request, m_transaction->backend(), ec);
185 request->markEarlyDeath();
188 return request.release();
191 PassRefPtr<IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
193 IDB_TRACE("IDBObjectStore::delete");
194 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
197 return deleteFunction(context, keyRange.release(), ec);
200 PassRefPtr<IDBRequest> IDBObjectStore::clear(ScriptExecutionContext* context, ExceptionCode& ec)
202 IDB_TRACE("IDBObjectStore::clear");
204 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
207 if (m_transaction->isReadOnly()) {
208 ec = IDBDatabaseException::READ_ONLY_ERR;
212 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
213 m_backend->clear(request, m_transaction->backend(), ec);
215 request->markEarlyDeath();
218 return request.release();
221 PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const String& keyPath, const Dictionary& options, ExceptionCode& ec)
223 return createIndex(name, IDBKeyPath(keyPath), options, ec);
226 PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, PassRefPtr<DOMStringList> keyPath, const Dictionary& options, ExceptionCode& ec)
228 // FIXME: Binding code for DOMString[] should not match null. http://webkit.org/b/84217
230 return createIndex(name, IDBKeyPath("null"), options, ec);
231 return createIndex(name, IDBKeyPath(*keyPath), options, ec);
235 PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const IDBKeyPath& keyPath, const Dictionary& options, ExceptionCode& ec)
237 IDB_TRACE("IDBObjectStore::createIndex");
238 if (!m_transaction->isVersionChange() || m_deleted) {
239 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
243 if (!keyPath.isValid()) {
244 ec = IDBDatabaseException::IDB_SYNTAX_ERR;
249 options.get("unique", unique);
251 bool multiEntry = false;
252 options.get("multiEntry", multiEntry);
254 if (keyPath.type() == IDBKeyPath::ArrayType && multiEntry) {
255 ec = IDBDatabaseException::IDB_NOT_SUPPORTED_ERR;
259 RefPtr<IDBIndexBackendInterface> indexBackend = m_backend->createIndex(name, keyPath, unique, multiEntry, m_transaction->backend(), ec);
260 ASSERT(!indexBackend != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa.
264 IDBIndexMetadata metadata(name, keyPath, unique, multiEntry);
265 RefPtr<IDBIndex> index = IDBIndex::create(metadata, indexBackend.release(), this, m_transaction.get());
266 m_indexMap.set(name, index);
267 m_metadata.indexes.set(name, metadata);
269 return index.release();
272 PassRefPtr<IDBIndex> IDBObjectStore::index(const String& name, ExceptionCode& ec)
274 IDB_TRACE("IDBObjectStore::index");
276 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
279 if (m_transaction->isFinished()) {
280 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
284 IDBIndexMap::iterator it = m_indexMap.find(name);
285 if (it != m_indexMap.end())
288 RefPtr<IDBIndexBackendInterface> indexBackend = m_backend->index(name, ec);
289 ASSERT(!indexBackend != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa.
293 IDBObjectStoreMetadata::IndexMap::const_iterator mdit = m_metadata.indexes.find(name);
294 ASSERT(mdit != m_metadata.indexes.end());
296 RefPtr<IDBIndex> index = IDBIndex::create(mdit->second, indexBackend.release(), this, m_transaction.get());
297 m_indexMap.set(name, index);
298 return index.release();
301 void IDBObjectStore::deleteIndex(const String& name, ExceptionCode& ec)
303 if (!m_transaction->isVersionChange() || m_deleted) {
304 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
308 m_backend->deleteIndex(name, m_transaction->backend(), ec);
310 IDBIndexMap::iterator it = m_indexMap.find(name);
311 if (it != m_indexMap.end()) {
312 it->second->markDeleted();
313 m_indexMap.remove(name);
316 ASSERT(m_metadata.indexes.contains(name));
317 m_metadata.indexes.remove(name);
321 PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, const String& directionString, ExceptionCode& ec)
323 IDB_TRACE("IDBObjectStore::openCursor");
325 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
328 unsigned short direction = IDBCursor::stringToDirection(directionString, ec);
332 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
333 request->setCursorType(IDBCursorBackendInterface::ObjectStoreCursor);
334 m_backend->openCursor(range, direction, request, m_transaction->backend(), ec);
336 request->markEarlyDeath();
339 return request.release();
342 PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, unsigned short direction, ExceptionCode& ec)
344 IDB_TRACE("IDBObjectStore::openCursor");
345 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Numeric direction values are deprecated in IDBObjectStore.openCursor. Use\"next\", \"nextunique\", \"prev\", or \"prevunique\"."));
346 context->addConsoleMessage(JSMessageSource, LogMessageType, WarningMessageLevel, consoleMessage);
347 const String& directionString = IDBCursor::directionToString(direction, ec);
350 return openCursor(context, range, directionString, ec);
353 PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, const String& direction, ExceptionCode& ec)
355 IDB_TRACE("IDBObjectStore::openCursor");
356 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
359 return openCursor(context, keyRange.release(), ec);
362 PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, unsigned short direction, ExceptionCode& ec)
364 IDB_TRACE("IDBObjectStore::openCursor");
365 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
368 return openCursor(context, keyRange.release(), direction, ec);
371 PassRefPtr<IDBRequest> IDBObjectStore::count(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, ExceptionCode& ec)
373 IDB_TRACE("IDBObjectStore::count");
375 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
378 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
379 m_backend->count(range, request, m_transaction->backend(), ec);
381 request->markEarlyDeath();
384 return request.release();
387 PassRefPtr<IDBRequest> IDBObjectStore::count(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
389 IDB_TRACE("IDBObjectStore::count");
390 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
393 return count(context, keyRange.release(), ec);
396 void IDBObjectStore::transactionFinished()
398 ASSERT(m_transaction->isFinished());
400 // Break reference cycles.
405 } // namespace WebCore
407 #endif // ENABLE(INDEXED_DATABASE)