OSDN Git Service

40b46c6c2daa9f177f9d2e4bb871a1f971cdbae0
[android-x86/external-webkit.git] / WebCore / storage / IDBCursorBackendImpl.cpp
1 /*
2  * Copyright (C) 2010 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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.
13  *
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.
24  */
25
26 #include "config.h"
27 #include "IDBCursorBackendImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
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"
44
45 namespace WebCore {
46
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)
51     , m_query(query)
52     , m_isSerializedScriptValueCursor(true)
53     , m_transaction(transaction)
54 {
55     loadCurrentRow();
56 }
57
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)
62     , m_query(query)
63     , m_isSerializedScriptValueCursor(isSerializedScriptValueCursor)
64     , m_transaction(transaction)
65 {
66     loadCurrentRow();
67 }
68
69 IDBCursorBackendImpl::~IDBCursorBackendImpl()
70 {
71 }
72
73 unsigned short IDBCursorBackendImpl::direction() const
74 {
75     return m_direction;
76 }
77
78 PassRefPtr<IDBKey> IDBCursorBackendImpl::key() const
79 {
80     
81     return m_currentKey;
82 }
83
84 PassRefPtr<IDBAny> IDBCursorBackendImpl::value() const
85 {
86     if (m_isSerializedScriptValueCursor)
87         return IDBAny::create(m_currentSerializedScriptValue.get());
88     return IDBAny::create(m_currentIDBKeyValue.get());
89 }
90
91 void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
92 {
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;
99 }
100
101 void IDBCursorBackendImpl::updateInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> cursor, PassRefPtr<SerializedScriptValue> prpValue, PassRefPtr<IDBCallbacks> callbacks)
102 {
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."));
105     return;
106
107     RefPtr<SerializedScriptValue> value = prpValue;
108
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."));
112         return;
113     }
114
115     String sql = "UPDATE ObjectStoreData SET value = ? WHERE id = ?";
116     SQLiteStatement updateQuery(cursor->database()->sqliteDatabase(), sql);
117     
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.
124
125     if (cursor->m_isSerializedScriptValueCursor)
126         cursor->m_currentSerializedScriptValue = value.release();
127     callbacks->onSuccess();
128 }
129
130 void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
131 {
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;
137 }
138
139 void IDBCursorBackendImpl::continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> prpCursor, PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> callbacks)
140 {
141     RefPtr<IDBCursorBackendImpl> cursor = prpCursor;
142     RefPtr<IDBKey> key = prpKey;
143     while (true) {
144         if (!cursor->m_query || cursor->m_query->step() != SQLResultRow) {
145             cursor->m_query = 0;
146             cursor->m_currentId = InvalidId;
147             cursor->m_currentKey = 0;
148             cursor->m_currentSerializedScriptValue = 0;
149             cursor->m_currentIDBKeyValue = 0;
150             callbacks->onSuccess();
151             return;
152         }
153
154         RefPtr<IDBKey> oldKey = cursor->m_currentKey;
155         cursor->loadCurrentRow();
156
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()))
159             continue;
160
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)
163             break;
164         if (!cursor->m_currentKey->isEqual(oldKey.get()))
165             break;
166     }
167
168     callbacks->onSuccess(cursor.get());
169 }
170
171 void IDBCursorBackendImpl::remove(PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
172 {
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;
177 }
178
179 void IDBCursorBackendImpl::removeInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> cursor, PassRefPtr<IDBCallbacks> callbacks)
180 {
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."));
183     return;
184
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."));
188         return;
189     }
190
191     String sql = "DELETE FROM ObjectStoreData WHERE id = ?";
192     SQLiteStatement deleteQuery(cursor->database()->sqliteDatabase(), sql);
193     
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.
199
200     cursor->m_currentId = InvalidId;
201     cursor->m_currentSerializedScriptValue = 0;
202     cursor->m_currentIDBKeyValue = 0;
203     callbacks->onSuccess();
204 }
205
206 void IDBCursorBackendImpl::loadCurrentRow()
207 {
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));
213     else
214         m_currentIDBKeyValue = IDBKey::fromQuery(*m_query, 4);
215 }
216
217 IDBDatabaseBackendImpl* IDBCursorBackendImpl::database() const
218 {
219     if (m_idbObjectStore)
220         return m_idbObjectStore->database();
221     return m_idbIndex->objectStore()->database();
222 }
223
224 } // namespace WebCore
225
226 #endif // ENABLE(INDEXED_DATABASE)