2759514eff74224c61799cf5f60779fdce4d2423
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBCursor.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 "IDBCursor.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBAny.h"
32 #include "IDBCallbacks.h"
33 #include "IDBCursorBackendInterface.h"
34 #include "IDBKey.h"
35 #include "IDBRequest.h"
36 #include "IDBTracing.h"
37 #include "IDBTransaction.h"
38 #include "ScriptExecutionContext.h"
39 #include "SerializedScriptValue.h"
40
41 namespace WebCore {
42
43 PassRefPtr<IDBCursor> IDBCursor::create(PassRefPtr<IDBCursorBackendInterface> backend, IDBRequest* request, IDBAny* source, IDBTransaction* transaction)
44 {
45     return adoptRef(new IDBCursor(backend, request, source, transaction));
46 }
47
48 const AtomicString& IDBCursor::directionNext()
49 {
50     DEFINE_STATIC_LOCAL(AtomicString, next, ("next"));
51     return next;
52 }
53
54 const AtomicString& IDBCursor::directionNextUnique()
55 {
56     DEFINE_STATIC_LOCAL(AtomicString, nextunique, ("nextunique"));
57     return nextunique;
58 }
59
60 const AtomicString& IDBCursor::directionPrev()
61 {
62     DEFINE_STATIC_LOCAL(AtomicString, prev, ("prev"));
63     return prev;
64 }
65
66 const AtomicString& IDBCursor::directionPrevUnique()
67 {
68     DEFINE_STATIC_LOCAL(AtomicString, prevunique, ("prevunique"));
69     return prevunique;
70 }
71
72
73 IDBCursor::IDBCursor(PassRefPtr<IDBCursorBackendInterface> backend, IDBRequest* request, IDBAny* source, IDBTransaction* transaction)
74     : m_backend(backend)
75     , m_request(request)
76     , m_source(source)
77     , m_transaction(transaction)
78     , m_transactionNotifier(transaction, this)
79     , m_gotValue(false)
80     , m_valueIsDirty(true)
81 {
82     ASSERT(m_backend);
83     ASSERT(m_request);
84     ASSERT(m_source->type() == IDBAny::IDBObjectStoreType || m_source->type() == IDBAny::IDBIndexType);
85     ASSERT(m_transaction);
86 }
87
88 IDBCursor::~IDBCursor()
89 {
90 }
91
92 const String& IDBCursor::direction() const
93 {
94     IDB_TRACE("IDBCursor::direction");
95     ExceptionCode ec = 0;
96     const AtomicString& direction = directionToString(m_backend->direction(), ec);
97     ASSERT(!ec);
98     return direction;
99 }
100
101 PassRefPtr<IDBKey> IDBCursor::key() const
102 {
103     IDB_TRACE("IDBCursor::key");
104     return m_currentKey;
105 }
106
107 PassRefPtr<IDBKey> IDBCursor::primaryKey() const
108 {
109     IDB_TRACE("IDBCursor::primaryKey");
110     return m_currentPrimaryKey;
111 }
112
113 PassRefPtr<IDBAny> IDBCursor::value()
114 {
115     IDB_TRACE("IDBCursor::value");
116     m_valueIsDirty = false;
117     return m_currentValue;
118 }
119
120 IDBAny* IDBCursor::source() const
121 {
122     return m_source.get();
123 }
124
125 PassRefPtr<IDBRequest> IDBCursor::update(ScriptExecutionContext* context, PassRefPtr<SerializedScriptValue> prpValue, ExceptionCode& ec)
126 {
127     IDB_TRACE("IDBCursor::update");
128
129     if (!m_gotValue) {
130         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
131         return 0;
132     }
133
134     if (m_transaction->isReadOnly()) {
135         ec = IDBDatabaseException::READ_ONLY_ERR;
136         return 0;
137     }
138
139     RefPtr<SerializedScriptValue> value = prpValue;
140     if (value->blobURLs().size() > 0) {
141         // FIXME: Add Blob/File/FileList support
142         ec = IDBDatabaseException::IDB_DATA_CLONE_ERR;
143         return 0;
144     }
145
146     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
147     m_backend->update(value, request, ec);
148     if (ec) {
149         request->markEarlyDeath();
150         return 0;
151     }
152     return request.release();
153 }
154
155 void IDBCursor::advance(unsigned long count, ExceptionCode& ec)
156 {
157     IDB_TRACE("IDBCursor::advance");
158     if (!m_gotValue) {
159         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
160         return;
161     }
162
163     if (!m_request) {
164         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
165         return;
166     }
167
168     if (!count) {
169         ec = IDBDatabaseException::IDB_TYPE_ERR;
170         return;
171     }
172
173     if (!m_request->resetReadyState(m_transaction.get())) {
174         ASSERT_NOT_REACHED();
175         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
176         return;
177     }
178     m_request->setCursor(this);
179     m_gotValue = false;
180     m_backend->advance(count, m_request, ec);
181 }
182
183 void IDBCursor::continueFunction(PassRefPtr<IDBKey> key, ExceptionCode& ec)
184 {
185     IDB_TRACE("IDBCursor::continue");
186     if (key && !key->isValid()) {
187         ec = IDBDatabaseException::DATA_ERR;
188         return;
189     }
190
191     if (!m_request) {
192         ec = IDBDatabaseException::TRANSACTION_INACTIVE_ERR;
193         return;
194     }
195
196     if (!m_gotValue) {
197         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
198         return;
199     }
200
201     // FIXME: We're not using the context from when continue was called, which means the callback
202     //        will be on the original context openCursor was called on. Is this right?
203     if (m_request->resetReadyState(m_transaction.get())) {
204         m_request->setCursor(this);
205         m_gotValue = false;
206         m_backend->continueFunction(key, m_request, ec);
207     } else {
208         ASSERT_NOT_REACHED();
209         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
210     }
211 }
212
213 PassRefPtr<IDBRequest> IDBCursor::deleteFunction(ScriptExecutionContext* context, ExceptionCode& ec)
214 {
215     IDB_TRACE("IDBCursor::delete");
216     if (m_transaction->isReadOnly()) {
217         ec = IDBDatabaseException::READ_ONLY_ERR;
218         return 0;
219     }
220
221     if (!m_gotValue) {
222         ec = IDBDatabaseException::IDB_INVALID_STATE_ERR;
223         return 0;
224     }
225     RefPtr<IDBRequest> request = IDBRequest::create(context, IDBAny::create(this), m_transaction.get());
226     m_backend->deleteFunction(request, ec);
227     if (ec) {
228         request->markEarlyDeath();
229         return 0;
230     }
231     return request.release();
232 }
233
234 void IDBCursor::postSuccessHandlerCallback()
235 {
236     m_backend->postSuccessHandlerCallback();
237 }
238
239 void IDBCursor::close()
240 {
241     ASSERT(m_request);
242     m_request->finishCursor();
243     m_request.clear();
244 }
245
246 void IDBCursor::setValueReady()
247 {
248     m_currentKey = m_backend->key();
249     m_currentPrimaryKey = m_backend->primaryKey();
250     m_currentValue = IDBAny::create(m_backend->value());
251     m_gotValue = true;
252     m_valueIsDirty = true;
253 }
254
255 unsigned short IDBCursor::stringToDirection(const String& directionString, ExceptionCode& ec)
256 {
257     if (directionString == IDBCursor::directionNext())
258         return IDBCursor::NEXT;
259     if (directionString == IDBCursor::directionNextUnique())
260         return IDBCursor::NEXT_NO_DUPLICATE;
261     if (directionString == IDBCursor::directionPrev())
262         return IDBCursor::PREV;
263     if (directionString == IDBCursor::directionPrevUnique())
264         return IDBCursor::PREV_NO_DUPLICATE;
265
266     ec = IDBDatabaseException::IDB_TYPE_ERR;
267     return 0;
268 }
269
270 const AtomicString& IDBCursor::directionToString(unsigned short direction, ExceptionCode& ec)
271 {
272     switch (direction) {
273     case IDBCursor::NEXT:
274         return IDBCursor::directionNext();
275
276     case IDBCursor::NEXT_NO_DUPLICATE:
277         return IDBCursor::directionNextUnique();
278
279     case IDBCursor::PREV:
280         return IDBCursor::directionPrev();
281
282     case IDBCursor::PREV_NO_DUPLICATE:
283         return IDBCursor::directionPrevUnique();
284
285     default:
286         ec = IDBDatabaseException::IDB_TYPE_ERR;
287         return IDBCursor::directionNext();
288     }
289 }
290
291 } // namespace WebCore
292
293 #endif // ENABLE(INDEXED_DATABASE)