summaryrefslogtreecommitdiffstats
path: root/WebCore/storage
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2010-10-22 13:02:20 +0100
committerBen Murdoch <benm@google.com>2010-10-26 15:21:41 +0100
commita94275402997c11dd2e778633dacf4b7e630a35d (patch)
treee66f56c67e3b01f22c9c23cd932271ee9ac558ed /WebCore/storage
parent09e26c78506587b3f5d930d7bc72a23287ffbec0 (diff)
downloadexternal_webkit-a94275402997c11dd2e778633dacf4b7e630a35d.zip
external_webkit-a94275402997c11dd2e778633dacf4b7e630a35d.tar.gz
external_webkit-a94275402997c11dd2e778633dacf4b7e630a35d.tar.bz2
Merge WebKit at r70209: Initial merge by Git
Change-Id: Id23a68efa36e9d1126bcce0b137872db00892c8e
Diffstat (limited to 'WebCore/storage')
-rw-r--r--WebCore/storage/IDBAny.cpp31
-rw-r--r--WebCore/storage/IDBAny.h7
-rw-r--r--WebCore/storage/IDBCallbacks.h7
-rw-r--r--WebCore/storage/IDBCompleteEvent.cpp55
-rw-r--r--WebCore/storage/IDBCompleteEvent.h57
-rw-r--r--WebCore/storage/IDBCursor.cpp32
-rw-r--r--WebCore/storage/IDBCursor.h18
-rw-r--r--WebCore/storage/IDBCursor.idl9
-rw-r--r--WebCore/storage/IDBCursorBackendImpl.cpp87
-rw-r--r--WebCore/storage/IDBCursorBackendImpl.h25
-rw-r--r--WebCore/storage/IDBCursorBackendInterface.h7
-rw-r--r--WebCore/storage/IDBDatabase.cpp52
-rw-r--r--WebCore/storage/IDBDatabase.h24
-rw-r--r--WebCore/storage/IDBDatabase.idl17
-rw-r--r--WebCore/storage/IDBDatabaseBackendImpl.cpp161
-rw-r--r--WebCore/storage/IDBDatabaseBackendImpl.h21
-rw-r--r--WebCore/storage/IDBDatabaseBackendInterface.h12
-rw-r--r--WebCore/storage/IDBFactory.cpp16
-rw-r--r--WebCore/storage/IDBFactory.h4
-rw-r--r--WebCore/storage/IDBFactory.idl3
-rw-r--r--WebCore/storage/IDBFactoryBackendImpl.cpp9
-rw-r--r--WebCore/storage/IDBFactoryBackendImpl.h2
-rw-r--r--WebCore/storage/IDBFactoryBackendInterface.h2
-rw-r--r--WebCore/storage/IDBIndex.cpp38
-rw-r--r--WebCore/storage/IDBIndex.h23
-rw-r--r--WebCore/storage/IDBIndex.idl13
-rw-r--r--WebCore/storage/IDBIndexBackendImpl.cpp56
-rw-r--r--WebCore/storage/IDBIndexBackendImpl.h27
-rw-r--r--WebCore/storage/IDBIndexBackendInterface.h10
-rw-r--r--WebCore/storage/IDBKey.cpp2
-rw-r--r--WebCore/storage/IDBKey.h10
-rw-r--r--WebCore/storage/IDBKeyRange.h4
-rw-r--r--WebCore/storage/IDBKeyTree.h153
-rw-r--r--WebCore/storage/IDBObjectStore.cpp64
-rw-r--r--WebCore/storage/IDBObjectStore.h29
-rw-r--r--WebCore/storage/IDBObjectStore.idl30
-rw-r--r--WebCore/storage/IDBObjectStoreBackendImpl.cpp278
-rw-r--r--WebCore/storage/IDBObjectStoreBackendImpl.h50
-rw-r--r--WebCore/storage/IDBObjectStoreBackendInterface.h15
-rw-r--r--WebCore/storage/IDBRequest.cpp39
-rw-r--r--WebCore/storage/IDBRequest.h9
-rw-r--r--WebCore/storage/IDBTimeoutEvent.cpp55
-rw-r--r--WebCore/storage/IDBTimeoutEvent.h57
-rw-r--r--WebCore/storage/IDBTransaction.cpp77
-rw-r--r--WebCore/storage/IDBTransaction.h15
-rw-r--r--WebCore/storage/IDBTransactionBackendImpl.cpp93
-rw-r--r--WebCore/storage/IDBTransactionBackendImpl.h17
-rw-r--r--WebCore/storage/IDBTransactionBackendInterface.h2
-rw-r--r--WebCore/storage/IDBTransactionCallbacks.h4
-rw-r--r--WebCore/storage/IDBTransactionCoordinator.h4
50 files changed, 1196 insertions, 636 deletions
diff --git a/WebCore/storage/IDBAny.cpp b/WebCore/storage/IDBAny.cpp
index 45b166d..3a049c0 100644
--- a/WebCore/storage/IDBAny.cpp
+++ b/WebCore/storage/IDBAny.cpp
@@ -70,6 +70,12 @@ PassRefPtr<IDBDatabase> IDBAny::idbDatabase()
return m_idbDatabase;
}
+PassRefPtr<IDBFactory> IDBAny::idbFactory()
+{
+ ASSERT(m_type == IDBFactoryType);
+ return m_idbFactory;
+}
+
PassRefPtr<IDBIndex> IDBAny::idbIndex()
{
ASSERT(m_type == IDBIndexType);
@@ -88,10 +94,10 @@ PassRefPtr<IDBObjectStore> IDBAny::idbObjectStore()
return m_idbObjectStore;
}
-PassRefPtr<IDBFactory> IDBAny::idbFactory()
+PassRefPtr<IDBTransaction> IDBAny::idbTransaction()
{
- ASSERT(m_type == IDBFactoryType);
- return m_idbFactory;
+ ASSERT(m_type == IDBTransactionType);
+ return m_idbTransaction;
}
PassRefPtr<SerializedScriptValue> IDBAny::serializedScriptValue()
@@ -120,6 +126,13 @@ void IDBAny::set(PassRefPtr<IDBDatabase> value)
m_idbDatabase = value;
}
+void IDBAny::set(PassRefPtr<IDBFactory> value)
+{
+ ASSERT(m_type == UndefinedType);
+ m_type = IDBFactoryType;
+ m_idbFactory = value;
+}
+
void IDBAny::set(PassRefPtr<IDBIndex> value)
{
ASSERT(m_type == UndefinedType);
@@ -134,18 +147,18 @@ void IDBAny::set(PassRefPtr<IDBKey> value)
m_idbKey = value;
}
-void IDBAny::set(PassRefPtr<IDBObjectStore> value)
+void IDBAny::set(PassRefPtr<IDBTransaction> value)
{
ASSERT(m_type == UndefinedType);
- m_type = IDBObjectStoreType;
- m_idbObjectStore = value;
+ m_type = IDBTransactionType;
+ m_idbTransaction = value;
}
-void IDBAny::set(PassRefPtr<IDBFactory> value)
+void IDBAny::set(PassRefPtr<IDBObjectStore> value)
{
ASSERT(m_type == UndefinedType);
- m_type = IDBFactoryType;
- m_idbFactory = value;
+ m_type = IDBObjectStoreType;
+ m_idbObjectStore = value;
}
void IDBAny::set(PassRefPtr<SerializedScriptValue> value)
diff --git a/WebCore/storage/IDBAny.h b/WebCore/storage/IDBAny.h
index 9066e13..8e3f83e 100644
--- a/WebCore/storage/IDBAny.h
+++ b/WebCore/storage/IDBAny.h
@@ -36,10 +36,11 @@ namespace WebCore {
class IDBCursor;
class IDBDatabase;
+class IDBFactory;
class IDBIndex;
class IDBKey;
class IDBObjectStore;
-class IDBFactory;
+class IDBTransaction;
class SerializedScriptValue;
class IDBAny : public RefCounted<IDBAny> {
@@ -71,6 +72,7 @@ public:
IDBIndexType,
IDBKeyType,
IDBObjectStoreType,
+ IDBTransactionType,
SerializedScriptValueType
};
@@ -82,6 +84,7 @@ public:
PassRefPtr<IDBIndex> idbIndex();
PassRefPtr<IDBKey> idbKey();
PassRefPtr<IDBObjectStore> idbObjectStore();
+ PassRefPtr<IDBTransaction> idbTransaction();
PassRefPtr<SerializedScriptValue> serializedScriptValue();
// Set can only be called once.
@@ -92,6 +95,7 @@ public:
void set(PassRefPtr<IDBIndex>);
void set(PassRefPtr<IDBKey>);
void set(PassRefPtr<IDBObjectStore>);
+ void set(PassRefPtr<IDBTransaction>);
void set(PassRefPtr<SerializedScriptValue>);
private:
@@ -106,6 +110,7 @@ private:
RefPtr<IDBIndex> m_idbIndex;
RefPtr<IDBKey> m_idbKey;
RefPtr<IDBObjectStore> m_idbObjectStore;
+ RefPtr<IDBTransaction> m_idbTransaction;
RefPtr<SerializedScriptValue> m_serializedScriptValue;
};
diff --git a/WebCore/storage/IDBCallbacks.h b/WebCore/storage/IDBCallbacks.h
index bc48477..e62c085 100644
--- a/WebCore/storage/IDBCallbacks.h
+++ b/WebCore/storage/IDBCallbacks.h
@@ -35,14 +35,16 @@
#include "IDBIndexBackendInterface.h"
#include "IDBKey.h"
#include "IDBObjectStoreBackendInterface.h"
+#include "IDBTransactionBackendInterface.h"
#include "SerializedScriptValue.h"
-#include <wtf/RefCounted.h>
+#include <wtf/Threading.h>
#if ENABLE(INDEXED_DATABASE)
namespace WebCore {
-class IDBCallbacks : public RefCounted<IDBCallbacks> {
+// FIXME: All child classes need to be made threadsafe.
+class IDBCallbacks : public ThreadSafeShared<IDBCallbacks> {
public:
virtual ~IDBCallbacks() { }
@@ -53,6 +55,7 @@ public:
virtual void onSuccess(PassRefPtr<IDBIndexBackendInterface>) = 0;
virtual void onSuccess(PassRefPtr<IDBKey>) = 0;
virtual void onSuccess(PassRefPtr<IDBObjectStoreBackendInterface>) = 0;
+ virtual void onSuccess(PassRefPtr<IDBTransactionBackendInterface>) = 0;
virtual void onSuccess(PassRefPtr<SerializedScriptValue>) = 0;
};
diff --git a/WebCore/storage/IDBCompleteEvent.cpp b/WebCore/storage/IDBCompleteEvent.cpp
new file mode 100644
index 0000000..f0ad9fc
--- /dev/null
+++ b/WebCore/storage/IDBCompleteEvent.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBCompleteEvent.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "EventNames.h"
+#include "IDBAny.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBCompleteEvent> IDBCompleteEvent::create()
+{
+ return adoptRef(new IDBCompleteEvent());
+}
+
+IDBCompleteEvent::IDBCompleteEvent()
+ : IDBEvent(eventNames().completeEvent, 0) // FIXME: set the source to the transaction
+{
+}
+
+IDBCompleteEvent::~IDBCompleteEvent()
+{
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/storage/IDBCompleteEvent.h b/WebCore/storage/IDBCompleteEvent.h
new file mode 100644
index 0000000..c407096
--- /dev/null
+++ b/WebCore/storage/IDBCompleteEvent.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBCompleteEvent_h
+#define IDBCompleteEvent_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBEvent.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBCompleteEvent : public IDBEvent {
+public:
+ static PassRefPtr<IDBCompleteEvent> create();
+ // FIXME: Need to allow creation of these events from JS.
+ virtual ~IDBCompleteEvent();
+
+ virtual bool isIDBCompleteEvent() const { return true; }
+
+private:
+ IDBCompleteEvent();
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBCompleteEvent_h
diff --git a/WebCore/storage/IDBCursor.cpp b/WebCore/storage/IDBCursor.cpp
index c1c077b..1aaff9d 100644
--- a/WebCore/storage/IDBCursor.cpp
+++ b/WebCore/storage/IDBCursor.cpp
@@ -33,15 +33,20 @@
#include "IDBCursorBackendInterface.h"
#include "IDBKey.h"
#include "IDBRequest.h"
+#include "IDBTransactionBackendInterface.h"
#include "ScriptExecutionContext.h"
#include "SerializedScriptValue.h"
namespace WebCore {
-IDBCursor::IDBCursor(PassRefPtr<IDBCursorBackendInterface> backend, IDBRequest* request)
+IDBCursor::IDBCursor(PassRefPtr<IDBCursorBackendInterface> backend, IDBRequest* request, IDBTransactionBackendInterface* transaction)
: m_backend(backend)
, m_request(request)
+ , m_transaction(transaction)
{
+ ASSERT(m_backend);
+ ASSERT(m_request);
+ ASSERT(m_transaction);
}
IDBCursor::~IDBCursor()
@@ -63,26 +68,31 @@ PassRefPtr<IDBAny> IDBCursor::value() const
return m_backend->value();
}
-PassRefPtr<IDBRequest> IDBCursor::update(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value)
+PassRefPtr<IDBRequest> IDBCursor::update(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_backend->update(value, request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->update(value, request, ec);
+ if (ec)
+ return 0;
return request.release();
}
-void IDBCursor::continueFunction(PassRefPtr<IDBKey> key)
+void IDBCursor::continueFunction(PassRefPtr<IDBKey> key, ExceptionCode& ec)
{
// FIXME: We're not using the context from when continue was called, which means the callback
// will be on the original context openCursor was called on. Is this right?
- if (m_request->resetReadyState())
- m_backend->continueFunction(key, m_request);
- // FIXME: Else throw?
+ if (m_request->resetReadyState(m_transaction.get()))
+ m_backend->continueFunction(key, m_request, ec);
+ else
+ ASSERT_NOT_REACHED();
}
-PassRefPtr<IDBRequest> IDBCursor::remove(ScriptExecutionContext* context)
+PassRefPtr<IDBRequest> IDBCursor::remove(ScriptExecutionContext* context, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_backend->remove(request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->remove(request, ec);
+ if (ec)
+ return 0;
return request.release();
}
diff --git a/WebCore/storage/IDBCursor.h b/WebCore/storage/IDBCursor.h
index 0c438c4..6f3a940 100644
--- a/WebCore/storage/IDBCursor.h
+++ b/WebCore/storage/IDBCursor.h
@@ -28,6 +28,7 @@
#if ENABLE(INDEXED_DATABASE)
+#include "ExceptionCode.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
@@ -41,6 +42,7 @@ class IDBKey;
class IDBRequest;
class ScriptExecutionContext;
class SerializedScriptValue;
+class IDBTransactionBackendInterface;
class IDBCursor : public RefCounted<IDBCursor> {
public:
@@ -50,25 +52,29 @@ public:
PREV = 2,
PREV_NO_DUPLICATE = 3,
};
- static PassRefPtr<IDBCursor> create(PassRefPtr<IDBCursorBackendInterface> backend, IDBRequest* request)
+ static PassRefPtr<IDBCursor> create(PassRefPtr<IDBCursorBackendInterface> backend, IDBRequest* request, IDBTransactionBackendInterface* transaction)
{
- return adoptRef(new IDBCursor(backend, request));
+ return adoptRef(new IDBCursor(backend, request, transaction));
}
~IDBCursor();
+ // FIXME: Try to modify the code generator so this is unneeded.
+ void continueFunction(ExceptionCode& ec) { continueFunction(0, ec); }
+
// Implement the IDL
unsigned short direction() const;
PassRefPtr<IDBKey> key() const;
PassRefPtr<IDBAny> value() const;
- PassRefPtr<IDBRequest> update(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>);
- void continueFunction(PassRefPtr<IDBKey> = 0);
- PassRefPtr<IDBRequest> remove(ScriptExecutionContext*);
+ PassRefPtr<IDBRequest> update(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>, ExceptionCode&);
+ void continueFunction(PassRefPtr<IDBKey>, ExceptionCode&);
+ PassRefPtr<IDBRequest> remove(ScriptExecutionContext*, ExceptionCode&);
private:
- explicit IDBCursor(PassRefPtr<IDBCursorBackendInterface>, IDBRequest*);
+ explicit IDBCursor(PassRefPtr<IDBCursorBackendInterface>, IDBRequest*, IDBTransactionBackendInterface*);
RefPtr<IDBCursorBackendInterface> m_backend;
RefPtr<IDBRequest> m_request;
+ RefPtr<IDBTransactionBackendInterface> m_transaction;
};
} // namespace WebCore
diff --git a/WebCore/storage/IDBCursor.idl b/WebCore/storage/IDBCursor.idl
index 232842b..0cef3f9 100644
--- a/WebCore/storage/IDBCursor.idl
+++ b/WebCore/storage/IDBCursor.idl
@@ -37,8 +37,11 @@ module storage {
readonly attribute IDBKey key;
readonly attribute IDBAny value;
- [CallWith=ScriptExecutionContext] IDBRequest update(in SerializedScriptValue value);
- [ImplementationFunction=continueFunction] void continue(in [Optional] IDBKey key);
- [CallWith=ScriptExecutionContext] IDBRequest remove();
+ [CallWith=ScriptExecutionContext] IDBRequest update(in SerializedScriptValue value)
+ raises (IDBDatabaseException);
+ [ImplementationFunction=continueFunction] void continue(in [Optional] IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest remove()
+ raises (IDBDatabaseException);
};
}
diff --git a/WebCore/storage/IDBCursorBackendImpl.cpp b/WebCore/storage/IDBCursorBackendImpl.cpp
index 13df5f0..40b46c6 100644
--- a/WebCore/storage/IDBCursorBackendImpl.cpp
+++ b/WebCore/storage/IDBCursorBackendImpl.cpp
@@ -28,6 +28,7 @@
#if ENABLE(INDEXED_DATABASE)
+#include "CrossThreadTask.h"
#include "IDBCallbacks.h"
#include "IDBDatabaseBackendImpl.h"
#include "IDBDatabaseError.h"
@@ -43,22 +44,24 @@
namespace WebCore {
-IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl> idbObjectStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query)
+IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl> idbObjectStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, IDBTransactionBackendInterface* transaction)
: m_idbObjectStore(idbObjectStore)
, m_keyRange(keyRange)
, m_direction(direction)
, m_query(query)
, m_isSerializedScriptValueCursor(true)
+ , m_transaction(transaction)
{
loadCurrentRow();
}
-IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBIndexBackendImpl> idbIndex, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor)
+IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBIndexBackendImpl> idbIndex, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface* transaction)
: m_idbIndex(idbIndex)
, m_keyRange(keyRange)
, m_direction(direction)
, m_query(query)
, m_isSerializedScriptValueCursor(isSerializedScriptValueCursor)
+ , m_transaction(transaction)
{
loadCurrentRow();
}
@@ -85,7 +88,17 @@ PassRefPtr<IDBAny> IDBCursorBackendImpl::value() const
return IDBAny::create(m_currentIDBKeyValue.get());
}
-void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> callbacks)
+void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
+{
+ RefPtr<IDBCursorBackendImpl> cursor = this;
+ RefPtr<SerializedScriptValue> value = prpValue;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ // FIXME: Throw DATA_ERR and SERIAL_ERR when appropriate.
+ if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::updateInternal, cursor, value, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBCursorBackendImpl::updateInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> cursor, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> callbacks)
{
// FIXME: This method doesn't update indexes. It's dangerous to call in its current state.
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Not implemented."));
@@ -93,82 +106,100 @@ void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, Pa
RefPtr<SerializedScriptValue> value = prpValue;
- if (!m_query || m_currentId == InvalidId) {
+ if (!cursor->m_query || cursor->m_currentId == InvalidId) {
// FIXME: Use the proper error code when it's specced.
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Operation not possible."));
return;
}
String sql = "UPDATE ObjectStoreData SET value = ? WHERE id = ?";
- SQLiteStatement updateQuery(database()->sqliteDatabase(), sql);
+ SQLiteStatement updateQuery(cursor->database()->sqliteDatabase(), sql);
bool ok = updateQuery.prepare() == SQLResultOk;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
updateQuery.bindText(1, value->toWireString());
- updateQuery.bindInt64(2, m_currentId);
+ updateQuery.bindInt64(2, cursor->m_currentId);
ok = updateQuery.step() == SQLResultDone;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
- if (m_isSerializedScriptValueCursor)
- m_currentSerializedScriptValue = value.release();
+ if (cursor->m_isSerializedScriptValueCursor)
+ cursor->m_currentSerializedScriptValue = value.release();
callbacks->onSuccess();
}
-void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> callbacks)
+void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
+{
+ RefPtr<IDBCursorBackendImpl> cursor = this;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::continueFunctionInternal, cursor, key, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBCursorBackendImpl::continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> prpCursor, PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> callbacks)
{
+ RefPtr<IDBCursorBackendImpl> cursor = prpCursor;
RefPtr<IDBKey> key = prpKey;
while (true) {
- if (!m_query || m_query->step() != SQLResultRow) {
- m_query = 0;
- m_currentId = InvalidId;
- m_currentKey = 0;
- m_currentSerializedScriptValue = 0;
- m_currentIDBKeyValue = 0;
+ if (!cursor->m_query || cursor->m_query->step() != SQLResultRow) {
+ cursor->m_query = 0;
+ cursor->m_currentId = InvalidId;
+ cursor->m_currentKey = 0;
+ cursor->m_currentSerializedScriptValue = 0;
+ cursor->m_currentIDBKeyValue = 0;
callbacks->onSuccess();
return;
}
- RefPtr<IDBKey> oldKey = m_currentKey;
- loadCurrentRow();
+ RefPtr<IDBKey> oldKey = cursor->m_currentKey;
+ cursor->loadCurrentRow();
// If a key was supplied, we must loop until we find that key (or hit the end).
- if (key && !key->isEqual(m_currentKey.get()))
+ if (key && !key->isEqual(cursor->m_currentKey.get()))
continue;
// If we don't have a uniqueness constraint, we can stop now.
- if (m_direction == IDBCursor::NEXT || m_direction == IDBCursor::PREV)
+ if (cursor->m_direction == IDBCursor::NEXT || cursor->m_direction == IDBCursor::PREV)
break;
- if (!m_currentKey->isEqual(oldKey.get()))
+ if (!cursor->m_currentKey->isEqual(oldKey.get()))
break;
}
- callbacks->onSuccess(this);
+ callbacks->onSuccess(cursor.get());
+}
+
+void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
+{
+ RefPtr<IDBCursorBackendImpl> cursor = this;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::removeInternal, cursor, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
}
-void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks> callbacks)
+void IDBCursorBackendImpl::removeInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> cursor, PassRefPtr<IDBCallbacks> callbacks)
{
// FIXME: This method doesn't update indexes. It's dangerous to call in its current state.
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Not implemented."));
return;
- if (!m_query || m_currentId == InvalidId) {
+ if (!cursor->m_query || cursor->m_currentId == InvalidId) {
// FIXME: Use the proper error code when it's specced.
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Operation not possible."));
return;
}
String sql = "DELETE FROM ObjectStoreData WHERE id = ?";
- SQLiteStatement deleteQuery(database()->sqliteDatabase(), sql);
+ SQLiteStatement deleteQuery(cursor->database()->sqliteDatabase(), sql);
bool ok = deleteQuery.prepare() == SQLResultOk;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
- deleteQuery.bindInt64(1, m_currentId);
+ deleteQuery.bindInt64(1, cursor->m_currentId);
ok = deleteQuery.step() == SQLResultDone;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
- m_currentId = InvalidId;
- m_currentSerializedScriptValue = 0;
- m_currentIDBKeyValue = 0;
+ cursor->m_currentId = InvalidId;
+ cursor->m_currentSerializedScriptValue = 0;
+ cursor->m_currentIDBKeyValue = 0;
callbacks->onSuccess();
}
diff --git a/WebCore/storage/IDBCursorBackendImpl.h b/WebCore/storage/IDBCursorBackendImpl.h
index b67ec70..5dd45f2 100644
--- a/WebCore/storage/IDBCursorBackendImpl.h
+++ b/WebCore/storage/IDBCursorBackendImpl.h
@@ -41,35 +41,40 @@ class IDBDatabaseBackendImpl;
class IDBIndexBackendImpl;
class IDBKeyRange;
class IDBObjectStoreBackendImpl;
+class IDBTransactionBackendInterface;
class SQLiteStatement;
class SerializedScriptValue;
class IDBCursorBackendImpl : public IDBCursorBackendInterface {
public:
- static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query)
+ static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, IDBTransactionBackendInterface* transaction)
{
- return adoptRef(new IDBCursorBackendImpl(objectStore, keyRange, direction, query));
+ return adoptRef(new IDBCursorBackendImpl(objectStore, keyRange, direction, query, transaction));
}
- static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor)
+ static PassRefPtr<IDBCursorBackendImpl> create(PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface* transaction)
{
- return adoptRef(new IDBCursorBackendImpl(index, keyRange, direction, query, isSerializedScriptValueCursor));
+ return adoptRef(new IDBCursorBackendImpl(index, keyRange, direction, query, isSerializedScriptValueCursor, transaction));
}
virtual ~IDBCursorBackendImpl();
virtual unsigned short direction() const;
virtual PassRefPtr<IDBKey> key() const;
virtual PassRefPtr<IDBAny> value() const;
- virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>);
- virtual void continueFunction(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
- virtual void remove(PassRefPtr<IDBCallbacks>);
+ virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>, ExceptionCode&);
+ virtual void continueFunction(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, ExceptionCode&);
+ virtual void remove(PassRefPtr<IDBCallbacks>, ExceptionCode&);
private:
- IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query);
- IDBCursorBackendImpl(PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor);
+ IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query, IDBTransactionBackendInterface*);
+ IDBCursorBackendImpl(PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKeyRange>, IDBCursor::Direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface*);
void loadCurrentRow();
IDBDatabaseBackendImpl* database() const;
+ static void updateInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl>, PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>);
+ static void continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl>, PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
+ static void removeInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl>, PassRefPtr<IDBCallbacks>);
+
static const int64_t InvalidId = -1;
// Only one or the other should be used.
@@ -86,6 +91,8 @@ private:
// Only one of these will ever be used for each instance. Which depends on m_isSerializedScriptValueCursor.
RefPtr<SerializedScriptValue> m_currentSerializedScriptValue;
RefPtr<IDBKey> m_currentIDBKeyValue;
+
+ RefPtr<IDBTransactionBackendInterface> m_transaction;
};
} // namespace WebCore
diff --git a/WebCore/storage/IDBCursorBackendInterface.h b/WebCore/storage/IDBCursorBackendInterface.h
index 4b209c4..e1ac274 100644
--- a/WebCore/storage/IDBCursorBackendInterface.h
+++ b/WebCore/storage/IDBCursorBackendInterface.h
@@ -28,6 +28,7 @@
#if ENABLE(INDEXED_DATABASE)
+#include "ExceptionCode.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/Threading.h>
@@ -48,9 +49,9 @@ public:
virtual PassRefPtr<IDBKey> key() const = 0;
virtual PassRefPtr<IDBAny> value() const = 0;
- virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>) = 0;
- virtual void continueFunction(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>) = 0;
- virtual void remove(PassRefPtr<IDBCallbacks>) = 0;
+ virtual void update(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBCallbacks>, ExceptionCode&) = 0;
+ virtual void continueFunction(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>, ExceptionCode&) = 0;
+ virtual void remove(PassRefPtr<IDBCallbacks>, ExceptionCode&) = 0;
};
} // namespace WebCore
diff --git a/WebCore/storage/IDBDatabase.cpp b/WebCore/storage/IDBDatabase.cpp
index 0ea7ac2..1ee0fa9 100644
--- a/WebCore/storage/IDBDatabase.cpp
+++ b/WebCore/storage/IDBDatabase.cpp
@@ -27,7 +27,10 @@
#include "IDBDatabase.h"
#include "IDBAny.h"
+#include "IDBDatabaseError.h"
+#include "IDBDatabaseException.h"
#include "IDBFactoryBackendInterface.h"
+#include "IDBIndex.h"
#include "IDBObjectStore.h"
#include "IDBRequest.h"
#include "IDBTransaction.h"
@@ -40,7 +43,7 @@ namespace WebCore {
IDBDatabase::IDBDatabase(PassRefPtr<IDBDatabaseBackendInterface> backend)
: m_backend(backend)
{
- // We pass a reference to this object before it can be adopted.
+ // We pass a reference of this object before it can be adopted.
relaxAdoptionRequirement();
}
@@ -48,47 +51,58 @@ IDBDatabase::~IDBDatabase()
{
}
-PassRefPtr<IDBRequest> IDBDatabase::createObjectStore(ScriptExecutionContext* context, const String& name, const String& keyPath, bool autoIncrement)
+void IDBDatabase::setSetVersionTransaction(IDBTransactionBackendInterface* transaction)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_backend->createObjectStore(name, keyPath, autoIncrement, request);
- return request;
+ m_setVersionTransaction = transaction;
}
-// FIXME: remove this method.
-PassRefPtr<IDBObjectStore> IDBDatabase::objectStore(const String& name, unsigned short mode)
+PassRefPtr<IDBObjectStore> IDBDatabase::createObjectStore(const String& name, const String& keyPath, bool autoIncrement, ExceptionCode& ec)
{
- RefPtr<IDBObjectStoreBackendInterface> objectStore = m_backend->objectStore(name, mode);
- ASSERT(objectStore); // FIXME: If this is null, we should raise a NOT_FOUND_ERR.
- return IDBObjectStore::create(objectStore.release(), 0);
+ if (!m_setVersionTransaction) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return 0;
+ }
+
+ RefPtr<IDBObjectStoreBackendInterface> objectStore = m_backend->createObjectStore(name, keyPath, autoIncrement, m_setVersionTransaction.get(), ec);
+ if (!objectStore)
+ return 0;
+ return IDBObjectStore::create(objectStore.release(), m_setVersionTransaction.get());
}
-PassRefPtr<IDBRequest> IDBDatabase::removeObjectStore(ScriptExecutionContext* context, const String& name)
+void IDBDatabase::removeObjectStore(const String& name, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_backend->removeObjectStore(name, request);
- return request;
+ if (!m_setVersionTransaction) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return;
+ }
+
+ m_backend->removeObjectStore(name, m_setVersionTransaction.get(), ec);
}
-PassRefPtr<IDBRequest> IDBDatabase::setVersion(ScriptExecutionContext* context, const String& version)
+PassRefPtr<IDBRequest> IDBDatabase::setVersion(ScriptExecutionContext* context, const String& version, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_backend->setVersion(version, request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), 0);
+ m_backend->setVersion(version, request, ec);
return request;
}
-PassRefPtr<IDBTransaction> IDBDatabase::transaction(ScriptExecutionContext* context, DOMStringList* storeNames, unsigned short mode, unsigned long timeout)
+PassRefPtr<IDBTransaction> IDBDatabase::transaction(ScriptExecutionContext* context, DOMStringList* storeNames, unsigned short mode, unsigned long timeout, ExceptionCode& ec)
{
// We need to create a new transaction synchronously. Locks are acquired asynchronously. Operations
// can be queued against the transaction at any point. They will start executing as soon as the
// appropriate locks have been acquired.
// Also note that each backend object corresponds to exactly one IDBTransaction object.
- RefPtr<IDBTransactionBackendInterface> transactionBackend = m_backend->transaction(storeNames, mode, timeout);
+ RefPtr<IDBTransactionBackendInterface> transactionBackend = m_backend->transaction(storeNames, mode, timeout, ec);
RefPtr<IDBTransaction> transaction = IDBTransaction::create(context, transactionBackend, this);
transactionBackend->setCallbacks(transaction.get());
return transaction.release();
}
+void IDBDatabase::close()
+{
+ m_backend->close();
+}
+
} // namespace WebCore
#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBDatabase.h b/WebCore/storage/IDBDatabase.h
index dc70114..df56f46 100644
--- a/WebCore/storage/IDBDatabase.h
+++ b/WebCore/storage/IDBDatabase.h
@@ -27,7 +27,9 @@
#define IDBDatabase_h
#include "DOMStringList.h"
+#include "ExceptionCode.h"
#include "IDBDatabaseBackendInterface.h"
+#include "IDBObjectStore.h"
#include "IDBTransaction.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
@@ -38,7 +40,6 @@
namespace WebCore {
class IDBAny;
-class IDBObjectStore;
class IDBRequest;
class ScriptExecutionContext;
@@ -50,22 +51,31 @@ public:
}
~IDBDatabase();
+ void setSetVersionTransaction(IDBTransactionBackendInterface*);
+
// Implement the IDL
String name() const { return m_backend->name(); }
String version() const { return m_backend->version(); }
PassRefPtr<DOMStringList> objectStores() const { return m_backend->objectStores(); }
- PassRefPtr<IDBRequest> createObjectStore(ScriptExecutionContext*, const String& name, const String& keyPath = String(), bool autoIncrement = false);
- PassRefPtr<IDBObjectStore> objectStore(const String& name, unsigned short mode = IDBTransaction::READ_ONLY);
- PassRefPtr<IDBRequest> removeObjectStore(ScriptExecutionContext*, const String& name);
- PassRefPtr<IDBRequest> setVersion(ScriptExecutionContext*, const String& version);
- PassRefPtr<IDBTransaction> transaction(ScriptExecutionContext*, DOMStringList* storeNames = 0, unsigned short mode = IDBTransaction::READ_ONLY,
- unsigned long timeout = 0); // FIXME: what should the default timeout be?
+ // FIXME: Try to modify the code generator so this is unneeded.
+ PassRefPtr<IDBObjectStore> createObjectStore(const String& name, ExceptionCode& ec) { return createObjectStore(name, String(), ec); }
+ PassRefPtr<IDBObjectStore> createObjectStore(const String& name, const String& keyPath, ExceptionCode& ec) { return createObjectStore(name, keyPath, false, ec); }
+ PassRefPtr<IDBTransaction> transaction(ScriptExecutionContext* context, ExceptionCode& ec) { return transaction(context, 0, ec); }
+ PassRefPtr<IDBTransaction> transaction(ScriptExecutionContext* context, DOMStringList* storeNames, ExceptionCode& ec) { return transaction(context, storeNames, IDBTransaction::READ_ONLY, ec); }
+ PassRefPtr<IDBTransaction> transaction(ScriptExecutionContext* context, DOMStringList* storeNames, unsigned short mode, ExceptionCode& ec) { return transaction(context, storeNames, mode, 0, ec); } // FIXME: what should the default timeout be?
+
+ PassRefPtr<IDBObjectStore> createObjectStore(const String& name, const String& keyPath, bool autoIncrement, ExceptionCode&);
+ void removeObjectStore(const String& name, ExceptionCode&);
+ PassRefPtr<IDBRequest> setVersion(ScriptExecutionContext*, const String& version, ExceptionCode&);
+ PassRefPtr<IDBTransaction> transaction(ScriptExecutionContext*, DOMStringList*, unsigned short mode, unsigned long timeout, ExceptionCode&);
+ void close();
private:
IDBDatabase(PassRefPtr<IDBDatabaseBackendInterface>);
RefPtr<IDBDatabaseBackendInterface> m_backend;
+ RefPtr<IDBTransactionBackendInterface> m_setVersionTransaction;
};
} // namespace WebCore
diff --git a/WebCore/storage/IDBDatabase.idl b/WebCore/storage/IDBDatabase.idl
index 347b3a7..b529c9a 100644
--- a/WebCore/storage/IDBDatabase.idl
+++ b/WebCore/storage/IDBDatabase.idl
@@ -32,14 +32,15 @@ module storage {
readonly attribute DOMString version;
readonly attribute DOMStringList objectStores;
-
- [CallWith=ScriptExecutionContext] IDBRequest createObjectStore(in DOMString name, in [Optional, ConvertNullToNullString] DOMString keyPath, in [Optional] boolean autoIncrement);
- // FIXME: objectStore needs to be able to raise an IDBDatabaseException.
- IDBObjectStore objectStore(in DOMString name, in [Optional] unsigned short mode);
- [CallWith=ScriptExecutionContext] IDBRequest removeObjectStore(in DOMString name);
- [CallWith=ScriptExecutionContext] IDBRequest setVersion(in DOMString version);
- [CallWith=ScriptExecutionContext] IDBTransaction transaction (in [Optional] DOMStringList storeNames, in [Optional] unsigned short mode, in [Optional] unsigned long timeout);
- // FIXME: Add close.
+ IDBObjectStore createObjectStore(in DOMString name, in [Optional, ConvertNullToNullString] DOMString keyPath, in [Optional] boolean autoIncrement)
+ raises (IDBDatabaseException);
+ void removeObjectStore(in DOMString name)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest setVersion(in DOMString version)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBTransaction transaction (in [Optional] DOMStringList storeNames, in [Optional] unsigned short mode, in [Optional] unsigned long timeout)
+ raises (IDBDatabaseException);
+ void close();
};
}
diff --git a/WebCore/storage/IDBDatabaseBackendImpl.cpp b/WebCore/storage/IDBDatabaseBackendImpl.cpp
index b8fe9b5..dc61e22 100644
--- a/WebCore/storage/IDBDatabaseBackendImpl.cpp
+++ b/WebCore/storage/IDBDatabaseBackendImpl.cpp
@@ -26,21 +26,23 @@
#include "config.h"
#include "IDBDatabaseBackendImpl.h"
+#if ENABLE(INDEXED_DATABASE)
+
+#include "CrossThreadTask.h"
#include "DOMStringList.h"
#include "IDBDatabaseException.h"
#include "IDBObjectStoreBackendImpl.h"
+#include "IDBTransactionBackendInterface.h"
#include "IDBTransactionCoordinator.h"
#include "SQLiteDatabase.h"
#include "SQLiteStatement.h"
#include "SQLiteTransaction.h"
-#if ENABLE(INDEXED_DATABASE)
-
namespace WebCore {
-static bool extractMetaData(SQLiteDatabase* sqliteDatabase, const String& expectedName, String& foundDescription, String& foundVersion)
+static bool extractMetaData(SQLiteDatabase* sqliteDatabase, const String& expectedName, String& foundVersion)
{
- SQLiteStatement metaDataQuery(*sqliteDatabase, "SELECT name, description, version FROM MetaData");
+ SQLiteStatement metaDataQuery(*sqliteDatabase, "SELECT name, version FROM MetaData");
if (metaDataQuery.prepare() != SQLResultOk || metaDataQuery.step() != SQLResultRow)
return false;
@@ -48,8 +50,7 @@ static bool extractMetaData(SQLiteDatabase* sqliteDatabase, const String& expect
LOG_ERROR("Name in MetaData (%s) doesn't match expected (%s) for IndexedDB", metaDataQuery.getColumnText(0).utf8().data(), expectedName.utf8().data());
ASSERT_NOT_REACHED();
}
- foundDescription = metaDataQuery.getColumnText(1);
- foundVersion = metaDataQuery.getColumnText(2);
+ foundVersion = metaDataQuery.getColumnText(1);
if (metaDataQuery.step() == SQLResultRow) {
LOG_ERROR("More than one row found in MetaData table");
@@ -80,26 +81,21 @@ static bool setMetaData(SQLiteDatabase* sqliteDatabase, const String& name, cons
return false;
}
- // FIXME: Should we assert there's only one row?
-
return true;
}
IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, const String& description, PassOwnPtr<SQLiteDatabase> sqliteDatabase, IDBTransactionCoordinator* coordinator)
: m_sqliteDatabase(sqliteDatabase)
, m_name(name)
+ , m_description(description)
, m_version("")
, m_transactionCoordinator(coordinator)
{
ASSERT(!m_name.isNull());
+ ASSERT(!m_description.isNull());
- // FIXME: The spec is in flux about how to handle description. Sync it up once a final decision is made.
- String foundDescription = "";
- bool result = extractMetaData(m_sqliteDatabase.get(), m_name, foundDescription, m_version);
- m_description = description.isNull() ? foundDescription : description;
-
- if (!result || m_description != foundDescription)
- setMetaData(m_sqliteDatabase.get(), m_name, m_description, m_version);
+ extractMetaData(m_sqliteDatabase.get(), m_name, m_version);
+ setMetaData(m_sqliteDatabase.get(), m_name, m_description, m_version);
loadObjectStores();
}
@@ -125,35 +121,49 @@ PassRefPtr<DOMStringList> IDBDatabaseBackendImpl::objectStores() const
return objectStoreNames.release();
}
-void IDBDatabaseBackendImpl::createObjectStore(const String& name, const String& keyPath, bool autoIncrement, PassRefPtr<IDBCallbacks> callbacks)
+PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::createObjectStore(const String& name, const String& keyPath, bool autoIncrement, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
{
if (m_objectStores.contains(name)) {
- callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "An objectStore with that name already exists."));
- return;
+ // FIXME: Throw CONSTRAINT_ERR in this case.
+ return 0;
}
- SQLiteStatement insert(sqliteDatabase(), "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement) VALUES (?, ?, ?)");
- bool ok = insert.prepare() == SQLResultOk;
- ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
- insert.bindText(1, name);
- insert.bindText(2, keyPath);
- insert.bindInt(3, static_cast<int>(autoIncrement));
- ok = insert.step() == SQLResultDone;
- ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
- int64_t id = sqliteDatabase().lastInsertRowID();
-
- RefPtr<IDBObjectStoreBackendImpl> objectStore = IDBObjectStoreBackendImpl::create(this, id, name, keyPath, autoIncrement);
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = IDBObjectStoreBackendImpl::create(this, name, keyPath, autoIncrement);
ASSERT(objectStore->name() == name);
+
+ RefPtr<IDBDatabaseBackendImpl> database = this;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBDatabaseBackendImpl::createObjectStoreInternal, database, objectStore, transaction),
+ createCallbackTask(&IDBDatabaseBackendImpl::removeObjectStoreFromMap, database, objectStore))) {
+ return 0;
+ }
+
m_objectStores.set(name, objectStore);
- callbacks->onSuccess(objectStore.get());
+ return objectStore.release();
}
-// FIXME: Do not expose this method via IDL.
-PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::objectStore(const String& name, unsigned short mode)
+void IDBDatabaseBackendImpl::createObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBTransactionBackendInterface> transaction)
{
- ASSERT_UNUSED(mode, !mode); // FIXME: Remove the mode parameter. Transactions have modes, not object stores.
- RefPtr<IDBObjectStoreBackendInterface> objectStore = m_objectStores.get(name);
- return objectStore.release();
+ SQLiteStatement insert(database->sqliteDatabase(), "INSERT INTO ObjectStores (name, keyPath, doAutoIncrement) VALUES (?, ?, ?)");
+ if (insert.prepare() != SQLResultOk) {
+ transaction->abort();
+ return;
+ }
+ insert.bindText(1, objectStore->name());
+ insert.bindText(2, objectStore->keyPath());
+ insert.bindInt(3, static_cast<int>(objectStore->autoIncrement()));
+ if (insert.step() != SQLResultDone) {
+ transaction->abort();
+ return;
+ }
+ int64_t id = database->sqliteDatabase().lastInsertRowID();
+ objectStore->setId(id);
+ transaction->didCompleteTaskEvents();
+}
+
+PassRefPtr<IDBObjectStoreBackendInterface> IDBDatabaseBackendImpl::objectStore(const String& name)
+{
+ return m_objectStores.get(name);
}
static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id)
@@ -166,38 +176,68 @@ static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id)
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
}
-void IDBDatabaseBackendImpl::removeObjectStore(const String& name, PassRefPtr<IDBCallbacks> callbacks)
+void IDBDatabaseBackendImpl::removeObjectStore(const String& name, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
{
RefPtr<IDBObjectStoreBackendImpl> objectStore = m_objectStores.get(name);
if (!objectStore) {
- callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "No objectStore with that name exists."));
+ ec = IDBDatabaseException::NOT_FOUND_ERR;
return;
}
+ RefPtr<IDBDatabaseBackendImpl> database = this;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBDatabaseBackendImpl::removeObjectStoreInternal, database, objectStore, transaction),
+ createCallbackTask(&IDBDatabaseBackendImpl::addObjectStoreToMap, database, objectStore))) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return;
+ }
+ m_objectStores.remove(name);
+}
- SQLiteTransaction transaction(sqliteDatabase());
- transaction.begin();
- doDelete(sqliteDatabase(), "DELETE FROM ObjectStores WHERE id = ?", objectStore->id());
- doDelete(sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStore->id());
- doDelete(sqliteDatabase(), "DELETE FROM IndexData WHERE indexId IN (SELECT id FROM Indexes WHERE objectStoreId = ?)", objectStore->id());
- doDelete(sqliteDatabase(), "DELETE FROM Indexes WHERE objectStoreId = ?", objectStore->id());
- transaction.commit();
+void IDBDatabaseBackendImpl::removeObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ doDelete(database->sqliteDatabase(), "DELETE FROM ObjectStores WHERE id = ?", objectStore->id());
+ doDelete(database->sqliteDatabase(), "DELETE FROM ObjectStoreData WHERE objectStoreId = ?", objectStore->id());
+ doDelete(database->sqliteDatabase(), "DELETE FROM IndexData WHERE indexId IN (SELECT id FROM Indexes WHERE objectStoreId = ?)", objectStore->id());
+ doDelete(database->sqliteDatabase(), "DELETE FROM Indexes WHERE objectStoreId = ?", objectStore->id());
- m_objectStores.remove(name);
- callbacks->onSuccess();
+ transaction->didCompleteTaskEvents();
}
-void IDBDatabaseBackendImpl::setVersion(const String& version, PassRefPtr<IDBCallbacks> callbacks)
+void IDBDatabaseBackendImpl::setVersion(const String& version, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
{
- m_version = version;
- setMetaData(m_sqliteDatabase.get(), m_name, m_description, m_version);
- callbacks->onSuccess();
+ RefPtr<IDBDatabaseBackendImpl> database = this;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<DOMStringList> objectStores = DOMStringList::create();
+ RefPtr<IDBTransactionBackendInterface> transaction = m_transactionCoordinator->createTransaction(objectStores.get(), IDBTransaction::VERSION_CHANGE, 0, this);
+ if (!transaction->scheduleTask(createCallbackTask(&IDBDatabaseBackendImpl::setVersionInternal, database, version, callbacks, transaction),
+ createCallbackTask(&IDBDatabaseBackendImpl::resetVersion, database, m_version))) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ }
+}
+
+void IDBDatabaseBackendImpl::setVersionInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, const String& version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ database->m_version = version;
+ if (!setMetaData(database->m_sqliteDatabase.get(), database->m_name, database->m_description, database->m_version)) {
+ // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
+ transaction->abort();
+ return;
+ }
+ callbacks->onSuccess(transaction);
}
-PassRefPtr<IDBTransactionBackendInterface> IDBDatabaseBackendImpl::transaction(DOMStringList* objectStores, unsigned short mode, unsigned long timeout)
+PassRefPtr<IDBTransactionBackendInterface> IDBDatabaseBackendImpl::transaction(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, ExceptionCode&)
{
+ // FIXME: Return not allowed err if close has been called.
return m_transactionCoordinator->createTransaction(objectStores, mode, timeout, this);
}
+void IDBDatabaseBackendImpl::close()
+{
+ // FIXME: Implement.
+}
+
void IDBDatabaseBackendImpl::loadObjectStores()
{
SQLiteStatement objectStoresQuery(sqliteDatabase(), "SELECT id, name, keyPath, doAutoIncrement FROM ObjectStores");
@@ -214,6 +254,25 @@ void IDBDatabaseBackendImpl::loadObjectStores()
}
}
+void IDBDatabaseBackendImpl::removeObjectStoreFromMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
+{
+ ASSERT(database->m_objectStores.contains(objectStore->name()));
+ database->m_objectStores.remove(objectStore->name());
+}
+
+void IDBDatabaseBackendImpl::addObjectStoreToMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, PassRefPtr<IDBObjectStoreBackendImpl> objectStore)
+{
+ RefPtr<IDBObjectStoreBackendImpl> objectStorePtr = objectStore;
+ ASSERT(!database->m_objectStores.contains(objectStorePtr->name()));
+ database->m_objectStores.set(objectStorePtr->name(), objectStorePtr);
+}
+
+void IDBDatabaseBackendImpl::resetVersion(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl> database, const String& version)
+{
+ database->m_version = version;
+}
+
+
} // namespace WebCore
#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBDatabaseBackendImpl.h b/WebCore/storage/IDBDatabaseBackendImpl.h
index 7e08ad6..bb6429c 100644
--- a/WebCore/storage/IDBDatabaseBackendImpl.h
+++ b/WebCore/storage/IDBDatabaseBackendImpl.h
@@ -50,18 +50,18 @@ public:
void setDescription(const String& description);
SQLiteDatabase& sqliteDatabase() const { return *m_sqliteDatabase.get(); }
- // Implements IDBDatabase
virtual String name() const { return m_name; }
virtual String description() const { return m_description; }
virtual String version() const { return m_version; }
virtual PassRefPtr<DOMStringList> objectStores() const;
- virtual void createObjectStore(const String& name, const String& keyPath, bool autoIncrement, PassRefPtr<IDBCallbacks>);
- virtual PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name, unsigned short mode);
- virtual void removeObjectStore(const String& name, PassRefPtr<IDBCallbacks>);
- virtual void setVersion(const String& version, PassRefPtr<IDBCallbacks>);
- virtual PassRefPtr<IDBTransactionBackendInterface> transaction(DOMStringList* storeNames, unsigned short mode, unsigned long timeout);
+ virtual PassRefPtr<IDBObjectStoreBackendInterface> createObjectStore(const String& name, const String& keyPath, bool autoIncrement, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void removeObjectStore(const String& name, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void setVersion(const String& version, PassRefPtr<IDBCallbacks>, ExceptionCode&);
+ virtual PassRefPtr<IDBTransactionBackendInterface> transaction(DOMStringList* storeNames, unsigned short mode, unsigned long timeout, ExceptionCode&);
+ virtual void close();
+ PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name);
IDBTransactionCoordinator* transactionCoordinator() const { return m_transactionCoordinator.get(); }
private:
@@ -69,6 +69,15 @@ private:
void loadObjectStores();
+ static void createObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void removeObjectStoreInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void setVersionInternal(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, const String& version, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
+
+ // These are used as setVersion transaction abort tasks.
+ static void removeObjectStoreFromMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>);
+ static void addObjectStoreToMap(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, PassRefPtr<IDBObjectStoreBackendImpl>);
+ static void resetVersion(ScriptExecutionContext*, PassRefPtr<IDBDatabaseBackendImpl>, const String& version);
+
OwnPtr<SQLiteDatabase> m_sqliteDatabase;
String m_name;
String m_description;
diff --git a/WebCore/storage/IDBDatabaseBackendInterface.h b/WebCore/storage/IDBDatabaseBackendInterface.h
index a2e042a..4b0255d 100644
--- a/WebCore/storage/IDBDatabaseBackendInterface.h
+++ b/WebCore/storage/IDBDatabaseBackendInterface.h
@@ -26,6 +26,7 @@
#ifndef IDBDatabaseBackendInterface_h
#define IDBDatabaseBackendInterface_h
+#include "ExceptionCode.h"
#include "PlatformString.h"
#include <wtf/PassRefPtr.h>
#include <wtf/Threading.h>
@@ -54,12 +55,11 @@ public:
virtual String version() const = 0;
virtual PassRefPtr<DOMStringList> objectStores() const = 0;
- virtual void createObjectStore(const String& name, const String& keyPath, bool autoIncrement, PassRefPtr<IDBCallbacks>) = 0;
- virtual PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name, unsigned short mode) = 0;
- virtual void removeObjectStore(const String& name, PassRefPtr<IDBCallbacks>) = 0;
- virtual void setVersion(const String& version, PassRefPtr<IDBCallbacks>) = 0;
- virtual PassRefPtr<IDBTransactionBackendInterface> transaction(DOMStringList* storeNames, unsigned short mode, unsigned long timeout) = 0;
- // FIXME: Add close.
+ virtual PassRefPtr<IDBObjectStoreBackendInterface> createObjectStore(const String& name, const String& keyPath, bool autoIncrement, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void removeObjectStore(const String& name, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void setVersion(const String& version, PassRefPtr<IDBCallbacks>, ExceptionCode&) = 0;
+ virtual PassRefPtr<IDBTransactionBackendInterface> transaction(DOMStringList* storeNames, unsigned short mode, unsigned long timeout, ExceptionCode&) = 0;
+ virtual void close() = 0;
};
} // namespace WebCore
diff --git a/WebCore/storage/IDBFactory.cpp b/WebCore/storage/IDBFactory.cpp
index 06c06ea..649eb37 100644
--- a/WebCore/storage/IDBFactory.cpp
+++ b/WebCore/storage/IDBFactory.cpp
@@ -37,6 +37,7 @@
#include "Frame.h"
#include "GroupSettings.h"
#include "IDBDatabase.h"
+#include "IDBDatabaseException.h"
#include "IDBFactoryBackendInterface.h"
#include "IDBKeyRange.h"
#include "IDBRequest.h"
@@ -56,7 +57,7 @@ IDBFactory::~IDBFactory()
{
}
-PassRefPtr<IDBRequest> IDBFactory::open(ScriptExecutionContext* context, const String& name, const String& description)
+PassRefPtr<IDBRequest> IDBFactory::open(ScriptExecutionContext* context, const String& name, const String& description, ExceptionCode& ec)
{
if (!context->isDocument()) {
// FIXME: make this work with workers.
@@ -67,8 +68,17 @@ PassRefPtr<IDBRequest> IDBFactory::open(ScriptExecutionContext* context, const S
if (!document->frame() || !document->page())
return 0;
- RefPtr<IDBRequest> request = IDBRequest::create(document, IDBAny::create(this));
- m_factoryBackend->open(name, description, request, document->securityOrigin(), document->frame(), document->page()->group().groupSettings()->indexedDBDatabasePath());
+
+ // FIXME: Raise a NON_TRANSIENT_ERR if the name is invalid.
+
+ if (description.isNull()) {
+ ec = IDBDatabaseException::NON_TRANSIENT_ERR;
+ return 0;
+ }
+
+ RefPtr<IDBRequest> request = IDBRequest::create(document, IDBAny::create(this), 0);
+ GroupSettings* groupSettings = document->page()->group().groupSettings();
+ m_factoryBackend->open(name, description, request, document->securityOrigin(), document->frame(), groupSettings->indexedDBDatabasePath(), groupSettings->indexedDBQuotaBytes());
return request;
}
diff --git a/WebCore/storage/IDBFactory.h b/WebCore/storage/IDBFactory.h
index a96aa38..8953245 100644
--- a/WebCore/storage/IDBFactory.h
+++ b/WebCore/storage/IDBFactory.h
@@ -31,6 +31,7 @@
#include "DOMStringList.h"
#include "ExceptionCode.h"
#include "IDBFactoryBackendInterface.h"
+#include "IDBRequest.h"
#include "PlatformString.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
@@ -42,7 +43,6 @@ namespace WebCore {
class IDBKey;
class IDBKeyRange;
-class IDBRequest;
class IDBFactoryBackendInterface;
class ScriptExecutionContext;
@@ -54,7 +54,7 @@ public:
}
~IDBFactory();
- PassRefPtr<IDBRequest> open(ScriptExecutionContext*, const String& name, const String& description = String());
+ PassRefPtr<IDBRequest> open(ScriptExecutionContext*, const String& name, const String& description, ExceptionCode&);
private:
IDBFactory(IDBFactoryBackendInterface*);
diff --git a/WebCore/storage/IDBFactory.idl b/WebCore/storage/IDBFactory.idl
index 215d67c..646df41 100644
--- a/WebCore/storage/IDBFactory.idl
+++ b/WebCore/storage/IDBFactory.idl
@@ -28,7 +28,8 @@ module storage {
interface [
Conditional=INDEXED_DATABASE
] IDBFactory {
- [CallWith=ScriptExecutionContext] IDBRequest open(in DOMString name, in [Optional, ConvertUndefinedOrNullToNullString] DOMString description);
+ [CallWith=ScriptExecutionContext] IDBRequest open(in DOMString name, in [ConvertUndefinedOrNullToNullString] DOMString description)
+ raises (IDBDatabaseException);
};
}
diff --git a/WebCore/storage/IDBFactoryBackendImpl.cpp b/WebCore/storage/IDBFactoryBackendImpl.cpp
index 6219c2d..c18294d 100644
--- a/WebCore/storage/IDBFactoryBackendImpl.cpp
+++ b/WebCore/storage/IDBFactoryBackendImpl.cpp
@@ -52,7 +52,7 @@ IDBFactoryBackendImpl::~IDBFactoryBackendImpl()
{
}
-static PassOwnPtr<SQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOrigin, String name, const String& pathBase)
+static PassOwnPtr<SQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOrigin, String name, const String& pathBase, int64_t maximumSize)
{
String path = ":memory:";
if (!pathBase.isEmpty()) {
@@ -72,6 +72,7 @@ static PassOwnPtr<SQLiteDatabase> openSQLiteDatabase(SecurityOrigin* securityOri
return 0;
}
+ sqliteDatabase->setMaximumSize(maximumSize);
return sqliteDatabase.release();
}
@@ -98,7 +99,7 @@ static bool createTables(SQLiteDatabase* sqliteDatabase)
"CREATE UNIQUE INDEX IF NOT EXISTS ObjectStoreData_composit ON ObjectStoreData(keyString, keyDate, keyNumber, objectStoreId)",
"DROP TABLE IF EXISTS IndexData",
- "CREATE TABLE IF NOT EXISTS IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL UNIQUE REFERENCES ObjectStoreData(id))",
+ "CREATE TABLE IF NOT EXISTS IndexData (id INTEGER PRIMARY KEY, indexId INTEGER NOT NULL REFERENCES Indexes(id), keyString TEXT, keyDate INTEGER, keyNumber INTEGER, objectStoreDataId INTEGER NOT NULL REFERENCES ObjectStoreData(id))",
"DROP INDEX IF EXISTS IndexData_composit",
"CREATE INDEX IF NOT EXISTS IndexData_composit ON IndexData(keyString, keyDate, keyNumber, indexId)",
"DROP INDEX IF EXISTS IndexData_objectStoreDataId",
@@ -117,7 +118,7 @@ static bool createTables(SQLiteDatabase* sqliteDatabase)
return true;
}
-void IDBFactoryBackendImpl::open(const String& name, const String& description, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*, const String& dataDir)
+void IDBFactoryBackendImpl::open(const String& name, const String& description, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<SecurityOrigin> securityOrigin, Frame*, const String& dataDir, int64_t maximumSize)
{
IDBDatabaseBackendMap::iterator it = m_databaseBackendMap.find(name);
if (it != m_databaseBackendMap.end()) {
@@ -129,7 +130,7 @@ void IDBFactoryBackendImpl::open(const String& name, const String& description,
// FIXME: Everything from now on should be done on another thread.
- OwnPtr<SQLiteDatabase> sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), name, dataDir);
+ OwnPtr<SQLiteDatabase> sqliteDatabase = openSQLiteDatabase(securityOrigin.get(), name, dataDir, maximumSize);
if (!sqliteDatabase || !createTables(sqliteDatabase.get())) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Internal error."));
return;
diff --git a/WebCore/storage/IDBFactoryBackendImpl.h b/WebCore/storage/IDBFactoryBackendImpl.h
index 76e545e..211b7fa 100644
--- a/WebCore/storage/IDBFactoryBackendImpl.h
+++ b/WebCore/storage/IDBFactoryBackendImpl.h
@@ -49,7 +49,7 @@ public:
}
virtual ~IDBFactoryBackendImpl();
- virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir);
+ virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir, int64_t maximumSize);
static String databaseFileName(const String& name, SecurityOrigin*);
diff --git a/WebCore/storage/IDBFactoryBackendInterface.h b/WebCore/storage/IDBFactoryBackendInterface.h
index 4914024..7d922c3 100644
--- a/WebCore/storage/IDBFactoryBackendInterface.h
+++ b/WebCore/storage/IDBFactoryBackendInterface.h
@@ -51,7 +51,7 @@ public:
static PassRefPtr<IDBFactoryBackendInterface> create();
virtual ~IDBFactoryBackendInterface() { }
- virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir) = 0;
+ virtual void open(const String& name, const String& description, PassRefPtr<IDBCallbacks>, PassRefPtr<SecurityOrigin>, Frame*, const String& dataDir, int64_t maximumSize) = 0;
};
} // namespace WebCore
diff --git a/WebCore/storage/IDBIndex.cpp b/WebCore/storage/IDBIndex.cpp
index 5cd12dd..a008470 100644
--- a/WebCore/storage/IDBIndex.cpp
+++ b/WebCore/storage/IDBIndex.cpp
@@ -33,43 +33,55 @@
#include "IDBKey.h"
#include "IDBKeyRange.h"
#include "IDBRequest.h"
+#include "IDBTransactionBackendInterface.h"
namespace WebCore {
-IDBIndex::IDBIndex(PassRefPtr<IDBIndexBackendInterface> backend)
+IDBIndex::IDBIndex(PassRefPtr<IDBIndexBackendInterface> backend, IDBTransactionBackendInterface* transaction)
: m_backend(backend)
+ , m_transaction(transaction)
{
+ ASSERT(m_backend);
+ ASSERT(m_transaction);
}
IDBIndex::~IDBIndex()
{
}
-PassRefPtr<IDBRequest> IDBIndex::openObjectCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction)
+PassRefPtr<IDBRequest> IDBIndex::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_backend->openObjectCursor(keyRange, direction, request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->openCursor(keyRange, direction, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
return request;
}
-PassRefPtr<IDBRequest> IDBIndex::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction)
+PassRefPtr<IDBRequest> IDBIndex::openKeyCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_backend->openCursor(keyRange, direction, request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->openKeyCursor(keyRange, direction, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
return request;
}
-PassRefPtr<IDBRequest> IDBIndex::getObject(ScriptExecutionContext* context, PassRefPtr<IDBKey> key)
+PassRefPtr<IDBRequest> IDBIndex::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_backend->getObject(key, request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->get(key, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
return request;
}
-PassRefPtr<IDBRequest> IDBIndex::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key)
+PassRefPtr<IDBRequest> IDBIndex::getKey(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_backend->get(key, request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_backend->getKey(key, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
return request;
}
diff --git a/WebCore/storage/IDBIndex.h b/WebCore/storage/IDBIndex.h
index 45fcfa1..4a1a666 100644
--- a/WebCore/storage/IDBIndex.h
+++ b/WebCore/storage/IDBIndex.h
@@ -28,6 +28,8 @@
#include "IDBCursor.h"
#include "IDBIndexBackendInterface.h"
+#include "IDBKeyRange.h"
+#include "IDBRequest.h"
#include "PlatformString.h"
#include <wtf/Forward.h>
@@ -37,9 +39,9 @@ namespace WebCore {
class IDBIndex : public RefCounted<IDBIndex> {
public:
- static PassRefPtr<IDBIndex> create(PassRefPtr<IDBIndexBackendInterface> backend)
+ static PassRefPtr<IDBIndex> create(PassRefPtr<IDBIndexBackendInterface> backend, IDBTransactionBackendInterface* transaction)
{
- return adoptRef(new IDBIndex(backend));
+ return adoptRef(new IDBIndex(backend, transaction));
}
~IDBIndex();
@@ -49,15 +51,22 @@ public:
String keyPath() const { return m_backend->keyPath(); }
bool unique() const { return m_backend->unique(); }
- PassRefPtr<IDBRequest> openObjectCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange> = 0, unsigned short direction = IDBCursor::NEXT);
- PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange> = 0, unsigned short direction = IDBCursor::NEXT);
- PassRefPtr<IDBRequest> getObject(ScriptExecutionContext*, PassRefPtr<IDBKey>);
- PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey>);
+ // FIXME: Try to modify the code generator so this is unneeded.
+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, ExceptionCode& ec) { return openCursor(context, 0, ec); }
+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec) { return openCursor(context, keyRange, IDBCursor::NEXT, ec); }
+ PassRefPtr<IDBRequest> openKeyCursor(ScriptExecutionContext* context, ExceptionCode& ec) { return openKeyCursor(context, 0, ec); }
+ PassRefPtr<IDBRequest> openKeyCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec) { return openKeyCursor(context, keyRange, IDBCursor::NEXT, ec); }
+
+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, unsigned short direction, ExceptionCode&);
+ PassRefPtr<IDBRequest> openKeyCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, unsigned short direction, ExceptionCode&);
+ PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey>, ExceptionCode&);
+ PassRefPtr<IDBRequest> getKey(ScriptExecutionContext*, PassRefPtr<IDBKey>, ExceptionCode&);
private:
- IDBIndex(PassRefPtr<IDBIndexBackendInterface>);
+ IDBIndex(PassRefPtr<IDBIndexBackendInterface>, IDBTransactionBackendInterface* transaction);
RefPtr<IDBIndexBackendInterface> m_backend;
+ RefPtr<IDBTransactionBackendInterface> m_transaction;
};
} // namespace WebCore
diff --git a/WebCore/storage/IDBIndex.idl b/WebCore/storage/IDBIndex.idl
index ba3ecea..7c2c962 100644
--- a/WebCore/storage/IDBIndex.idl
+++ b/WebCore/storage/IDBIndex.idl
@@ -33,11 +33,14 @@ module storage {
readonly attribute DOMString keyPath;
readonly attribute boolean unique;
- // FIXME: All of these should raise on certain errors.
- [CallWith=ScriptExecutionContext] IDBRequest openObjectCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction);
- [CallWith=ScriptExecutionContext] IDBRequest openCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction);
- [CallWith=ScriptExecutionContext] IDBRequest getObject(in IDBKey key);
- [CallWith=ScriptExecutionContext] IDBRequest get(in IDBKey key);
+ [CallWith=ScriptExecutionContext] IDBRequest openCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest openKeyCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest get(in IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest getKey(in IDBKey key)
+ raises (IDBDatabaseException);
};
}
diff --git a/WebCore/storage/IDBIndexBackendImpl.cpp b/WebCore/storage/IDBIndexBackendImpl.cpp
index 6f698c6..2a991fa 100644
--- a/WebCore/storage/IDBIndexBackendImpl.cpp
+++ b/WebCore/storage/IDBIndexBackendImpl.cpp
@@ -28,6 +28,7 @@
#if ENABLE(INDEXED_DATABASE)
+#include "CrossThreadTask.h"
#include "IDBCallbacks.h"
#include "IDBCursorBackendImpl.h"
#include "IDBDatabaseBackendImpl.h"
@@ -49,6 +50,15 @@ IDBIndexBackendImpl::IDBIndexBackendImpl(IDBObjectStoreBackendImpl* objectStore,
{
}
+IDBIndexBackendImpl::IDBIndexBackendImpl(IDBObjectStoreBackendImpl* objectStore, const String& name, const String& keyPath, bool unique)
+ : m_objectStore(objectStore)
+ , m_id(InvalidId)
+ , m_name(name)
+ , m_keyPath(keyPath)
+ , m_unique(unique)
+{
+}
+
IDBIndexBackendImpl::~IDBIndexBackendImpl()
{
}
@@ -58,7 +68,7 @@ String IDBIndexBackendImpl::storeName()
return m_objectStore->name();
}
-static void openCursorInternal(SQLiteDatabase& database, IDBIndexBackendImpl* index, IDBKeyRange* range, unsigned short untypedDirection, bool objectCursor, IDBCallbacks* callbacks)
+void IDBIndexBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKeyRange> range, unsigned short untypedDirection, bool objectCursor, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
{
// Several files depend on this order of selects.
String sql = String("SELECT IndexData.id, IndexData.keyString, IndexData.keyDate, IndexData.keyNumber, ")
@@ -80,7 +90,7 @@ static void openCursorInternal(SQLiteDatabase& database, IDBIndexBackendImpl* in
else
sql += "IndexData.keyString DESC, IndexData.keyDate DESC, IndexData.keyNumber DESC, IndexData.id DESC";
- OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(database, sql));
+ OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(index->sqliteDatabase(), sql));
bool ok = query->prepare() == SQLResultOk;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
@@ -96,32 +106,42 @@ static void openCursorInternal(SQLiteDatabase& database, IDBIndexBackendImpl* in
return;
}
- RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(index, range, direction, query.release(), objectCursor);
+ RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(index, range, direction, query.release(), objectCursor, transaction.get());
callbacks->onSuccess(cursor.release());
}
-void IDBIndexBackendImpl::openObjectCursor(PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks)
+void IDBIndexBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
{
- openCursorInternal(sqliteDatabase(), this, keyRange.get(), direction, true, callbacks.get());
+ RefPtr<IDBIndexBackendImpl> index = this;
+ RefPtr<IDBKeyRange> keyRange = prpKeyRange;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, true, callbacks, transaction)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
}
-void IDBIndexBackendImpl::openCursor(PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, PassRefPtr<IDBCallbacks> callbacks)
+void IDBIndexBackendImpl::openKeyCursor(PassRefPtr<IDBKeyRange> prpKeyRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
{
- openCursorInternal(sqliteDatabase(), this, keyRange.get(), direction, false, callbacks.get());
+ RefPtr<IDBIndexBackendImpl> index = this;
+ RefPtr<IDBKeyRange> keyRange = prpKeyRange;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ if (!transaction->scheduleTask(createCallbackTask(&openCursorInternal, index, keyRange, direction, false, callbacks, transaction)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
}
-static void getInternal(SQLiteDatabase& database, int64 id, IDBKey* key, bool getObject, IDBCallbacks* callbacks)
+void IDBIndexBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBKey> key, bool getObject, PassRefPtr<IDBCallbacks> callbacks)
{
String sql = String("SELECT ")
+ (getObject ? "ObjectStoreData.value " : "ObjectStoreData.keyString, ObjectStoreData.keyDate, ObjectStoreData.keyNumber ")
+ "FROM IndexData INNER JOIN ObjectStoreData ON IndexData.objectStoreDataId = ObjectStoreData.id "
+ "WHERE IndexData.indexId = ? AND " + key->whereSyntax("IndexData.")
+ "ORDER BY IndexData.id LIMIT 1"; // Order by insertion order when all else fails.
- SQLiteStatement query(database, sql);
+ SQLiteStatement query(index->sqliteDatabase(), sql);
bool ok = query.prepare() == SQLResultOk;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
- query.bindInt64(1, id);
+ query.bindInt64(1, index->id());
key->bind(query, 2);
if (query.step() != SQLResultRow) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the index."));
@@ -135,14 +155,22 @@ static void getInternal(SQLiteDatabase& database, int64 id, IDBKey* key, bool ge
ASSERT(query.step() != SQLResultRow);
}
-void IDBIndexBackendImpl::getObject(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+void IDBIndexBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
{
- getInternal(sqliteDatabase(), m_id, key.get(), true, callbacks.get());
+ RefPtr<IDBIndexBackendImpl> index = this;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!transaction->scheduleTask(createCallbackTask(&getInternal, index, key, true, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
}
-void IDBIndexBackendImpl::get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+void IDBIndexBackendImpl::getKey(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
{
- getInternal(sqliteDatabase(), m_id, key.get(), false, callbacks.get());
+ RefPtr<IDBIndexBackendImpl> index = this;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!transaction->scheduleTask(createCallbackTask(&getInternal, index, key, false, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
}
static String whereClause(IDBKey* key)
diff --git a/WebCore/storage/IDBIndexBackendImpl.h b/WebCore/storage/IDBIndexBackendImpl.h
index a98ed2a..d5e81ae 100644
--- a/WebCore/storage/IDBIndexBackendImpl.h
+++ b/WebCore/storage/IDBIndexBackendImpl.h
@@ -35,6 +35,7 @@ namespace WebCore {
class IDBKey;
class IDBObjectStoreBackendImpl;
class SQLiteDatabase;
+class ScriptExecutionContext;
class IDBIndexBackendImpl : public IDBIndexBackendInterface {
public:
@@ -42,9 +43,19 @@ public:
{
return adoptRef(new IDBIndexBackendImpl(objectStore, id, name, keyPath, unique));
}
+ static PassRefPtr<IDBIndexBackendImpl> create(IDBObjectStoreBackendImpl* objectStore, const String& name, const String& keyPath, bool unique)
+ {
+ return adoptRef(new IDBIndexBackendImpl(objectStore, name, keyPath, unique));
+ }
virtual ~IDBIndexBackendImpl();
- int64_t id() { return m_id; }
+ int64_t id() const
+ {
+ ASSERT(m_id != InvalidId);
+ return m_id;
+ }
+ void setId(int64_t id) { m_id = id; }
+
bool addingKeyAllowed(IDBKey*);
// Implements IDBIndexBackendInterface.
@@ -53,18 +64,24 @@ public:
virtual String keyPath() { return m_keyPath; }
virtual bool unique() { return m_unique; }
- virtual void openObjectCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>);
- virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>);
- virtual void getObject(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
- virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>);
+ virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void openKeyCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void getKey(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
IDBObjectStoreBackendImpl* objectStore() const { return m_objectStore.get(); }
private:
IDBIndexBackendImpl(IDBObjectStoreBackendImpl*, int64_t id, const String& name, const String& keyPath, bool unique);
+ IDBIndexBackendImpl(IDBObjectStoreBackendImpl*, const String& name, const String& keyPath, bool unique);
SQLiteDatabase& sqliteDatabase() const;
+ static void openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKeyRange>, unsigned short direction, bool objectCursor, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void getInternal(ScriptExecutionContext*, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBKey>, bool getObject, PassRefPtr<IDBCallbacks>);
+
+ static const int64_t InvalidId = 0;
+
RefPtr<IDBObjectStoreBackendImpl> m_objectStore;
int64_t m_id;
diff --git a/WebCore/storage/IDBIndexBackendInterface.h b/WebCore/storage/IDBIndexBackendInterface.h
index ff2316f..e0e578d 100644
--- a/WebCore/storage/IDBIndexBackendInterface.h
+++ b/WebCore/storage/IDBIndexBackendInterface.h
@@ -26,6 +26,7 @@
#ifndef IDBIndexBackendInterface_h
#define IDBIndexBackendInterface_h
+#include "ExceptionCode.h"
#include "PlatformString.h"
#include <wtf/Forward.h>
@@ -36,6 +37,7 @@ namespace WebCore {
class IDBCallbacks;
class IDBKey;
class IDBKeyRange;
+class IDBTransactionBackendInterface;
class IDBIndexBackendInterface : public ThreadSafeShared<IDBIndexBackendInterface> {
public:
@@ -46,10 +48,10 @@ public:
virtual String keyPath() = 0;
virtual bool unique() = 0;
- virtual void openObjectCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>) = 0;
- virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>) = 0;
- virtual void getObject(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>) = 0;
- virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>) = 0;
+ virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void openKeyCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void getKey(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
};
} // namespace WebCore
diff --git a/WebCore/storage/IDBKey.cpp b/WebCore/storage/IDBKey.cpp
index 3eec36c..d0f3c2b 100644
--- a/WebCore/storage/IDBKey.cpp
+++ b/WebCore/storage/IDBKey.cpp
@@ -46,7 +46,7 @@ IDBKey::IDBKey(int32_t number)
IDBKey::IDBKey(const String& string)
: m_type(StringType)
- , m_string(string)
+ , m_string(string.crossThreadString())
{
}
diff --git a/WebCore/storage/IDBKey.h b/WebCore/storage/IDBKey.h
index 3175e7e..0303a38 100644
--- a/WebCore/storage/IDBKey.h
+++ b/WebCore/storage/IDBKey.h
@@ -26,17 +26,18 @@
#ifndef IDBKey_h
#define IDBKey_h
+#if ENABLE(INDEXED_DATABASE)
+
#include "PlatformString.h"
#include <wtf/Forward.h>
-
-#if ENABLE(INDEXED_DATABASE)
+#include <wtf/Threading.h>
namespace WebCore {
class SQLiteStatement;
// FIXME: Add dates.
-class IDBKey : public RefCounted<IDBKey> {
+class IDBKey : public ThreadSafeShared<IDBKey> {
public:
static PassRefPtr<IDBKey> create()
{
@@ -82,6 +83,9 @@ public:
int bind(SQLiteStatement& query, int column) const;
void bindWithNulls(SQLiteStatement& query, int baseColumn) const;
+ using ThreadSafeShared<IDBKey>::ref;
+ using ThreadSafeShared<IDBKey>::deref;
+
private:
IDBKey();
explicit IDBKey(int32_t);
diff --git a/WebCore/storage/IDBKeyRange.h b/WebCore/storage/IDBKeyRange.h
index 4621a50..d246ebc 100644
--- a/WebCore/storage/IDBKeyRange.h
+++ b/WebCore/storage/IDBKeyRange.h
@@ -30,11 +30,11 @@
#include "IDBKey.h"
#include <wtf/PassRefPtr.h>
-#include <wtf/RefCounted.h>
+#include <wtf/Threading.h>
namespace WebCore {
-class IDBKeyRange : public RefCounted<IDBKeyRange> {
+class IDBKeyRange : public ThreadSafeShared<IDBKeyRange> {
public:
// Keep in sync with what's in the .idl file.
enum Flags {
diff --git a/WebCore/storage/IDBKeyTree.h b/WebCore/storage/IDBKeyTree.h
deleted file mode 100644
index 70d6f83..0000000
--- a/WebCore/storage/IDBKeyTree.h
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2010 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- *
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
- * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
- * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
- * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-#ifndef IDBKeyTree_h
-#define IDBKeyTree_h
-
-#if ENABLE(INDEXED_DATABASE)
-
-#include "IDBKey.h"
-#include <wtf/AVLTree.h>
-#include <wtf/Vector.h>
-
-namespace WebCore {
-
-template <typename ValueType>
-class IDBKeyTree : public RefCounted<IDBKeyTree<ValueType> > {
-public:
- static PassRefPtr<IDBKeyTree> create()
- {
- return adoptRef(new IDBKeyTree());
- }
- ~IDBKeyTree();
-
- ValueType* get(IDBKey* key);
- void put(IDBKey* key, ValueType* value);
- void remove(IDBKey* key);
-
-private:
- struct TreeNode {
- RefPtr<ValueType> value;
- RefPtr<IDBKey> key;
-
- TreeNode* less;
- TreeNode* greater;
- int balanceFactor;
- };
-
- struct AVLTreeAbstractor {
- typedef TreeNode* handle;
- typedef size_t size;
- typedef IDBKey* key;
-
- handle get_less(handle h) { return h->less; }
- void set_less(handle h, handle lh) { h->less = lh; }
- handle get_greater(handle h) { return h->greater; }
- void set_greater(handle h, handle gh) { h->greater = gh; }
- int get_balance_factor(handle h) { return h->balanceFactor; }
- void set_balance_factor(handle h, int bf) { h->balanceFactor = bf; }
-
- static handle null() { return 0; }
-
- int compare_key_key(key va, key vb);
- int compare_key_node(key k, handle h) { return compare_key_key(k, h->key.get()); }
- int compare_node_node(handle h1, handle h2) { return compare_key_key(h1->key.get(), h2->key.get()); }
- };
-
- IDBKeyTree();
-
- typedef WTF::AVLTree<AVLTreeAbstractor> TreeType;
- TreeType m_tree;
-};
-
-template <typename ValueType>
-IDBKeyTree<ValueType>::IDBKeyTree()
-{
-}
-
-template <typename ValueType>
-IDBKeyTree<ValueType>::~IDBKeyTree()
-{
- typename TreeType::Iterator iter;
- iter.start_iter_least(m_tree);
- for (; *iter; ++iter)
- delete *iter;
- m_tree.purge();
-}
-
-template <typename ValueType>
-int IDBKeyTree<ValueType>::AVLTreeAbstractor::compare_key_key(key va, key vb)
-{
- if (va->type() != vb->type())
- return vb->type() - va->type();
-
- switch (va->type()) {
- case IDBKey::NullType:
- return 0;
- case IDBKey::NumberType:
- return vb->number() - va->number();
- case IDBKey::StringType:
- return codePointCompare(va->string(), vb->string());
- // FIXME: Handle dates. Oh, and test this thoroughly.
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
-}
-
-template <typename ValueType>
-ValueType* IDBKeyTree<ValueType>::get(IDBKey* key)
-{
- TreeNode* node = m_tree.search(key);
- if (!node)
- return 0;
- return node->value.get();
-}
-
-template <typename ValueType>
-void IDBKeyTree<ValueType>::put(IDBKey* key, ValueType* value)
-{
- TreeNode* node = m_tree.search(key);
- if (!node) {
- node = new TreeNode();
- node->key = key;
- m_tree.insert(node);
- }
- node->value = value;
-}
-
-template <typename ValueType>
-void IDBKeyTree<ValueType>::remove(IDBKey* key)
-{
- TreeNode* node = m_tree.remove(key);
- if (node)
- delete node;
-}
-
-}
-
-#endif // ENABLE(INDEXED_DATABASE)
-
-#endif // IDBKeyTree_h
diff --git a/WebCore/storage/IDBObjectStore.cpp b/WebCore/storage/IDBObjectStore.cpp
index 4c5cf34..c30243e 100644
--- a/WebCore/storage/IDBObjectStore.cpp
+++ b/WebCore/storage/IDBObjectStore.cpp
@@ -43,6 +43,8 @@ IDBObjectStore::IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface> idbObj
: m_objectStore(idbObjectStore)
, m_transaction(transaction)
{
+ ASSERT(m_objectStore);
+ ASSERT(m_transaction);
// We pass a reference to this object before it can be adopted.
relaxAdoptionRequirement();
}
@@ -62,61 +64,71 @@ PassRefPtr<DOMStringList> IDBObjectStore::indexNames() const
return m_objectStore->indexNames();
}
-PassRefPtr<IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key)
+PassRefPtr<IDBRequest> IDBObjectStore::get(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
{
RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
- m_objectStore->get(key, request, m_transaction.get());
+ m_objectStore->get(key, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
return request.release();
}
-PassRefPtr<IDBRequest> IDBObjectStore::add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key)
+PassRefPtr<IDBRequest> IDBObjectStore::add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_objectStore->put(value, key, true, request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_objectStore->put(value, key, true, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
return request;
}
-PassRefPtr<IDBRequest> IDBObjectStore::put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key)
+PassRefPtr<IDBRequest> IDBObjectStore::put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_objectStore->put(value, key, false, request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_objectStore->put(value, key, false, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
return request;
}
-PassRefPtr<IDBRequest> IDBObjectStore::remove(ScriptExecutionContext* context, PassRefPtr<IDBKey> key)
+PassRefPtr<IDBRequest> IDBObjectStore::remove(ScriptExecutionContext* context, PassRefPtr<IDBKey> key, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_objectStore->remove(key, request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_objectStore->remove(key, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
return request;
}
-PassRefPtr<IDBRequest> IDBObjectStore::createIndex(ScriptExecutionContext* context, const String& name, const String& keyPath, bool unique)
+PassRefPtr<IDBIndex> IDBObjectStore::createIndex(const String& name, const String& keyPath, bool unique, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_objectStore->createIndex(name, keyPath, unique, request);
- return request;
+ RefPtr<IDBIndexBackendInterface> index = m_objectStore->createIndex(name, keyPath, unique, m_transaction.get(), ec);
+ ASSERT(!index != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa.
+ if (!index)
+ return 0;
+ return IDBIndex::create(index.release(), m_transaction.get());
}
-PassRefPtr<IDBIndex> IDBObjectStore::index(const String& name)
+PassRefPtr<IDBIndex> IDBObjectStore::index(const String& name, ExceptionCode& ec)
{
- // FIXME: If this is null, we should raise a NOT_FOUND_ERR.
- RefPtr<IDBIndexBackendInterface> index = m_objectStore->index(name);
+ RefPtr<IDBIndexBackendInterface> index = m_objectStore->index(name, ec);
+ ASSERT(!index != !ec); // If we didn't get an index, we should have gotten an exception code. And vice versa.
if (!index)
return 0;
- return IDBIndex::create(index.release());
+ return IDBIndex::create(index.release(), m_transaction.get());
}
-PassRefPtr<IDBRequest> IDBObjectStore::removeIndex(ScriptExecutionContext* context, const String& name)
+void IDBObjectStore::removeIndex(const String& name, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_objectStore->removeIndex(name, request);
- return request;
+ m_objectStore->removeIndex(name, m_transaction.get(), ec);
}
-PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, unsigned short direction)
+PassRefPtr<IDBRequest> IDBObjectStore::openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> range, unsigned short direction, ExceptionCode& ec)
{
- RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this));
- m_objectStore->openCursor(range, direction, request);
+ RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
+ m_objectStore->openCursor(range, direction, request, m_transaction.get(), ec);
+ if (ec)
+ return 0;
return request.release();
}
diff --git a/WebCore/storage/IDBObjectStore.h b/WebCore/storage/IDBObjectStore.h
index df5b3f7..dc92233 100644
--- a/WebCore/storage/IDBObjectStore.h
+++ b/WebCore/storage/IDBObjectStore.h
@@ -27,10 +27,13 @@
#define IDBObjectStore_h
#include "IDBCursor.h"
+#include "IDBIndex.h"
+#include "IDBKey.h"
#include "IDBKeyRange.h"
#include "IDBObjectStoreBackendInterface.h"
#include "IDBRequest.h"
#include "PlatformString.h"
+#include "SerializedScriptValue.h"
#include <wtf/PassRefPtr.h>
#include <wtf/RefCounted.h>
#include <wtf/RefPtr.h>
@@ -41,10 +44,7 @@ namespace WebCore {
class DOMStringList;
class IDBAny;
-class IDBIndexRequest;
-class IDBKey;
class IDBTransactionBackendInterface;
-class SerializedScriptValue;
class IDBObjectStore : public RefCounted<IDBObjectStore> {
public:
@@ -58,16 +58,23 @@ public:
String keyPath() const;
PassRefPtr<DOMStringList> indexNames() const;
- PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey> key);
- PassRefPtr<IDBRequest> add(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key = 0);
- PassRefPtr<IDBRequest> put(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key = 0);
- PassRefPtr<IDBRequest> remove(ScriptExecutionContext*, PassRefPtr<IDBKey> key);
+ // FIXME: Try to modify the code generator so this is unneeded.
+ PassRefPtr<IDBRequest> add(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, ExceptionCode& ec) { return add(context, value, 0, ec); }
+ PassRefPtr<IDBRequest> put(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> value, ExceptionCode& ec) { return put(context, value, 0, ec); }
+ PassRefPtr<IDBIndex> createIndex(const String& name, const String& keyPath, ExceptionCode& ec) { return createIndex(name, keyPath, false, ec); }
+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, ExceptionCode& ec) { return openCursor(context, 0, ec); }
+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext* context, PassRefPtr<IDBKeyRange> keyRange, ExceptionCode& ec) { return openCursor(context, keyRange, IDBCursor::NEXT, ec); }
- PassRefPtr<IDBRequest> createIndex(ScriptExecutionContext*, const String& name, const String& keyPath, bool unique = false);
- PassRefPtr<IDBIndex> index(const String& name);
- PassRefPtr<IDBRequest> removeIndex(ScriptExecutionContext*, const String& name);
+ PassRefPtr<IDBRequest> get(ScriptExecutionContext*, PassRefPtr<IDBKey>, ExceptionCode&);
+ PassRefPtr<IDBRequest> add(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, ExceptionCode&);
+ PassRefPtr<IDBRequest> put(ScriptExecutionContext*, PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, ExceptionCode&);
+ PassRefPtr<IDBRequest> remove(ScriptExecutionContext*, PassRefPtr<IDBKey> key, ExceptionCode&);
- PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange> = 0, unsigned short direction = IDBCursor::NEXT);
+ PassRefPtr<IDBIndex> createIndex(const String& name, const String& keyPath, bool unique, ExceptionCode&);
+ PassRefPtr<IDBIndex> index(const String& name, ExceptionCode&);
+ void removeIndex(const String& name, ExceptionCode&);
+
+ PassRefPtr<IDBRequest> openCursor(ScriptExecutionContext*, PassRefPtr<IDBKeyRange>, unsigned short direction, ExceptionCode&);
private:
IDBObjectStore(PassRefPtr<IDBObjectStoreBackendInterface>, IDBTransactionBackendInterface* transaction);
diff --git a/WebCore/storage/IDBObjectStore.idl b/WebCore/storage/IDBObjectStore.idl
index ccd0311..31eb865 100644
--- a/WebCore/storage/IDBObjectStore.idl
+++ b/WebCore/storage/IDBObjectStore.idl
@@ -28,21 +28,25 @@ module storage {
interface [
Conditional=INDEXED_DATABASE
] IDBObjectStore {
- // FIXME: Many of these should raise on certain errors.
- [CallWith=ScriptExecutionContext] IDBRequest get(in IDBKey key);
- [CallWith=ScriptExecutionContext] IDBRequest add(in SerializedScriptValue value, in [Optional] IDBKey key);
- [CallWith=ScriptExecutionContext] IDBRequest put(in SerializedScriptValue value, in [Optional] IDBKey key);
- [CallWith=ScriptExecutionContext] IDBRequest remove(in IDBKey key);
- // FIXME: write openCursor
- [CallWith=ScriptExecutionContext] IDBRequest createIndex(in DOMString name, in [ConvertNullToNullString] DOMString keyPath, in [Optional] boolean unique);
- // FIXME: This needs to raise an IDBDatabaseException on errors.
- IDBIndex index(in DOMString name);
- [CallWith=ScriptExecutionContext] IDBRequest removeIndex(in DOMString name);
-
- [CallWith=ScriptExecutionContext] IDBRequest openCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction);
-
readonly attribute DOMString name;
readonly attribute [ConvertNullStringTo=Null] DOMString keyPath;
readonly attribute DOMStringList indexNames;
+
+ [CallWith=ScriptExecutionContext] IDBRequest put(in SerializedScriptValue value, in [Optional] IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest add(in SerializedScriptValue value, in [Optional] IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest remove(in IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest get(in IDBKey key)
+ raises (IDBDatabaseException);
+ [CallWith=ScriptExecutionContext] IDBRequest openCursor(in [Optional] IDBKeyRange range, in [Optional] unsigned short direction)
+ raises (IDBDatabaseException);
+ IDBIndex createIndex(in DOMString name, in [ConvertNullToNullString] DOMString keyPath, in [Optional] boolean unique)
+ raises (IDBDatabaseException);
+ IDBIndex index(in DOMString name)
+ raises (IDBDatabaseException);
+ void removeIndex(in DOMString name)
+ raises (IDBDatabaseException);
};
}
diff --git a/WebCore/storage/IDBObjectStoreBackendImpl.cpp b/WebCore/storage/IDBObjectStoreBackendImpl.cpp
index 18d6b0c..f3aee91 100644
--- a/WebCore/storage/IDBObjectStoreBackendImpl.cpp
+++ b/WebCore/storage/IDBObjectStoreBackendImpl.cpp
@@ -26,6 +26,9 @@
#include "config.h"
#include "IDBObjectStoreBackendImpl.h"
+#if ENABLE(INDEXED_DATABASE)
+
+#include "CrossThreadTask.h"
#include "DOMStringList.h"
#include "IDBBindingUtilities.h"
#include "IDBCallbacks.h"
@@ -33,6 +36,7 @@
#include "IDBDatabaseBackendImpl.h"
#include "IDBDatabaseException.h"
#include "IDBIndexBackendImpl.h"
+#include "IDBKey.h"
#include "IDBKeyPath.h"
#include "IDBKeyPathBackendImpl.h"
#include "IDBKeyRange.h"
@@ -42,37 +46,8 @@
#include "SQLiteStatement.h"
#include "SQLiteTransaction.h"
-#if ENABLE(INDEXED_DATABASE)
-
namespace WebCore {
-template <class T, class Method, class Param1, class Param2>
-class IDBTask : public ScriptExecutionContext::Task {
-public:
- IDBTask(T* obj, Method method, const Param1& param1, const Param2& param2)
- : m_obj(obj), m_method(method), m_param1(param1), m_param2(param2)
- {
- }
-
- virtual void performTask(ScriptExecutionContext*)
- {
- if (m_obj)
- (m_obj->*m_method)(m_param1, m_param2);
- }
-
-private:
- T* m_obj;
- Method m_method;
- Param1 m_param1;
- Param2 m_param2;
-};
-
-template <class T, class Method, class Param1, class Param2>
-PassOwnPtr<ScriptExecutionContext::Task> createTask(T* object, Method method, const Param1& param1, const Param2& param2)
-{
- return adoptPtr(new IDBTask<T, Method, Param1, Param2>(object, method, param1, param2));
-}
-
IDBObjectStoreBackendImpl::~IDBObjectStoreBackendImpl()
{
}
@@ -87,6 +62,15 @@ IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBDatabaseBackendImpl* dat
loadIndexes();
}
+IDBObjectStoreBackendImpl::IDBObjectStoreBackendImpl(IDBDatabaseBackendImpl* database, const String& name, const String& keyPath, bool autoIncrement)
+ : m_database(database)
+ , m_id(InvalidId)
+ , m_name(name)
+ , m_keyPath(keyPath)
+ , m_autoIncrement(autoIncrement)
+{
+}
+
PassRefPtr<DOMStringList> IDBObjectStoreBackendImpl::indexNames() const
{
RefPtr<DOMStringList> indexNames = DOMStringList::create();
@@ -106,19 +90,22 @@ static void bindWhereClause(SQLiteStatement& query, int64_t id, IDBKey* key)
key->bind(query, 2);
}
-void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks, IDBTransactionBackendInterface* transaction)
+void IDBObjectStoreBackendImpl::get(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
{
- if (!transaction->scheduleTask(createTask(this, &IDBObjectStoreBackendImpl::getInternal, key, callbacks)))
- callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_ALLOWED_ERR, "Get must be called in the context of a transaction."));
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::getInternal, objectStore, key, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
}
-void IDBObjectStoreBackendImpl::getInternal(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+void IDBObjectStoreBackendImpl::getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
{
- SQLiteStatement query(sqliteDatabase(), "SELECT keyString, keyDate, keyNumber, value FROM ObjectStoreData " + whereClause(key.get()));
+ SQLiteStatement query(objectStore->sqliteDatabase(), "SELECT keyString, keyDate, keyNumber, value FROM ObjectStoreData " + whereClause(key.get()));
bool ok = query.prepare() == SQLResultOk;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
- bindWhereClause(query, m_id, key.get());
+ bindWhereClause(query, objectStore->id(), key.get());
if (query.step() != SQLResultRow) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store."));
return;
@@ -144,13 +131,13 @@ static PassRefPtr<IDBKey> fetchKeyFromKeyPath(SerializedScriptValue* value, cons
return keys[0].release();
}
-static void putObjectStoreData(SQLiteDatabase& db, IDBKey* key, SerializedScriptValue* value, int64_t objectStoreId, int64_t* dataRowId)
+static bool putObjectStoreData(SQLiteDatabase& db, IDBKey* key, SerializedScriptValue* value, int64_t objectStoreId, int64_t* dataRowId)
{
String sql = *dataRowId != -1 ? "UPDATE ObjectStoreData SET keyString = ?, keyDate = ?, keyNumber = ?, value = ? WHERE id = ?"
: "INSERT INTO ObjectStoreData (keyString, keyDate, keyNumber, value, objectStoreId) VALUES (?, ?, ?, ?, ?)";
SQLiteStatement query(db, sql);
- bool ok = query.prepare() == SQLResultOk;
- ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+ if (query.prepare() != SQLResultOk)
+ return false;
key->bindWithNulls(query, 1);
query.bindText(4, value->toWireString());
if (*dataRowId != -1)
@@ -158,44 +145,63 @@ static void putObjectStoreData(SQLiteDatabase& db, IDBKey* key, SerializedScript
else
query.bindInt64(5, objectStoreId);
- ok = query.step() == SQLResultDone;
- ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+ if (query.step() != SQLResultDone)
+ return false;
if (*dataRowId == -1)
*dataRowId = db.lastInsertRowID();
+
+ return true;
}
-static void putIndexData(SQLiteDatabase& db, IDBKey* key, int64_t indexId, int64_t objectStoreDataId)
+static bool deleteIndexData(SQLiteDatabase& db, int64_t objectStoreDataId)
{
SQLiteStatement deleteQuery(db, "DELETE FROM IndexData WHERE objectStoreDataId = ?");
- bool ok = deleteQuery.prepare() == SQLResultOk;
- ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
+ if (deleteQuery.prepare() != SQLResultOk)
+ return false;
deleteQuery.bindInt64(1, objectStoreDataId);
- ok = deleteQuery.step() == SQLResultDone;
- ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
+ return deleteQuery.step() == SQLResultDone;
+}
+
+static bool putIndexData(SQLiteDatabase& db, IDBKey* key, int64_t indexId, int64_t objectStoreDataId)
+{
SQLiteStatement putQuery(db, "INSERT INTO IndexData (keyString, keyDate, keyNumber, indexId, objectStoreDataId) VALUES (?, ?, ?, ?, ?)");
- ok = putQuery.prepare() == SQLResultOk;
- ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+ if (putQuery.prepare() != SQLResultOk)
+ return false;
key->bindWithNulls(putQuery, 1);
putQuery.bindInt64(4, indexId);
putQuery.bindInt64(5, objectStoreDataId);
- ok = putQuery.step() == SQLResultDone;
- ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
+ return putQuery.step() == SQLResultDone;
+}
+
+void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
+{
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<SerializedScriptValue> value = prpValue;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ // FIXME: This should throw a SERIAL_ERR on structured clone problems.
+ // FIXME: This should throw a DATA_ERR when the wrong key/keyPath data is supplied.
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::putInternal, objectStore, value, key, addOnly, callbacks, transaction)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
}
-void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> callbacks)
+void IDBObjectStoreBackendImpl::putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBKey> prpKey, bool addOnly, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
{
RefPtr<SerializedScriptValue> value = prpValue;
RefPtr<IDBKey> key = prpKey;
- if (!m_keyPath.isNull()) {
+ // FIXME: Support auto-increment.
+
+ if (!objectStore->m_keyPath.isNull()) {
if (key) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "A key was supplied for an objectStore that has a keyPath."));
return;
}
- key = fetchKeyFromKeyPath(value.get(), m_keyPath);
+ key = fetchKeyFromKeyPath(value.get(), objectStore->m_keyPath);
if (!key) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "The key could not be fetched from the keyPath."));
return;
@@ -206,7 +212,7 @@ void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue,
}
Vector<RefPtr<IDBKey> > indexKeys;
- for (IndexMap::iterator it = m_indexes.begin(); it != m_indexes.end(); ++it) {
+ for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it) {
RefPtr<IDBKey> key = fetchKeyFromKeyPath(value.get(), it->second->keyPath());
if (!key) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "The key could not be fetched from an index's keyPath."));
@@ -219,36 +225,63 @@ void IDBObjectStoreBackendImpl::put(PassRefPtr<SerializedScriptValue> prpValue,
indexKeys.append(key.release());
}
- SQLiteStatement getQuery(sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get()));
+ SQLiteStatement getQuery(objectStore->sqliteDatabase(), "SELECT id FROM ObjectStoreData " + whereClause(key.get()));
bool ok = getQuery.prepare() == SQLResultOk;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
- bindWhereClause(getQuery, m_id, key.get());
+ bindWhereClause(getQuery, objectStore->id(), key.get());
bool isExistingValue = getQuery.step() == SQLResultRow;
if (addOnly && isExistingValue) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Key already exists in the object store."));
return;
}
- // Before this point, don't do any mutation. After this point, don't error out.
+ // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
int64_t dataRowId = isExistingValue ? getQuery.getColumnInt(0) : -1;
- putObjectStoreData(sqliteDatabase(), key.get(), value.get(), m_id, &dataRowId);
+ if (!putObjectStoreData(objectStore->sqliteDatabase(), key.get(), value.get(), objectStore->id(), &dataRowId)) {
+ // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
+ transaction->abort();
+ return;
+ }
+
+ if (!deleteIndexData(objectStore->sqliteDatabase(), dataRowId)) {
+ // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
+ transaction->abort();
+ return;
+ }
int i = 0;
- for (IndexMap::iterator it = m_indexes.begin(); it != m_indexes.end(); ++it, ++i)
- putIndexData(sqliteDatabase(), indexKeys[i].get(), it->second->id(), dataRowId);
+ for (IndexMap::iterator it = objectStore->m_indexes.begin(); it != objectStore->m_indexes.end(); ++it, ++i) {
+ if (!putIndexData(objectStore->sqliteDatabase(), indexKeys[i].get(), it->second->id(), dataRowId)) {
+ // FIXME: The Indexed Database specification does not have an error code dedicated to I/O errors.
+ callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Error writing data to stable storage."));
+ transaction->abort();
+ return;
+ }
+ }
callbacks->onSuccess(key.get());
}
-void IDBObjectStoreBackendImpl::remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
+void IDBObjectStoreBackendImpl::remove(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
+{
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<IDBKey> key = prpKey;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::removeInternal, objectStore, key, callbacks)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBObjectStoreBackendImpl::removeInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks> callbacks)
{
- SQLiteStatement query(sqliteDatabase(), "DELETE FROM ObjectStoreData " + whereClause(key.get()));
+ SQLiteStatement query(objectStore->sqliteDatabase(), "DELETE FROM ObjectStoreData " + whereClause(key.get()));
bool ok = query.prepare() == SQLResultOk;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
- bindWhereClause(query, m_id, key.get());
+ bindWhereClause(query, objectStore->id(), key.get());
if (query.step() != SQLResultDone) {
callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Key does not exist in the object store."));
return;
@@ -257,33 +290,60 @@ void IDBObjectStoreBackendImpl::remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCal
callbacks->onSuccess();
}
-void IDBObjectStoreBackendImpl::createIndex(const String& name, const String& keyPath, bool unique, PassRefPtr<IDBCallbacks> callbacks)
+PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::createIndex(const String& name, const String& keyPath, bool unique, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
{
if (m_indexes.contains(name)) {
- callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::CONSTRAINT_ERR, "Index name already exists."));
- return;
+ ec = IDBDatabaseException::CONSTRAINT_ERR;
+ return 0;
+ }
+ if (transaction->mode() != IDBTransaction::VERSION_CHANGE) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return 0;
}
- SQLiteStatement insert(sqliteDatabase(), "INSERT INTO Indexes (objectStoreId, name, keyPath, isUnique) VALUES (?, ?, ?, ?)");
- bool ok = insert.prepare() == SQLResultOk;
- ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
- insert.bindInt64(1, m_id);
- insert.bindText(2, name);
- insert.bindText(3, keyPath);
- insert.bindInt(4, static_cast<int>(unique));
- ok = insert.step() == SQLResultDone;
- ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
- int64_t id = sqliteDatabase().lastInsertRowID();
-
- RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(this, id, name, keyPath, unique);
+ RefPtr<IDBIndexBackendImpl> index = IDBIndexBackendImpl::create(this, name, keyPath, unique);
ASSERT(index->name() == name);
+
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::createIndexInternal, objectStore, index, transaction),
+ createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexFromMap, objectStore, index))) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return 0;
+ }
+
m_indexes.set(name, index);
- callbacks->onSuccess(index.get());
+ return index.release();
}
-PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name)
+void IDBObjectStoreBackendImpl::createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
{
- return m_indexes.get(name);
+ SQLiteStatement insert(objectStore->sqliteDatabase(), "INSERT INTO Indexes (objectStoreId, name, keyPath, isUnique) VALUES (?, ?, ?, ?)");
+ if (insert.prepare() != SQLResultOk) {
+ transaction->abort();
+ return;
+ }
+ insert.bindInt64(1, objectStore->m_id);
+ insert.bindText(2, index->name());
+ insert.bindText(3, index->keyPath());
+ insert.bindInt(4, static_cast<int>(index->unique()));
+ if (insert.step() != SQLResultDone) {
+ transaction->abort();
+ return;
+ }
+ int64_t id = objectStore->sqliteDatabase().lastInsertRowID();
+ index->setId(id);
+ transaction->didCompleteTaskEvents();
+}
+
+PassRefPtr<IDBIndexBackendInterface> IDBObjectStoreBackendImpl::index(const String& name, ExceptionCode& ec)
+{
+ RefPtr<IDBIndexBackendInterface> index = m_indexes.get(name);
+ if (!index) {
+ ec = IDBDatabaseException::NOT_FOUND_ERR;
+ return 0;
+ }
+ return index.release();
}
static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id)
@@ -296,25 +356,43 @@ static void doDelete(SQLiteDatabase& db, const char* sql, int64_t id)
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
}
-void IDBObjectStoreBackendImpl::removeIndex(const String& name, PassRefPtr<IDBCallbacks> callbacks)
+void IDBObjectStoreBackendImpl::removeIndex(const String& name, IDBTransactionBackendInterface* transaction, ExceptionCode& ec)
{
RefPtr<IDBIndexBackendImpl> index = m_indexes.get(name);
if (!index) {
- callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::NOT_FOUND_ERR, "Index name does not exist."));
+ ec = IDBDatabaseException::NOT_FOUND_ERR;
return;
}
- SQLiteTransaction transaction(sqliteDatabase());
- transaction.begin();
- doDelete(sqliteDatabase(), "DELETE FROM Indexes WHERE id = ?", index->id());
- doDelete(sqliteDatabase(), "DELETE FROM IndexData WHERE indexId = ?", index->id());
- transaction.commit();
-
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<IDBTransactionBackendInterface> transactionPtr = transaction;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::removeIndexInternal, objectStore, index, transactionPtr),
+ createCallbackTask(&IDBObjectStoreBackendImpl::addIndexToMap, objectStore, index))) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return;
+ }
m_indexes.remove(name);
- callbacks->onSuccess();
}
-void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks)
+void IDBObjectStoreBackendImpl::removeIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index, PassRefPtr<IDBTransactionBackendInterface> transaction)
+{
+ doDelete(objectStore->sqliteDatabase(), "DELETE FROM Indexes WHERE id = ?", index->id());
+ doDelete(objectStore->sqliteDatabase(), "DELETE FROM IndexData WHERE indexId = ?", index->id());
+
+ transaction->didCompleteTaskEvents();
+}
+
+void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> prpRange, unsigned short direction, PassRefPtr<IDBCallbacks> prpCallbacks, IDBTransactionBackendInterface* transactionPtr, ExceptionCode& ec)
+{
+ RefPtr<IDBObjectStoreBackendImpl> objectStore = this;
+ RefPtr<IDBKeyRange> range = prpRange;
+ RefPtr<IDBCallbacks> callbacks = prpCallbacks;
+ RefPtr<IDBTransactionBackendInterface> transaction = transactionPtr;
+ if (!transaction->scheduleTask(createCallbackTask(&IDBObjectStoreBackendImpl::openCursorInternal, objectStore, range, direction, callbacks, transaction)))
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+}
+
+void IDBObjectStoreBackendImpl::openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBKeyRange> range, unsigned short tmpDirection, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBTransactionBackendInterface> transaction)
{
// Several files depend on this order of selects.
String sql = "SELECT id, keyString, keyDate, keyNumber, value FROM ObjectStoreData WHERE ";
@@ -330,7 +408,7 @@ void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> range, unsign
else
sql += "keyString DESC, keyDate DESC, keyNumber DESC";
- OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(sqliteDatabase(), sql));
+ OwnPtr<SQLiteStatement> query = adoptPtr(new SQLiteStatement(objectStore->sqliteDatabase(), sql));
bool ok = query->prepare() == SQLResultOk;
ASSERT_UNUSED(ok, ok); // FIXME: Better error handling?
@@ -339,14 +417,14 @@ void IDBObjectStoreBackendImpl::openCursor(PassRefPtr<IDBKeyRange> range, unsign
currentColumn += range->left()->bind(*query, currentColumn);
if (range->flags() & IDBKeyRange::RIGHT_BOUND || range->flags() == IDBKeyRange::SINGLE)
currentColumn += range->right()->bind(*query, currentColumn);
- query->bindInt64(currentColumn, m_id);
+ query->bindInt64(currentColumn, objectStore->id());
if (query->step() != SQLResultRow) {
callbacks->onSuccess();
return;
}
- RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(this, range, direction, query.release());
+ RefPtr<IDBCursorBackendInterface> cursor = IDBCursorBackendImpl::create(objectStore, range, direction, query.release(), transaction.get());
callbacks->onSuccess(cursor.release());
}
@@ -373,6 +451,20 @@ SQLiteDatabase& IDBObjectStoreBackendImpl::sqliteDatabase() const
return m_database->sqliteDatabase();
}
+void IDBObjectStoreBackendImpl::removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
+{
+ ASSERT(objectStore->m_indexes.contains(index->name()));
+ objectStore->m_indexes.remove(index->name());
+}
+
+void IDBObjectStoreBackendImpl::addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl> objectStore, PassRefPtr<IDBIndexBackendImpl> index)
+{
+ RefPtr<IDBIndexBackendImpl> indexPtr = index;
+ ASSERT(!objectStore->m_indexes.contains(indexPtr->name()));
+ objectStore->m_indexes.set(indexPtr->name(), indexPtr);
+}
+
+
} // namespace WebCore
#endif
diff --git a/WebCore/storage/IDBObjectStoreBackendImpl.h b/WebCore/storage/IDBObjectStoreBackendImpl.h
index 36c0014..09223b1 100644
--- a/WebCore/storage/IDBObjectStoreBackendImpl.h
+++ b/WebCore/storage/IDBObjectStoreBackendImpl.h
@@ -38,6 +38,7 @@ class IDBDatabaseBackendImpl;
class IDBIndexBackendImpl;
class IDBTransactionBackendInterface;
class SQLiteDatabase;
+class ScriptExecutionContext;
class IDBObjectStoreBackendImpl : public IDBObjectStoreBackendInterface {
public:
@@ -45,32 +46,55 @@ public:
{
return adoptRef(new IDBObjectStoreBackendImpl(database, id, name, keyPath, autoIncrement));
}
- ~IDBObjectStoreBackendImpl();
+ static PassRefPtr<IDBObjectStoreBackendImpl> create(IDBDatabaseBackendImpl* database, const String& name, const String& keyPath, bool autoIncrement)
+ {
+ return adoptRef(new IDBObjectStoreBackendImpl(database, name, keyPath, autoIncrement));
+ }
+ virtual ~IDBObjectStoreBackendImpl();
- int64_t id() const { return m_id; }
- String name() const { return m_name; }
- String keyPath() const { return m_keyPath; }
- PassRefPtr<DOMStringList> indexNames() const;
+ int64_t id() const
+ {
+ ASSERT(m_id != InvalidId);
+ return m_id;
+ }
+ void setId(int64_t id) { m_id = id; }
- void get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface* transaction);
- void put(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>);
- void remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>);
+ virtual String name() const { return m_name; }
+ virtual String keyPath() const { return m_keyPath; }
+ virtual PassRefPtr<DOMStringList> indexNames() const;
+ virtual bool autoIncrement() const { return m_autoIncrement; }
- void createIndex(const String& name, const String& keyPath, bool unique, PassRefPtr<IDBCallbacks>);
- PassRefPtr<IDBIndexBackendInterface> index(const String& name);
- void removeIndex(const String& name, PassRefPtr<IDBCallbacks>);
+ virtual void get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void put(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual void remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
- void openCursor(PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks>);
+ virtual PassRefPtr<IDBIndexBackendInterface> createIndex(const String& name, const String& keyPath, bool unique, IDBTransactionBackendInterface*, ExceptionCode&);
+ virtual PassRefPtr<IDBIndexBackendInterface> index(const String& name, ExceptionCode&);
+ virtual void removeIndex(const String& name, IDBTransactionBackendInterface*, ExceptionCode&);
+
+ virtual void openCursor(PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&);
IDBDatabaseBackendImpl* database() const { return m_database.get(); }
private:
IDBObjectStoreBackendImpl(IDBDatabaseBackendImpl*, int64_t id, const String& name, const String& keyPath, bool autoIncrement);
+ IDBObjectStoreBackendImpl(IDBDatabaseBackendImpl*, const String& name, const String& keyPath, bool autoIncrement);
void loadIndexes();
SQLiteDatabase& sqliteDatabase() const;
- void getInternal(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>);
+ static void getInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>);
+ static void putInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void removeInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>);
+ static void createIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void removeIndexInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>, PassRefPtr<IDBTransactionBackendInterface>);
+ static void openCursorInternal(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBKeyRange> range, unsigned short direction, PassRefPtr<IDBCallbacks>, PassRefPtr<IDBTransactionBackendInterface>);
+
+ // These are used as setVersion transaction abort tasks.
+ static void removeIndexFromMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>);
+ static void addIndexToMap(ScriptExecutionContext*, PassRefPtr<IDBObjectStoreBackendImpl>, PassRefPtr<IDBIndexBackendImpl>);
+
+ static const int64_t InvalidId = 0;
RefPtr<IDBDatabaseBackendImpl> m_database;
diff --git a/WebCore/storage/IDBObjectStoreBackendInterface.h b/WebCore/storage/IDBObjectStoreBackendInterface.h
index c19855c..8763d90 100644
--- a/WebCore/storage/IDBObjectStoreBackendInterface.h
+++ b/WebCore/storage/IDBObjectStoreBackendInterface.h
@@ -26,6 +26,7 @@
#ifndef IDBObjectStoreBackendInterface_h
#define IDBObjectStoreBackendInterface_h
+#include "ExceptionCode.h"
#include "PlatformString.h"
#include <wtf/Threading.h>
@@ -49,15 +50,15 @@ public:
virtual String keyPath() const = 0;
virtual PassRefPtr<DOMStringList> indexNames() const = 0;
- virtual void get(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface* transaction) = 0;
- virtual void put(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBKey> key, bool addOnly, PassRefPtr<IDBCallbacks>) = 0;
- virtual void remove(PassRefPtr<IDBKey> key, PassRefPtr<IDBCallbacks>) = 0;
+ virtual void get(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void put(PassRefPtr<SerializedScriptValue>, PassRefPtr<IDBKey>, bool addOnly, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual void remove(PassRefPtr<IDBKey>, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
- virtual void createIndex(const String& name, const String& keyPath, bool unique, PassRefPtr<IDBCallbacks>) = 0;
- virtual PassRefPtr<IDBIndexBackendInterface> index(const String& name) = 0;
- virtual void removeIndex(const String& name, PassRefPtr<IDBCallbacks>) = 0;
+ virtual PassRefPtr<IDBIndexBackendInterface> createIndex(const String& name, const String& keyPath, bool unique, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
+ virtual PassRefPtr<IDBIndexBackendInterface> index(const String& name, ExceptionCode&) = 0;
+ virtual void removeIndex(const String& name, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
- virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>) = 0;
+ virtual void openCursor(PassRefPtr<IDBKeyRange>, unsigned short direction, PassRefPtr<IDBCallbacks>, IDBTransactionBackendInterface*, ExceptionCode&) = 0;
};
} // namespace WebCore
diff --git a/WebCore/storage/IDBRequest.cpp b/WebCore/storage/IDBRequest.cpp
index c672642..c67e379 100644
--- a/WebCore/storage/IDBRequest.cpp
+++ b/WebCore/storage/IDBRequest.cpp
@@ -53,8 +53,8 @@ IDBRequest::IDBRequest(ScriptExecutionContext* context, PassRefPtr<IDBAny> sourc
, m_timer(this, &IDBRequest::timerFired)
, m_readyState(LOADING)
{
- if (transaction)
- IDBPendingTransactionMonitor::removePendingTransaction(transaction);
+ if (m_transaction)
+ IDBPendingTransactionMonitor::removePendingTransaction(m_transaction.get());
}
IDBRequest::~IDBRequest()
@@ -70,10 +70,13 @@ IDBRequest::~IDBRequest()
ASSERT(!m_transaction);
}
-bool IDBRequest::resetReadyState()
+bool IDBRequest::resetReadyState(IDBTransactionBackendInterface* transaction)
{
ASSERT(m_readyState == DONE);
m_readyState = LOADING;
+ ASSERT(!m_transaction);
+ m_transaction = transaction;
+ IDBPendingTransactionMonitor::removePendingTransaction(m_transaction.get());
return true;
}
@@ -89,7 +92,7 @@ void IDBRequest::onSuccess()
void IDBRequest::onSuccess(PassRefPtr<IDBCursorBackendInterface> backend)
{
- scheduleEvent(IDBAny::create(IDBCursor::create(backend, this)), 0);
+ scheduleEvent(IDBAny::create(IDBCursor::create(backend, this, m_transaction.get())), 0);
}
void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
@@ -99,7 +102,7 @@ void IDBRequest::onSuccess(PassRefPtr<IDBDatabaseBackendInterface> backend)
void IDBRequest::onSuccess(PassRefPtr<IDBIndexBackendInterface> backend)
{
- scheduleEvent(IDBAny::create(IDBIndex::create(backend)), 0);
+ scheduleEvent(IDBAny::create(IDBIndex::create(backend, m_transaction.get())), 0);
}
void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
@@ -109,9 +112,20 @@ void IDBRequest::onSuccess(PassRefPtr<IDBKey> idbKey)
void IDBRequest::onSuccess(PassRefPtr<IDBObjectStoreBackendInterface> backend)
{
- // FIXME: the transaction pointer should be the one of the setVersion transaction. This is because
- // this callback is only executed for operations that neen to run in a setVersion transaction.
- scheduleEvent(IDBAny::create(IDBObjectStore::create(backend, 0)), 0);
+ // FIXME: This function should go away once createObjectStore is sync.
+ scheduleEvent(IDBAny::create(IDBObjectStore::create(backend, m_transaction.get())), 0);
+}
+
+void IDBRequest::onSuccess(PassRefPtr<IDBTransactionBackendInterface> prpBackend)
+{
+ RefPtr<IDBTransactionBackendInterface> backend = prpBackend;
+ // This is only used by setVersion which will always have a source that's an IDBDatabase.
+ m_source->idbDatabase()->setSetVersionTransaction(backend.get());
+ RefPtr<IDBTransaction> frontend = IDBTransaction::create(scriptExecutionContext(), backend, m_source->idbDatabase().get());
+ backend->setCallbacks(frontend.get());
+ m_transaction = backend;
+ IDBPendingTransactionMonitor::removePendingTransaction(m_transaction.get());
+ scheduleEvent(IDBAny::create(frontend.release()), 0);
}
void IDBRequest::onSuccess(PassRefPtr<SerializedScriptValue> serializedScriptValue)
@@ -151,6 +165,10 @@ void IDBRequest::timerFired(Timer<IDBRequest>*)
// need to make sure that resume() doesn't re-start the timer based on m_selfRef being set.
RefPtr<IDBRequest> selfRef = m_selfRef.release();
+ // readyStateReset can be called synchronously while we're dispatching the event.
+ RefPtr<IDBTransactionBackendInterface> transaction = m_transaction;
+ m_transaction.clear();
+
Vector<PendingEvent> pendingEvents;
pendingEvents.swap(m_pendingEvents);
for (size_t i = 0; i < pendingEvents.size(); ++i) {
@@ -162,12 +180,11 @@ void IDBRequest::timerFired(Timer<IDBRequest>*)
dispatchEvent(IDBSuccessEvent::create(m_source, pendingEvents[i].m_result));
}
}
- if (m_transaction) {
+ if (transaction) {
// Now that we processed all pending events, let the transaction monitor check if
// it can commit the current transaction or if there's anything new pending.
// FIXME: Handle the workers case.
- m_transaction->didCompleteTaskEvents();
- m_transaction.clear();
+ transaction->didCompleteTaskEvents();
}
}
diff --git a/WebCore/storage/IDBRequest.h b/WebCore/storage/IDBRequest.h
index 75cd9a8..fa68208 100644
--- a/WebCore/storage/IDBRequest.h
+++ b/WebCore/storage/IDBRequest.h
@@ -46,7 +46,7 @@ class IDBTransactionBackendInterface;
class IDBRequest : public IDBCallbacks, public EventTarget, public ActiveDOMObject {
public:
- static PassRefPtr<IDBRequest> create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface* transaction = 0) { return adoptRef(new IDBRequest(context, source, transaction)); }
+ static PassRefPtr<IDBRequest> create(ScriptExecutionContext* context, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface* transaction) { return adoptRef(new IDBRequest(context, source, transaction)); }
virtual ~IDBRequest();
// Defined in the IDL
@@ -58,7 +58,7 @@ public:
DEFINE_ATTRIBUTE_EVENT_LISTENER(success);
DEFINE_ATTRIBUTE_EVENT_LISTENER(error);
- bool resetReadyState();
+ bool resetReadyState(IDBTransactionBackendInterface*);
// IDBCallbacks
virtual void onError(PassRefPtr<IDBDatabaseError>);
@@ -68,6 +68,7 @@ public:
virtual void onSuccess(PassRefPtr<IDBIndexBackendInterface>);
virtual void onSuccess(PassRefPtr<IDBKey>);
virtual void onSuccess(PassRefPtr<IDBObjectStoreBackendInterface>);
+ virtual void onSuccess(PassRefPtr<IDBTransactionBackendInterface>);
virtual void onSuccess(PassRefPtr<SerializedScriptValue>);
// EventTarget
@@ -77,8 +78,8 @@ public:
virtual ScriptExecutionContext* scriptExecutionContext() const;
virtual bool canSuspend() const;
- using RefCounted<IDBCallbacks>::ref;
- using RefCounted<IDBCallbacks>::deref;
+ using ThreadSafeShared<IDBCallbacks>::ref;
+ using ThreadSafeShared<IDBCallbacks>::deref;
private:
IDBRequest(ScriptExecutionContext*, PassRefPtr<IDBAny> source, IDBTransactionBackendInterface* transaction);
diff --git a/WebCore/storage/IDBTimeoutEvent.cpp b/WebCore/storage/IDBTimeoutEvent.cpp
new file mode 100644
index 0000000..b61ee47
--- /dev/null
+++ b/WebCore/storage/IDBTimeoutEvent.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "IDBTimeoutEvent.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "EventNames.h"
+#include "IDBAny.h"
+
+namespace WebCore {
+
+PassRefPtr<IDBTimeoutEvent> IDBTimeoutEvent::create()
+{
+ return adoptRef(new IDBTimeoutEvent());
+}
+
+IDBTimeoutEvent::IDBTimeoutEvent()
+ : IDBEvent(eventNames().abortEvent, 0) // FIXME: set the source to the transaction
+{
+}
+
+IDBTimeoutEvent::~IDBTimeoutEvent()
+{
+}
+
+} // namespace WebCore
+
+#endif
diff --git a/WebCore/storage/IDBTimeoutEvent.h b/WebCore/storage/IDBTimeoutEvent.h
new file mode 100644
index 0000000..afc9ba4
--- /dev/null
+++ b/WebCore/storage/IDBTimeoutEvent.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef IDBTimeoutEvent_h
+#define IDBTimeoutEvent_h
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "IDBEvent.h"
+#include "PlatformString.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace WebCore {
+
+class IDBTimeoutEvent : public IDBEvent {
+public:
+ static PassRefPtr<IDBTimeoutEvent> create();
+ // FIXME: Need to allow creation of these events from JS.
+ virtual ~IDBTimeoutEvent();
+
+ virtual bool isIDBTimeoutEvent() const { return true; }
+
+private:
+ IDBTimeoutEvent();
+};
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)
+
+#endif // IDBTimeoutEvent_h
diff --git a/WebCore/storage/IDBTransaction.cpp b/WebCore/storage/IDBTransaction.cpp
index a223b7f..334c001 100644
--- a/WebCore/storage/IDBTransaction.cpp
+++ b/WebCore/storage/IDBTransaction.cpp
@@ -31,11 +31,14 @@
#include "Event.h"
#include "EventException.h"
#include "IDBAbortEvent.h"
+#include "IDBCompleteEvent.h"
#include "IDBDatabase.h"
#include "IDBDatabaseException.h"
+#include "IDBIndex.h"
#include "IDBObjectStore.h"
#include "IDBObjectStoreBackendInterface.h"
#include "IDBPendingTransactionMonitor.h"
+#include "IDBTimeoutEvent.h"
#include "ScriptExecutionContext.h"
namespace WebCore {
@@ -44,8 +47,10 @@ IDBTransaction::IDBTransaction(ScriptExecutionContext* context, PassRefPtr<IDBTr
: ActiveDOMObject(context, this)
, m_backend(backend)
, m_database(db)
- , m_stopped(false)
- , m_timer(this, &IDBTransaction::timerFired)
+ , m_mode(m_backend->mode())
+ , m_onAbortTimer(this, &IDBTransaction::onAbortTimerFired)
+ , m_onCompleteTimer(this, &IDBTransaction::onCompleteTimerFired)
+ , m_onTimeoutTimer(this, &IDBTransaction::onTimeoutTimerFired)
{
IDBPendingTransactionMonitor::addPendingTransaction(m_backend.get());
}
@@ -56,7 +61,7 @@ IDBTransaction::~IDBTransaction()
unsigned short IDBTransaction::mode() const
{
- return m_backend->mode();
+ return m_mode;
}
IDBDatabase* IDBTransaction::db()
@@ -64,11 +69,15 @@ IDBDatabase* IDBTransaction::db()
return m_database.get();
}
-PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, const ExceptionCode&)
+PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, ExceptionCode& ec)
{
+ if (!m_backend) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return 0;
+ }
RefPtr<IDBObjectStoreBackendInterface> objectStoreBackend = m_backend->objectStore(name);
if (!objectStoreBackend) {
- // FIXME: throw IDBDatabaseException::NOT_ALLOWED_ERR.
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
return 0;
}
RefPtr<IDBObjectStore> objectStore = IDBObjectStore::create(objectStoreBackend, m_backend.get());
@@ -77,7 +86,8 @@ PassRefPtr<IDBObjectStore> IDBTransaction::objectStore(const String& name, const
void IDBTransaction::abort()
{
- m_backend->abort();
+ if (m_backend)
+ m_backend->abort();
}
ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const
@@ -87,18 +97,32 @@ ScriptExecutionContext* IDBTransaction::scriptExecutionContext() const
void IDBTransaction::onAbort()
{
- if (!m_stopped) {
- m_selfRef = this;
- m_stopped = true;
- m_timer.startOneShot(0);
- }
- // Release the backend as it holds a (circular) reference back to us.
- m_backend.clear();
+ ASSERT(!m_onAbortTimer.isActive());
+ ASSERT(!m_onCompleteTimer.isActive());
+ ASSERT(!m_onTimeoutTimer.isActive());
+ m_selfRef = this;
+ m_onAbortTimer.startOneShot(0);
+ m_backend.clear(); // Release the backend as it holds a (circular) reference back to us.
+}
+
+void IDBTransaction::onComplete()
+{
+ ASSERT(!m_onAbortTimer.isActive());
+ ASSERT(!m_onCompleteTimer.isActive());
+ ASSERT(!m_onTimeoutTimer.isActive());
+ m_selfRef = this;
+ m_onCompleteTimer.startOneShot(0);
+ m_backend.clear(); // Release the backend as it holds a (circular) reference back to us.
}
-int IDBTransaction::id() const
+void IDBTransaction::onTimeout()
{
- return m_backend->id();
+ ASSERT(!m_onAbortTimer.isActive());
+ ASSERT(!m_onCompleteTimer.isActive());
+ ASSERT(!m_onTimeoutTimer.isActive());
+ m_selfRef = this;
+ m_onTimeoutTimer.startOneShot(0);
+ m_backend.clear(); // Release the backend as it holds a (circular) reference back to us.
}
bool IDBTransaction::canSuspend() const
@@ -110,11 +134,8 @@ bool IDBTransaction::canSuspend() const
void IDBTransaction::stop()
{
- if (!m_stopped) {
- // The document is getting detached. Abort!
- m_stopped = true;
+ if (m_backend)
m_backend->abort();
- }
}
EventTargetData* IDBTransaction::eventTargetData()
@@ -127,14 +148,28 @@ EventTargetData* IDBTransaction::ensureEventTargetData()
return &m_eventTargetData;
}
-void IDBTransaction::timerFired(Timer<IDBTransaction>* transaction)
+void IDBTransaction::onAbortTimerFired(Timer<IDBTransaction>* transaction)
{
ASSERT(m_selfRef);
-
RefPtr<IDBTransaction> selfRef = m_selfRef.release();
dispatchEvent(IDBAbortEvent::create());
}
+void IDBTransaction::onCompleteTimerFired(Timer<IDBTransaction>* transaction)
+{
+ ASSERT(m_selfRef);
+ RefPtr<IDBTransaction> selfRef = m_selfRef.release();
+ dispatchEvent(IDBCompleteEvent::create());
+}
+
+
+void IDBTransaction::onTimeoutTimerFired(Timer<IDBTransaction>* transaction)
+{
+ ASSERT(m_selfRef);
+ RefPtr<IDBTransaction> selfRef = m_selfRef.release();
+ dispatchEvent(IDBTimeoutEvent::create());
+}
+
}
#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBTransaction.h b/WebCore/storage/IDBTransaction.h
index 0d6f3ea..8db5205 100644
--- a/WebCore/storage/IDBTransaction.h
+++ b/WebCore/storage/IDBTransaction.h
@@ -60,7 +60,7 @@ public:
unsigned short mode() const;
IDBDatabase* db();
- PassRefPtr<IDBObjectStore> objectStore(const String& name, const ExceptionCode&);
+ PassRefPtr<IDBObjectStore> objectStore(const String& name, ExceptionCode&);
void abort();
DEFINE_ATTRIBUTE_EVENT_LISTENER(abort);
@@ -69,7 +69,8 @@ public:
// IDBTransactionCallbacks
virtual void onAbort();
- virtual int id() const;
+ virtual void onComplete();
+ virtual void onTimeout();
// EventTarget
virtual IDBTransaction* toIDBTransaction() { return this; }
@@ -91,14 +92,18 @@ private:
virtual EventTargetData* eventTargetData();
virtual EventTargetData* ensureEventTargetData();
- void timerFired(Timer<IDBTransaction>*);
+ void onAbortTimerFired(Timer<IDBTransaction>*);
+ void onCompleteTimerFired(Timer<IDBTransaction>*);
+ void onTimeoutTimerFired(Timer<IDBTransaction>*);
EventTargetData m_eventTargetData;
RefPtr<IDBTransactionBackendInterface> m_backend;
RefPtr<IDBDatabase> m_database;
+ unsigned short m_mode;
- bool m_stopped;
- Timer<IDBTransaction> m_timer;
+ Timer<IDBTransaction> m_onAbortTimer;
+ Timer<IDBTransaction> m_onCompleteTimer;
+ Timer<IDBTransaction> m_onTimeoutTimer;
RefPtr<IDBTransaction> m_selfRef; // This is set to us iff there's an event pending.
};
diff --git a/WebCore/storage/IDBTransactionBackendImpl.cpp b/WebCore/storage/IDBTransactionBackendImpl.cpp
index 4f18437..5016a3f 100644
--- a/WebCore/storage/IDBTransactionBackendImpl.cpp
+++ b/WebCore/storage/IDBTransactionBackendImpl.cpp
@@ -42,30 +42,34 @@ PassRefPtr<IDBTransactionBackendImpl> IDBTransactionBackendImpl::create(DOMStrin
IDBTransactionBackendImpl::IDBTransactionBackendImpl(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, int id, IDBDatabaseBackendImpl* database)
: m_objectStoreNames(objectStores)
, m_mode(mode)
- , m_timeout(timeout)
+ , m_timeout(timeout) // FIXME: Implement timeout.
, m_id(id)
- , m_state(NotStarted)
+ , m_state(Unused)
, m_database(database)
, m_transaction(new SQLiteTransaction(database->sqliteDatabase()))
- , m_timer(this, &IDBTransactionBackendImpl::timerFired)
+ , m_taskTimer(this, &IDBTransactionBackendImpl::taskTimerFired)
+ , m_taskEventTimer(this, &IDBTransactionBackendImpl::taskEventTimerFired)
, m_pendingEvents(0)
{
}
PassRefPtr<IDBObjectStoreBackendInterface> IDBTransactionBackendImpl::objectStore(const String& name)
{
- if (isFinished())
+ if (m_state == Finished)
return 0;
- return m_database->objectStore(name, 0); // FIXME: remove mode param.
+ return m_database->objectStore(name);
}
-bool IDBTransactionBackendImpl::scheduleTask(PassOwnPtr<ScriptExecutionContext::Task> task)
+bool IDBTransactionBackendImpl::scheduleTask(PassOwnPtr<ScriptExecutionContext::Task> task, PassOwnPtr<ScriptExecutionContext::Task> abortTask)
{
- if (isFinished())
+ if (m_state == Finished)
return false;
m_taskQueue.append(task);
- if (m_state == NotStarted)
+ if (abortTask)
+ m_abortTaskQueue.prepend(abortTask);
+
+ if (m_state == Unused)
start();
return true;
@@ -73,66 +77,73 @@ bool IDBTransactionBackendImpl::scheduleTask(PassOwnPtr<ScriptExecutionContext::
void IDBTransactionBackendImpl::abort()
{
- if (isFinished())
+ if (m_state == Finished)
return;
m_state = Finished;
+ m_taskTimer.stop();
+ m_taskEventTimer.stop();
m_transaction->rollback();
+
+ // Run the abort tasks, if any.
+ while (!m_abortTaskQueue.isEmpty()) {
+ OwnPtr<ScriptExecutionContext::Task> task(m_abortTaskQueue.first().release());
+ m_abortTaskQueue.removeFirst();
+ task->performTask(0);
+ }
+
m_callbacks->onAbort();
m_database->transactionCoordinator()->didFinishTransaction(this);
}
void IDBTransactionBackendImpl::didCompleteTaskEvents()
{
- ASSERT(m_state == Started);
- ASSERT(m_pendingEvents);
+ if (m_state == Finished)
+ return;
+ ASSERT(m_state == Running);
+ ASSERT(m_pendingEvents);
m_pendingEvents--;
- if (!m_pendingEvents && m_taskQueue.isEmpty()) {
- // The last task event has completed and the task
- // queue is empty. Commit the transaction.
- commit();
- return;
- }
-
- // We are still waiting for other events to complete. However,
- // the task queue is non-empty and the timer is inactive.
- // We can therfore schedule the timer again.
- if (!m_taskQueue.isEmpty() && !m_timer.isActive())
- m_timer.startOneShot(0);
+ if (!m_taskEventTimer.isActive())
+ m_taskEventTimer.startOneShot(0);
}
void IDBTransactionBackendImpl::run()
{
- ASSERT(m_state == Started);
- ASSERT(!m_timer.isActive());
+ ASSERT(m_state == StartPending || m_state == Running);
+ ASSERT(!m_taskTimer.isActive());
- m_timer.startOneShot(0);
+ m_taskTimer.startOneShot(0);
}
void IDBTransactionBackendImpl::start()
{
- ASSERT(m_state == NotStarted);
+ ASSERT(m_state == Unused);
- m_state = Started;
- m_transaction->begin();
+ m_state = StartPending;
m_database->transactionCoordinator()->didStartTransaction(this);
}
void IDBTransactionBackendImpl::commit()
{
- ASSERT(m_state == Started);
+ ASSERT(m_state == Running);
m_state = Finished;
m_transaction->commit();
+ m_callbacks->onComplete();
m_database->transactionCoordinator()->didFinishTransaction(this);
}
-void IDBTransactionBackendImpl::timerFired(Timer<IDBTransactionBackendImpl>*)
+void IDBTransactionBackendImpl::taskTimerFired(Timer<IDBTransactionBackendImpl>*)
{
ASSERT(!m_taskQueue.isEmpty());
- ASSERT(m_state == Started);
+
+ if (m_state == StartPending) {
+ m_transaction->begin();
+ m_state = Running;
+ } else
+ ASSERT(m_state == Running);
TaskQueue queue;
queue.swap(m_taskQueue);
@@ -144,6 +155,24 @@ void IDBTransactionBackendImpl::timerFired(Timer<IDBTransactionBackendImpl>*)
}
}
+void IDBTransactionBackendImpl::taskEventTimerFired(Timer<IDBTransactionBackendImpl>*)
+{
+ ASSERT(m_state == Running);
+
+ if (!m_pendingEvents && m_taskQueue.isEmpty()) {
+ // The last task event has completed and the task
+ // queue is empty. Commit the transaction.
+ commit();
+ return;
+ }
+
+ // We are still waiting for other events to complete. However,
+ // the task queue is non-empty and the timer is inactive.
+ // We can therfore schedule the timer again.
+ if (!m_taskQueue.isEmpty() && !m_taskTimer.isActive())
+ m_taskTimer.startOneShot(0);
+}
+
};
#endif // ENABLE(INDEXED_DATABASE)
diff --git a/WebCore/storage/IDBTransactionBackendImpl.h b/WebCore/storage/IDBTransactionBackendImpl.h
index c037a11..5f7409b 100644
--- a/WebCore/storage/IDBTransactionBackendImpl.h
+++ b/WebCore/storage/IDBTransactionBackendImpl.h
@@ -47,28 +47,29 @@ public:
virtual PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name);
virtual unsigned short mode() const { return m_mode; }
- virtual bool scheduleTask(PassOwnPtr<ScriptExecutionContext::Task>);
+ virtual bool scheduleTask(PassOwnPtr<ScriptExecutionContext::Task> task, PassOwnPtr<ScriptExecutionContext::Task> abortTask);
virtual void didCompleteTaskEvents();
virtual void abort();
virtual int id() const { return m_id; }
virtual void setCallbacks(IDBTransactionCallbacks* callbacks) { m_callbacks = callbacks; }
void run();
- bool isFinished() const { return m_state == Finished; }
private:
IDBTransactionBackendImpl(DOMStringList* objectStores, unsigned short mode, unsigned long timeout, int id, IDBDatabaseBackendImpl*);
enum State {
- NotStarted,
- Started,
- Finished,
+ Unused, // Created, but no tasks yet.
+ StartPending, // Enqueued tasks, but SQLite transaction not yet started.
+ Running, // SQLite transaction started but not yet finished.
+ Finished, // Either aborted or committed.
};
void start();
void commit();
- void timerFired(Timer<IDBTransactionBackendImpl>*);
+ void taskTimerFired(Timer<IDBTransactionBackendImpl>*);
+ void taskEventTimerFired(Timer<IDBTransactionBackendImpl>*);
RefPtr<DOMStringList> m_objectStoreNames;
unsigned short m_mode;
@@ -81,11 +82,13 @@ private:
typedef Deque<OwnPtr<ScriptExecutionContext::Task> > TaskQueue;
TaskQueue m_taskQueue;
+ TaskQueue m_abortTaskQueue;
OwnPtr<SQLiteTransaction> m_transaction;
// FIXME: delete the timer once we have threads instead.
- Timer<IDBTransactionBackendImpl> m_timer;
+ Timer<IDBTransactionBackendImpl> m_taskTimer;
+ Timer<IDBTransactionBackendImpl> m_taskEventTimer;
int m_pendingEvents;
};
diff --git a/WebCore/storage/IDBTransactionBackendInterface.h b/WebCore/storage/IDBTransactionBackendInterface.h
index db95d03..65b097d 100644
--- a/WebCore/storage/IDBTransactionBackendInterface.h
+++ b/WebCore/storage/IDBTransactionBackendInterface.h
@@ -50,7 +50,7 @@ public:
virtual PassRefPtr<IDBObjectStoreBackendInterface> objectStore(const String& name) = 0;
virtual unsigned short mode() const = 0;
- virtual bool scheduleTask(PassOwnPtr<ScriptExecutionContext::Task>) = 0;
+ virtual bool scheduleTask(PassOwnPtr<ScriptExecutionContext::Task> task, PassOwnPtr<ScriptExecutionContext::Task> abortTask = 0) = 0;
virtual void didCompleteTaskEvents() = 0;
virtual void abort() = 0;
virtual int id() const = 0;
diff --git a/WebCore/storage/IDBTransactionCallbacks.h b/WebCore/storage/IDBTransactionCallbacks.h
index 38181fc..348608d 100644
--- a/WebCore/storage/IDBTransactionCallbacks.h
+++ b/WebCore/storage/IDBTransactionCallbacks.h
@@ -41,8 +41,8 @@ public:
virtual ~IDBTransactionCallbacks() { }
virtual void onAbort() = 0;
- virtual int id() const = 0;
- // FIXME: add the rest
+ virtual void onComplete() = 0;
+ virtual void onTimeout() = 0;
};
} // namespace WebCore
diff --git a/WebCore/storage/IDBTransactionCoordinator.h b/WebCore/storage/IDBTransactionCoordinator.h
index 5e54ab4..fddb003 100644
--- a/WebCore/storage/IDBTransactionCoordinator.h
+++ b/WebCore/storage/IDBTransactionCoordinator.h
@@ -69,8 +69,8 @@ private:
// This map owns all transactions known to the coordinator.
HashMap<int, RefPtr<IDBTransactionBackendImpl> > m_transactions;
// Transactions in different states are grouped below.
- ListHashSet<IDBTransactionBackendImpl* > m_startedTransactions;
- HashSet<IDBTransactionBackendImpl* > m_runningTransactions;
+ ListHashSet<IDBTransactionBackendImpl*> m_startedTransactions;
+ HashSet<IDBTransactionBackendImpl*> m_runningTransactions;
int m_nextID;
};