summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/storage/IDBCursorBackendImpl.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/storage/IDBCursorBackendImpl.cpp')
-rw-r--r--Source/WebCore/storage/IDBCursorBackendImpl.cpp199
1 files changed, 199 insertions, 0 deletions
diff --git a/Source/WebCore/storage/IDBCursorBackendImpl.cpp b/Source/WebCore/storage/IDBCursorBackendImpl.cpp
new file mode 100644
index 0000000..9b4e4f1
--- /dev/null
+++ b/Source/WebCore/storage/IDBCursorBackendImpl.cpp
@@ -0,0 +1,199 @@
+/*
+ * 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.
+ */
+
+#include "config.h"
+#include "IDBCursorBackendImpl.h"
+
+#if ENABLE(INDEXED_DATABASE)
+
+#include "CrossThreadTask.h"
+#include "IDBCallbacks.h"
+#include "IDBDatabaseBackendImpl.h"
+#include "IDBDatabaseError.h"
+#include "IDBDatabaseException.h"
+#include "IDBIndexBackendImpl.h"
+#include "IDBKeyRange.h"
+#include "IDBObjectStoreBackendImpl.h"
+#include "IDBRequest.h"
+#include "IDBSQLiteDatabase.h"
+#include "IDBTransactionBackendInterface.h"
+#include "SQLiteDatabase.h"
+#include "SQLiteStatement.h"
+#include "SerializedScriptValue.h"
+
+namespace WebCore {
+
+IDBCursorBackendImpl::IDBCursorBackendImpl(IDBSQLiteDatabase* database, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore)
+ : m_database(database)
+ , m_keyRange(keyRange)
+ , m_direction(direction)
+ , m_query(query)
+ , m_isSerializedScriptValueCursor(isSerializedScriptValueCursor)
+ , m_transaction(transaction)
+ , m_objectStore(objectStore)
+{
+ loadCurrentRow();
+}
+
+IDBCursorBackendImpl::~IDBCursorBackendImpl()
+{
+}
+
+unsigned short IDBCursorBackendImpl::direction() const
+{
+ return m_direction;
+}
+
+PassRefPtr<IDBKey> IDBCursorBackendImpl::key() const
+{
+
+ return m_currentKey;
+}
+
+PassRefPtr<IDBAny> IDBCursorBackendImpl::value() const
+{
+ if (m_isSerializedScriptValueCursor)
+ return IDBAny::create(m_currentSerializedScriptValue.get());
+ return IDBAny::create(m_currentIDBKeyValue.get());
+}
+
+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."));
+ return;
+
+ RefPtr<SerializedScriptValue> value = prpValue;
+
+ 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(cursor->database(), sql);
+
+ bool ok = updateQuery.prepare() == SQLResultOk;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
+ updateQuery.bindText(1, value->toWireString());
+ updateQuery.bindInt64(2, cursor->m_currentId);
+ ok = updateQuery.step() == SQLResultDone;
+ ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
+
+ if (cursor->m_isSerializedScriptValueCursor)
+ cursor->m_currentSerializedScriptValue = value.release();
+ callbacks->onSuccess();
+}
+
+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 (!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 = 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(cursor->m_currentKey.get()))
+ continue;
+
+ // If we don't have a uniqueness constraint, we can stop now.
+ if (cursor->m_direction == IDBCursor::NEXT || cursor->m_direction == IDBCursor::PREV)
+ break;
+ if (!cursor->m_currentKey->isEqual(oldKey.get()))
+ break;
+ }
+
+ callbacks->onSuccess(cursor.get());
+}
+
+void IDBCursorBackendImpl::deleteFunction(PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
+{
+ if (!m_query || m_currentId == InvalidId || !m_isSerializedScriptValueCursor) {
+ ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ return;
+ }
+
+ // FIXME: Check that the transaction is READ_WRITE
+ // if (m_transaction->mode() == IDBTransaction::READ_ONLY) {
+ // FIXME: We must return READ_ONLY_ERR here. Fix this when we update IDBDatabaseException to match the spec.
+ // ec = IDBDatabaseException::NOT_ALLOWED_ERR;
+ // return;
+ // }
+ RefPtr<IDBKey> key = m_currentIDBKeyValue ? m_currentIDBKeyValue : m_currentKey;
+ m_objectStore->deleteFunction(key.release(), prpCallbacks, m_transaction.get(), ec);
+}
+
+
+void IDBCursorBackendImpl::loadCurrentRow()
+{
+ // The column numbers depend on the query in IDBObjectStoreBackendImpl::openCursorInternal or
+ // IDBIndexBackendImpl::openCursorInternal.
+ m_currentId = m_query->getColumnInt64(0);
+ m_currentKey = IDBKey::fromQuery(*m_query, 1);
+ if (m_isSerializedScriptValueCursor)
+ m_currentSerializedScriptValue = SerializedScriptValue::createFromWire(m_query->getColumnText(4));
+
+ m_currentIDBKeyValue = IDBKey::fromQuery(*m_query, 5);
+}
+
+SQLiteDatabase& IDBCursorBackendImpl::database() const
+{
+ return m_database->db();
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(INDEXED_DATABASE)