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 "IDBDatabaseException.h"
36 #include "IDBKeyPath.h"
37 #include "IDBKeyRange.h"
38 #include "IDBTracing.h"
39 #include "IDBTransaction.h"
40 #include "SerializedScriptValue.h"
41 #include <wtf/UnusedParam.h>
45 static const unsigned short defaultDirection = IDBCursor::NEXT;
47 IDBObjectStore::IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface> idbObjectStore, IDBTransaction* transaction)
48 : m_backend(idbObjectStore)
49 , m_transaction(transaction)
53 ASSERT(m_transaction);
54 // We pass a reference to this object before it can be adopted.
55 relaxAdoptionRequirement();
58 String IDBObjectStore::name() const
60 IDB_TRACE("IDBObjectStore::name");
61 return m_backend->name();
64 PassRefPtr<IDBAny> IDBObjectStore::keyPath() const
66 IDB_TRACE("IDBObjectStore::keyPath");
67 return m_backend->keyPath();
70 PassRefPtr<DOMStringList> IDBObjectStore::indexNames() const
72 IDB_TRACE("IDBObjectStore::indexNames");
73 return m_backend->indexNames();
76 IDBTransaction* IDBObjectStore::transaction() const
78 IDB_TRACE("IDBObjectStore::transaction");
79 return m_transaction.get();
82 bool IDBObjectStore::autoIncrement() const
84 IDB_TRACE("IDBObjectStore::autoIncrement");
85 return m_backend->autoIncrement();
88 PassRefPtr<IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec)
90 IDB_TRACE("IDBObjectStore::get");
92 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
96 ec = IDBDatabaseException::DATA_ERR;
99 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
100 m_backend->get(keyRange, request, m_transaction->backend(), ec);
102 request->markEarlyDeath();
105 return request.release();
108 PassRefPtr<IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
110 IDB_TRACE("IDBObjectStore::get");
111 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
114 return get(context, keyRange.release(), ec);
117 PassRefPtr<IDBRequest> IDBObjectStore::add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> key, ExceptionCode& ec)
119 IDB_TRACE("IDBObjectStore::add");
121 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
124 if (m_transaction->isReadOnly()) {
125 ec = IDBDatabaseException::READ_ONLY_ERR;
129 if (key && !key->isValid()) {
130 ec = IDBDatabaseException::DATA_ERR;
134 RefPtr<SerializedScriptValue> value = prpValue;
135 if (value->blobURLs().size() > 0) {
136 // FIXME: Add Blob/File/FileList support
137 ec = IDBDatabaseException::IDB_DATA_CLONE_ERR;
141 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
142 m_backend->put(value, key, IDBObjectStoreBackendInterface::AddOnly, request, m_transaction->backend(), ec);
144 request->markEarlyDeath();
147 return request.release();
150 PassRefPtr<IDBRequest> IDBObjectStore::put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> key, ExceptionCode& ec)
152 IDB_TRACE("IDBObjectStore::put");
154 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
157 if (m_transaction->isReadOnly()) {
158 ec = IDBDatabaseException::READ_ONLY_ERR;
162 if (key && !key->isValid()) {
163 ec = IDBDatabaseException::DATA_ERR;
167 RefPtr<SerializedScriptValue> value = prpValue;
168 if (value->blobURLs().size() > 0) {
169 // FIXME: Add Blob/File/FileList support
170 ec = IDBDatabaseException::IDB_DATA_CLONE_ERR;
174 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
175 m_backend->put(value, key, IDBObjectStoreBackendInterface::AddOrUpdate, request, m_transaction->backend(), ec);
177 request->markEarlyDeath();
180 return request.release();
183 PassRefPtr<IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec)
185 IDB_TRACE("IDBObjectStore::delete");
187 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
190 if (m_transaction->isReadOnly()) {
191 ec = IDBDatabaseException::READ_ONLY_ERR;
196 ec = IDBDatabaseException::DATA_ERR;
200 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
201 m_backend->deleteFunction(keyRange, request, m_transaction->backend(), ec);
203 request->markEarlyDeath();
206 return request.release();
209 PassRefPtr<IDBRequest> IDBObjectStore::deleteFunction(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
211 IDB_TRACE("IDBObjectStore::delete");
212 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
215 return deleteFunction(context, keyRange.release(), ec);
218 PassRefPtr<IDBRequest> IDBObjectStore::clear(ScriptExecutionContext* context, ExceptionCode& ec)
220 IDB_TRACE("IDBObjectStore::clear");
222 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
225 if (m_transaction->isReadOnly()) {
226 ec = IDBDatabaseException::READ_ONLY_ERR;
230 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
231 m_backend->clear(request, m_transaction->backend(), ec);
233 request->markEarlyDeath();
236 return request.release();
239 PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const String& keyPath, const Dictionary& options, ExceptionCode& ec)
241 return createIndex(name, IDBKeyPath(keyPath), options, ec);
244 PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, PassRefPtr<DOMStringList> keyPath, const Dictionary& options, ExceptionCode& ec)
246 // FIXME: Binding code for DOMString[] should not match null. http://webkit.org/b/84217
248 return createIndex(name, IDBKeyPath("null"), options, ec);
249 return createIndex(name, IDBKeyPath(*keyPath), options, ec);
253 PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const IDBKeyPath& keyPath, const Dictionary& options, ExceptionCode& ec)
255 IDB_TRACE("IDBObjectStore::createIndex");
256 if (!m_transaction->isVersionChange() || m_deleted) {
257 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
261 if (!keyPath.isValid()) {
262 ec = IDBDatabaseException::IDB_SYNTAX_ERR;
267 options.get("unique", unique);
269 bool multiEntry = false;
270 options.get("multiEntry", multiEntry);
272 if (keyPath.type() == IDBKeyPath::ArrayType && multiEntry) {
273 ec = IDBDatabaseException::IDB_NOT_SUPPORTED_ERR;
277 RefPtr<IDBIndexBackendInterface> indexBackend = m_backend->createIndex(name, keyPath, unique, multiEntry, m_transaction->backend(), ec);
278 ASSERT(!indexBackend != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa.
282 RefPtr<IDBIndex> index = IDBIndex::create(indexBackend.release(), this, m_transaction.get());
283 m_indexMap.set(name, index);
285 return index.release();
288 PassRefPtr<IDBIndex> IDBObjectStore::index(const String& name, ExceptionCode& ec)
290 IDB_TRACE("IDBObjectStore::index");
292 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
295 if (m_transaction->isFinished()) {
296 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
300 IDBIndexMap::iterator it = m_indexMap.find(name);
301 if (it != m_indexMap.end())
304 RefPtr<IDBIndexBackendInterface> indexBackend = m_backend->index(name, ec);
305 ASSERT(!indexBackend != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa.
309 RefPtr<IDBIndex> index = IDBIndex::create(indexBackend.release(), this, m_transaction.get());
310 m_indexMap.set(name, index);
311 return index.release();
314 void IDBObjectStore::deleteIndex(const String& name, ExceptionCode& ec)
316 if (!m_transaction->isVersionChange() || m_deleted) {
317 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
321 m_backend->deleteIndex(name, m_transaction->backend(), ec);
323 IDBIndexMap::iterator it = m_indexMap.find(name);
324 if (it != m_indexMap.end()) {
325 it->second->markDeleted();
326 m_indexMap.remove(name);
331 PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, const String& directionString, ExceptionCode& ec)
333 IDB_TRACE("IDBObjectStore::openCursor");
335 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
338 unsigned short direction = IDBCursor::stringToDirection(directionString, ec);
342 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
343 request->setCursorType(IDBCursorBackendInterface::ObjectStoreCursor);
344 m_backend->openCursor(range, direction, request, m_transaction->backend(), ec);
346 request->markEarlyDeath();
349 return request.release();
352 PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, unsigned short direction, ExceptionCode& ec)
354 IDB_TRACE("IDBObjectStore::openCursor");
355 DEFINE_STATIC_LOCAL(String, consoleMessage, ("Numeric direction values are deprecated in IDBObjectStore.openCursor. Use\"next\", \"nextunique\", \"prev\", or \"prevunique\"."));
356 context->addConsoleMessage(JSMessageSource, LogMessageType, WarningMessageLevel, consoleMessage);
357 const String& directionString = IDBCursor::directionToString(direction, ec);
360 return openCursor(context, range, directionString, ec);
363 PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, const String& direction, ExceptionCode& ec)
365 IDB_TRACE("IDBObjectStore::openCursor");
366 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
369 return openCursor(context, keyRange.release(), ec);
372 PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, unsigned short direction, ExceptionCode& ec)
374 IDB_TRACE("IDBObjectStore::openCursor");
375 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
378 return openCursor(context, keyRange.release(), direction, ec);
381 PassRefPtr<IDBRequest> IDBObjectStore::count(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, ExceptionCode& ec)
383 IDB_TRACE("IDBObjectStore::count");
385 ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
388 RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
389 m_backend->count(range, request, m_transaction->backend(), ec);
391 request->markEarlyDeath();
394 return request.release();
397 PassRefPtr<IDBRequest> IDBObjectStore::count(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
399 IDB_TRACE("IDBObjectStore::count");
400 RefPtr<IDBKeyRange> keyRange = IDBKeyRange::only(key, ec);
403 return count(context, keyRange.release(), ec);
406 void IDBObjectStore::transactionFinished()
408 ASSERT(m_transaction->isFinished());
410 // Break reference cycles.
415 } // namespace WebCore
417 #endif // ENABLE(INDEXED_DATABASE)