4576f6db817678459389782f432ec249684e2fcb
[WebKit-https.git] / Source / 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 "IDBBackingStore.h"
33 #include "IDBCallbacks.h"
34 #include "IDBDatabaseBackendImpl.h"
35 #include "IDBDatabaseError.h"
36 #include "IDBDatabaseException.h"
37 #include "IDBIndexBackendImpl.h"
38 #include "IDBKeyRange.h"
39 #include "IDBObjectStoreBackendImpl.h"
40 #include "IDBRequest.h"
41 #include "IDBTransactionBackendInterface.h"
42 #include "SQLiteDatabase.h"
43 #include "SQLiteStatement.h"
44 #include "SerializedScriptValue.h"
45
46 namespace WebCore {
47
48 IDBCursorBackendImpl::IDBCursorBackendImpl(IDBBackingStore* backingStore, PassRefPtr<IDBKeyRange> keyRange, IDBCursor::Direction direction, PassOwnPtr<SQLiteStatement> query, bool isSerializedScriptValueCursor, IDBTransactionBackendInterface* transaction, IDBObjectStoreBackendInterface* objectStore)
49     : m_backingStore(backingStore)
50     , m_keyRange(keyRange)
51     , m_direction(direction)
52     , m_query(query)
53     , m_isSerializedScriptValueCursor(isSerializedScriptValueCursor)
54     , m_transaction(transaction)
55     , m_objectStore(objectStore)
56 {
57     loadCurrentRow();
58 }
59
60 IDBCursorBackendImpl::~IDBCursorBackendImpl()
61 {
62 }
63
64 unsigned short IDBCursorBackendImpl::direction() const
65 {
66     return m_direction;
67 }
68
69 PassRefPtr<IDBKey> IDBCursorBackendImpl::key() const
70 {
71     return m_currentKey;
72 }
73
74 PassRefPtr<IDBAny> IDBCursorBackendImpl::value() const
75 {
76     if (m_isSerializedScriptValueCursor)
77         return IDBAny::create(m_currentSerializedScriptValue.get());
78     return IDBAny::create(m_currentIDBKeyValue.get());
79 }
80
81 void IDBCursorBackendImpl::update(PassRefPtr<SerializedScriptValue> value, PassRefPtr<IDBCallbacks> callbacks, ExceptionCode& ec)
82 {
83     if (!m_query || m_currentId == InvalidId || !m_isSerializedScriptValueCursor) {
84         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
85         return;
86     }
87
88     RefPtr<IDBKey> key = m_currentIDBKeyValue ? m_currentIDBKeyValue : m_currentKey;
89     m_objectStore->put(value, key.release(), IDBObjectStoreBackendInterface::CursorUpdate, callbacks, m_transaction.get(), ec);
90 }
91
92 void IDBCursorBackendImpl::continueFunction(PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
93 {
94     RefPtr<IDBCursorBackendImpl> cursor = this;
95     RefPtr<IDBKey> key = prpKey;
96     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
97     if (!m_transaction->scheduleTask(createCallbackTask(&IDBCursorBackendImpl::continueFunctionInternal, cursor, key, callbacks)))
98         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
99 }
100
101 bool IDBCursorBackendImpl::currentRowExists()
102 {
103     String sql = m_currentIDBKeyValue ? "SELECT id FROM IndexData WHERE id = ?" : "SELECT id FROM ObjectStoreData WHERE id = ?";
104     SQLiteStatement statement(m_backingStore->db(), sql);
105
106     bool ok = statement.prepare() == SQLResultOk;
107     ASSERT_UNUSED(ok, ok);
108
109     statement.bindInt64(1, m_currentId);
110     return statement.step() == SQLResultRow;
111 }
112
113 // IMPORTANT: If this ever 1) fires an 'error' event and 2) it's possible to fire another event afterwards,
114 //            IDBRequest::hasPendingActivity() will need to be modified to handle this!!!
115 void IDBCursorBackendImpl::continueFunctionInternal(ScriptExecutionContext*, PassRefPtr<IDBCursorBackendImpl> prpCursor, PassRefPtr<IDBKey> prpKey, PassRefPtr<IDBCallbacks> callbacks)
116 {
117     RefPtr<IDBCursorBackendImpl> cursor = prpCursor;
118     RefPtr<IDBKey> key = prpKey;
119     while (true) {
120         if (!cursor->m_query || cursor->m_query->step() != SQLResultRow) {
121             cursor->m_query = 0;
122             cursor->m_currentId = InvalidId;
123             cursor->m_currentKey = 0;
124             cursor->m_currentSerializedScriptValue = 0;
125             cursor->m_currentIDBKeyValue = 0;
126             callbacks->onSuccess(SerializedScriptValue::nullValue());
127             return;
128         }
129
130         RefPtr<IDBKey> oldKey = cursor->m_currentKey;
131         cursor->loadCurrentRow();
132
133         // Skip if this entry has been deleted from the object store.
134         if (!cursor->currentRowExists())
135             continue;
136
137         // If a key was supplied, we must loop until we find that key (or hit the end).
138         if (key && !key->isEqual(cursor->m_currentKey.get()))
139             continue;
140
141         // If we don't have a uniqueness constraint, we can stop now.
142         if (cursor->m_direction == IDBCursor::NEXT || cursor->m_direction == IDBCursor::PREV)
143             break;
144         if (!cursor->m_currentKey->isEqual(oldKey.get()))
145             break;
146     }
147
148     callbacks->onSuccess(cursor.get());
149 }
150
151 void IDBCursorBackendImpl::deleteFunction(PassRefPtr<IDBCallbacks> prpCallbacks, ExceptionCode& ec)
152 {
153     if (!m_query || m_currentId == InvalidId || !m_isSerializedScriptValueCursor) {
154         ec = IDBDatabaseException::NOT_ALLOWED_ERR;
155         return;
156     }
157
158     RefPtr<IDBKey> key = m_currentIDBKeyValue ? m_currentIDBKeyValue : m_currentKey;
159     m_objectStore->deleteFunction(key.release(), prpCallbacks, m_transaction.get(), ec);
160 }
161
162
163 void IDBCursorBackendImpl::loadCurrentRow()
164 {
165     // The column numbers depend on the query in IDBObjectStoreBackendImpl::openCursorInternal or
166     // IDBIndexBackendImpl::openCursorInternal.
167     m_currentId = m_query->getColumnInt64(0);
168     m_currentKey = IDBKey::fromQuery(*m_query, 1);
169     if (m_isSerializedScriptValueCursor)
170         m_currentSerializedScriptValue = SerializedScriptValue::createFromWire(m_query->getColumnBlobAsString(4));
171
172     m_currentIDBKeyValue = IDBKey::fromQuery(*m_query, 5);
173 }
174
175 SQLiteDatabase& IDBCursorBackendImpl::database() const
176 {
177     return m_backingStore->db();
178 }
179
180 } // namespace WebCore
181
182 #endif // ENABLE(INDEXED_DATABASE)