2 * Copyright (C) 2010 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
16 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
18 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
19 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
20 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
21 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 #include "IDBCursorBackendImpl.h"
29 #if ENABLE(INDEXED_DATABASE)
31 #include "CrossThreadTask.h"
32 #include "IDBCallbacks.h"
33 #include "IDBDatabaseBackendImpl.h"
34 #include "IDBDatabaseError.h"
35 #include "IDBDatabaseException.h"
36 #include "IDBIndexBackendImpl.h"
37 #include "IDBKeyRange.h"
38 #include "IDBObjectStoreBackendImpl.h"
39 #include "IDBRequest.h"
40 #include "IDBTransactionBackendInterface.h"
41 #include "SQLiteDatabase.h"
42 #include "SQLiteStatement.h"
43 #include "SerializedScriptValue.h"
47 IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBObjectStoreBackendImpl> idbObjectStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, IDBTransactionBackendInterface* transaction)
48 : m_idbObjectStore(idbObjectStore)
49 , m_keyRange(keyRange)
50 , m_direction(direction)
52 , m_isSerializedScriptValueCursor(true)
53 , m_transaction(transaction)
58 IDBCursorBackendImpl::IDBCursorBackendImpl(PassRefPtr<IDBIndexBackendImpl> idbIndex, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface* transaction)
59 : m_idbIndex(idbIndex)
60 , m_keyRange(keyRange)
61 , m_direction(direction)
63 , m_isSerializedScriptValueCursor(isSerializedScriptValueCursor)
64 , m_transaction(transaction)
69 IDBCursorBackendImpl::~IDBCursorBackendImpl()
73 unsigned short IDBCursorBackendImpl::direction() const
78 PassRefPtr<IDBKey> IDBCursorBackendImpl::key() const
84 PassRefPtr<IDBAny> IDBCursorBackendImpl::value() const
86 if (m_isSerializedScriptValueCursor)
87 return IDBAny::create(m_currentSerializedScriptValue.get());
88 return IDBAny::create(m_currentIDBKeyValue.get());
91 void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
93 RefPtr<IDBCursorBackendImpl> cursor = this;
94 RefPtr<SerializedScriptValue> value = prpValue;
95 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
96 // FIXME: Throw DATA_ERR and SERIAL_ERR when appropriate.
97 if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::updateInternal, cursor, value, callbacks)))
98 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
101 void IDBCursorBackendImpl::updateInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> cursor, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> callbacks)
103 // FIXME: This method doesn't update indexes. It's dangerous to call in its current state.
104 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Not implemented."));
107 RefPtr<SerializedScriptValue> value = prpValue;
109 if (!cursor->m_query || cursor->m_currentId == InvalidId) {
110 // FIXME: Use the proper error code when it's specced.
111 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Operation not possible."));
115 String sql = "UPDATE ObjectStoreData SET value = ? WHERE id = ?";
116 SQLiteStatement updateQuery(cursor->database()->sqliteDatabase(), sql);
118 bool ok = updateQuery.prepare() == SQLResultOk;
119 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
120 updateQuery.bindText(1, value->toWireString());
121 updateQuery.bindInt64(2, cursor->m_currentId);
122 ok = updateQuery.step() == SQLResultDone;
123 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
125 if (cursor->m_isSerializedScriptValueCursor)
126 cursor->m_currentSerializedScriptValue = value.release();
127 callbacks->onSuccess();
130 void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
132 RefPtr<IDBCursorBackendImpl> cursor = this;
133 RefPtr<IDBKey> key = prpKey;
134 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
135 if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::continueFunctionInternal, cursor, key, callbacks)))
136 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
139 void IDBCursorBackendImpl::continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> prpCursor, PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> callbacks)
141 RefPtr<IDBCursorBackendImpl> cursor = prpCursor;
142 RefPtr<IDBKey> key = prpKey;
144 if (!cursor->m_query || cursor->m_query->step() != SQLResultRow) {
146 cursor->m_currentId = InvalidId;
147 cursor->m_currentKey = 0;
148 cursor->m_currentSerializedScriptValue = 0;
149 cursor->m_currentIDBKeyValue = 0;
150 callbacks->onSuccess();
154 RefPtr<IDBKey> oldKey = cursor->m_currentKey;
155 cursor->loadCurrentRow();
157 // If a key was supplied, we must loop until we find that key (or hit the end).
158 if (key && !key->isEqual(cursor->m_currentKey.get()))
161 // If we don't have a uniqueness constraint, we can stop now.
162 if (cursor->m_direction == IDBCursor::NEXT || cursor->m_direction == IDBCursor::PREV)
164 if (!cursor->m_currentKey->isEqual(oldKey.get()))
168 callbacks->onSuccess(cursor.get());
171 void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
173 RefPtr<IDBCursorBackendImpl> cursor = this;
174 RefPtr<IDBCallbacks> callbacks = prpCallbacks;
175 if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::removeInternal, cursor, callbacks)))
176 ec = IDBDatabaseException::NOT_ALLOWED_ERR;
179 void IDBCursorBackendImpl::removeInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> cursor, PassRefPtr<IDBCallbacks> callbacks)
181 // FIXME: This method doesn't update indexes. It's dangerous to call in its current state.
182 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Not implemented."));
185 if (!cursor->m_query || cursor->m_currentId == InvalidId) {
186 // FIXME: Use the proper error code when it's specced.
187 callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UNKNOWN_ERR, "Operation not possible."));
191 String sql = "DELETE FROM ObjectStoreData WHERE id = ?";
192 SQLiteStatement deleteQuery(cursor->database()->sqliteDatabase(), sql);
194 bool ok = deleteQuery.prepare() == SQLResultOk;
195 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
196 deleteQuery.bindInt64(1, cursor->m_currentId);
197 ok = deleteQuery.step() == SQLResultDone;
198 ASSERT_UNUSED(ok, ok); // FIXME: Better error handling.
200 cursor->m_currentId = InvalidId;
201 cursor->m_currentSerializedScriptValue = 0;
202 cursor->m_currentIDBKeyValue = 0;
203 callbacks->onSuccess();
206 void IDBCursorBackendImpl::loadCurrentRow()
208 // The column numbers depend on the query in IDBObjectStoreBackendImpl::openCursor.
209 m_currentId = m_query->getColumnInt64(0);
210 m_currentKey = IDBKey::fromQuery(*m_query, 1);
211 if (m_isSerializedScriptValueCursor)
212 m_currentSerializedScriptValue = SerializedScriptValue::createFromWire(m_query->getColumnText(4));
214 m_currentIDBKeyValue = IDBKey::fromQuery(*m_query, 4);
217 IDBDatabaseBackendImpl* IDBCursorBackendImpl::database() const
219 if (m_idbObjectStore)
220 return m_idbObjectStore->database();
221 return m_idbIndex->objectStore()->database();
224 } // namespace WebCore
226 #endif // ENABLE(INDEXED_DATABASE)