IndexedDB: Allow createIndex/createObjectStore to be asynchronous
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / IDBDatabaseBackendImpl.cpp
1 /*
2  * Copyright (C) 2011 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 "IDBDatabaseBackendImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "IDBBackingStore.h"
32 #include "IDBCursorBackendImpl.h"
33 #include "IDBDatabaseException.h"
34 #include "IDBFactoryBackendImpl.h"
35 #include "IDBObjectStoreBackendImpl.h"
36 #include "IDBTracing.h"
37 #include "IDBTransactionBackendImpl.h"
38 #include "IDBTransactionCoordinator.h"
39
40 namespace WebCore {
41
42 class CreateObjectStoreOperation : public IDBTransactionBackendImpl::Operation {
43 public:
44     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, const IDBObjectStoreMetadata& objectStoreMetadata)
45     {
46         return adoptPtr(new CreateObjectStoreOperation(backingStore, objectStoreMetadata));
47     }
48     virtual void perform(IDBTransactionBackendImpl*);
49 private:
50     CreateObjectStoreOperation(PassRefPtr<IDBBackingStore> backingStore, const IDBObjectStoreMetadata& objectStoreMetadata)
51         : m_backingStore(backingStore)
52         , m_objectStoreMetadata(objectStoreMetadata)
53     {
54     }
55
56     const RefPtr<IDBBackingStore> m_backingStore;
57     const IDBObjectStoreMetadata m_objectStoreMetadata;
58 };
59
60 class DeleteObjectStoreOperation : public IDBTransactionBackendImpl::Operation {
61 public:
62     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, const IDBObjectStoreMetadata& objectStoreMetadata)
63     {
64         return adoptPtr(new DeleteObjectStoreOperation(backingStore, objectStoreMetadata));
65     }
66     virtual void perform(IDBTransactionBackendImpl*);
67 private:
68     DeleteObjectStoreOperation(PassRefPtr<IDBBackingStore> backingStore, const IDBObjectStoreMetadata& objectStoreMetadata)
69         : m_backingStore(backingStore)
70         , m_objectStoreMetadata(objectStoreMetadata)
71     {
72     }
73
74     const RefPtr<IDBBackingStore> m_backingStore;
75     const IDBObjectStoreMetadata m_objectStoreMetadata;
76 };
77
78 class IDBDatabaseBackendImpl::VersionChangeOperation : public IDBTransactionBackendImpl::Operation {
79 public:
80     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t transactionId, int64_t version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks)
81     {
82         return adoptPtr(new VersionChangeOperation(database, transactionId, version, callbacks, databaseCallbacks));
83     }
84     virtual void perform(IDBTransactionBackendImpl*);
85 private:
86     VersionChangeOperation(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t transactionId, int64_t version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks)
87         : m_database(database)
88         , m_transactionId(transactionId)
89         , m_version(version)
90         , m_callbacks(callbacks)
91         , m_databaseCallbacks(databaseCallbacks)
92     {
93     }
94
95     RefPtr<IDBDatabaseBackendImpl> m_database;
96     int64_t m_transactionId;
97     int64_t m_version;
98     RefPtr<IDBCallbacks> m_callbacks;
99     RefPtr<IDBDatabaseCallbacks> m_databaseCallbacks;
100 };
101
102 class CreateObjectStoreAbortOperation : public IDBTransactionBackendImpl::Operation {
103 public:
104     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId)
105     {
106         return adoptPtr(new CreateObjectStoreAbortOperation(database, objectStoreId));
107     }
108     virtual void perform(IDBTransactionBackendImpl*);
109 private:
110     CreateObjectStoreAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId)
111         : m_database(database)
112         , m_objectStoreId(objectStoreId)
113     {
114     }
115
116     const RefPtr<IDBDatabaseBackendImpl> m_database;
117     const int64_t m_objectStoreId;
118 };
119
120 class DeleteObjectStoreAbortOperation : public IDBTransactionBackendImpl::Operation {
121 public:
122     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, const IDBObjectStoreMetadata& objectStore)
123     {
124         return adoptPtr(new DeleteObjectStoreAbortOperation(database, objectStore));
125     }
126     virtual void perform(IDBTransactionBackendImpl*);
127 private:
128     DeleteObjectStoreAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, const IDBObjectStoreMetadata& objectStoreMetadata)
129         : m_database(database)
130         , m_objectStoreMetadata(objectStoreMetadata)
131     {
132     }
133
134     RefPtr<IDBDatabaseBackendImpl> m_database;
135     IDBObjectStoreMetadata m_objectStoreMetadata;
136 };
137
138 class IDBDatabaseBackendImpl::VersionChangeAbortOperation : public IDBTransactionBackendImpl::Operation {
139 public:
140     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, const String& previousVersion, int64_t previousIntVersion)
141     {
142         return adoptPtr(new VersionChangeAbortOperation(database, previousVersion, previousIntVersion));
143     }
144     virtual void perform(IDBTransactionBackendImpl*);
145 private:
146     VersionChangeAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, const String& previousVersion, int64_t previousIntVersion)
147         : m_database(database)
148         , m_previousVersion(previousVersion)
149         , m_previousIntVersion(previousIntVersion)
150     {
151     }
152
153     RefPtr<IDBDatabaseBackendImpl> m_database;
154     String m_previousVersion;
155     int64_t m_previousIntVersion;
156 };
157
158 class CreateIndexOperation : public IDBTransactionBackendImpl::Operation {
159 public:
160     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
161     {
162         return adoptPtr(new CreateIndexOperation(backingStore, objectStoreId, indexMetadata));
163     }
164     virtual void perform(IDBTransactionBackendImpl*);
165 private:
166     CreateIndexOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
167         : m_backingStore(backingStore)
168         , m_objectStoreId(objectStoreId)
169         , m_indexMetadata(indexMetadata)
170     {
171     }
172
173     const RefPtr<IDBBackingStore> m_backingStore;
174     const int64_t m_objectStoreId;
175     const IDBIndexMetadata m_indexMetadata;
176 };
177
178 class DeleteIndexOperation : public IDBTransactionBackendImpl::Operation {
179 public:
180     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t objectStoreId, int64_t indexId)
181     {
182         return adoptPtr(new DeleteIndexOperation(backingStore, objectStoreId, indexId));
183     }
184     virtual void perform(IDBTransactionBackendImpl*);
185 private:
186     DeleteIndexOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t objectStoreId, int64_t indexId)
187         : m_backingStore(backingStore)
188         , m_objectStoreId(objectStoreId)
189         , m_indexId(indexId)
190     {
191     }
192
193     const RefPtr<IDBBackingStore> m_backingStore;
194     const int64_t m_objectStoreId;
195     const int64_t m_indexId;
196 };
197
198 class CreateIndexAbortOperation : public IDBTransactionBackendImpl::Operation {
199 public:
200     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId, int64_t indexId)
201     {
202         return adoptPtr(new CreateIndexAbortOperation(database, objectStoreId, indexId));
203     }
204     virtual void perform(IDBTransactionBackendImpl*);
205 private:
206     CreateIndexAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId, int64_t indexId)
207         : m_database(database)
208         , m_objectStoreId(objectStoreId)
209         , m_indexId(indexId)
210     {
211     }
212
213     const RefPtr<IDBDatabaseBackendImpl> m_database;
214     const int64_t m_objectStoreId;
215     const int64_t m_indexId;
216 };
217
218 class DeleteIndexAbortOperation : public IDBTransactionBackendImpl::Operation {
219 public:
220     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
221     {
222         return adoptPtr(new DeleteIndexAbortOperation(database, objectStoreId, indexMetadata));
223     }
224     virtual void perform(IDBTransactionBackendImpl*);
225 private:
226     DeleteIndexAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
227         : m_database(database)
228         , m_objectStoreId(objectStoreId)
229         , m_indexMetadata(indexMetadata)
230     {
231     }
232
233     const RefPtr<IDBDatabaseBackendImpl> m_database;
234     const int64_t m_objectStoreId;
235     const IDBIndexMetadata m_indexMetadata;
236 };
237
238 class GetOperation : public IDBTransactionBackendImpl::Operation {
239 public:
240     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, const IDBDatabaseMetadata& metadata, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks)
241     {
242         return adoptPtr(new GetOperation(backingStore, metadata, objectStoreId, indexId, keyRange, cursorType, callbacks));
243     }
244     virtual void perform(IDBTransactionBackendImpl*);
245 private:
246     GetOperation(PassRefPtr<IDBBackingStore> backingStore, const IDBDatabaseMetadata& metadata, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, IDBCursorBackendInterface::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks)
247         : m_backingStore(backingStore)
248         , m_databaseId(metadata.id)
249         , m_objectStoreId(objectStoreId)
250         , m_indexId(indexId)
251         , m_keyPath(metadata.objectStores.get(objectStoreId).keyPath)
252         , m_autoIncrement(metadata.objectStores.get(objectStoreId).autoIncrement)
253         , m_keyRange(keyRange)
254         , m_cursorType(cursorType)
255         , m_callbacks(callbacks)
256     {
257         ASSERT(metadata.objectStores.contains(objectStoreId));
258         ASSERT(metadata.objectStores.get(objectStoreId).id == objectStoreId);
259     }
260
261     const RefPtr<IDBBackingStore> m_backingStore;
262     const int64_t m_databaseId;
263     const int64_t m_objectStoreId;
264     const int64_t m_indexId;
265     const IDBKeyPath m_keyPath;
266     const bool m_autoIncrement;
267     const RefPtr<IDBKeyRange> m_keyRange;
268     const IDBCursorBackendInterface::CursorType m_cursorType;
269     const RefPtr<IDBCallbacks> m_callbacks;
270 };
271
272 class PutOperation : public IDBTransactionBackendImpl::Operation {
273 public:
274     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, const IDBObjectStoreMetadata& objectStore, Vector<uint8_t>& value, PassRefPtr<IDBKey> key, IDBDatabaseBackendInterface::PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, const Vector<int64_t>& indexIds, const Vector<IDBDatabaseBackendInterface::IndexKeys>& indexKeys)
275     {
276         return adoptPtr(new PutOperation(backingStore, databaseId, objectStore, value, key, putMode, callbacks, indexIds, indexKeys));
277     }
278     virtual void perform(IDBTransactionBackendImpl*);
279 private:
280     PutOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, const IDBObjectStoreMetadata& objectStore, Vector<uint8_t>& value, PassRefPtr<IDBKey> key, IDBDatabaseBackendInterface::PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, const Vector<int64_t>& indexIds, const Vector<IDBDatabaseBackendInterface::IndexKeys>& indexKeys)
281         : m_backingStore(backingStore)
282         , m_databaseId(databaseId)
283         , m_objectStore(objectStore)
284         , m_key(key)
285         , m_putMode(putMode)
286         , m_callbacks(callbacks)
287         , m_indexIds(indexIds)
288         , m_indexKeys(indexKeys)
289     {
290         m_value.swap(value);
291     }
292
293     const RefPtr<IDBBackingStore> m_backingStore;
294     const int64_t m_databaseId;
295     const IDBObjectStoreMetadata m_objectStore;
296     Vector<uint8_t> m_value;
297     const RefPtr<IDBKey> m_key;
298     const IDBDatabaseBackendInterface::PutMode m_putMode;
299     const RefPtr<IDBCallbacks> m_callbacks;
300     const Vector<int64_t> m_indexIds;
301     const Vector<IDBDatabaseBackendInterface::IndexKeys> m_indexKeys;
302 };
303
304 class SetIndexesReadyOperation : public IDBTransactionBackendImpl::Operation {
305 public:
306     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(size_t indexCount)
307     {
308         return adoptPtr(new SetIndexesReadyOperation(indexCount));
309     }
310     virtual void perform(IDBTransactionBackendImpl*);
311 private:
312     SetIndexesReadyOperation(size_t indexCount)
313         : m_indexCount(indexCount)
314     {
315     }
316
317     const size_t m_indexCount;
318 };
319
320 class OpenCursorOperation : public IDBTransactionBackendImpl::Operation {
321 public:
322     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, IDBCursorBackendInterface::CursorType cursorType, IDBDatabaseBackendInterface::TaskType taskType, PassRefPtr<IDBCallbacks> callbacks)
323     {
324         return adoptPtr(new OpenCursorOperation(backingStore, databaseId, objectStoreId, indexId, keyRange, direction, cursorType, taskType, callbacks));
325     }
326     virtual void perform(IDBTransactionBackendImpl*);
327 private:
328     OpenCursorOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, IDBCursorBackendInterface::CursorType cursorType, IDBDatabaseBackendInterface::TaskType taskType, PassRefPtr<IDBCallbacks> callbacks)
329         : m_backingStore(backingStore)
330         , m_databaseId(databaseId)
331         , m_objectStoreId(objectStoreId)
332         , m_indexId(indexId)
333         , m_keyRange(keyRange)
334         , m_direction(direction)
335         , m_cursorType(cursorType)
336         , m_taskType(taskType)
337         , m_callbacks(callbacks)
338     {
339     }
340
341     const RefPtr<IDBBackingStore> m_backingStore;
342     const int64_t m_databaseId;
343     const int64_t m_objectStoreId;
344     const int64_t m_indexId;
345     const PassRefPtr<IDBKeyRange> m_keyRange;
346     const unsigned short m_direction;
347     const IDBCursorBackendInterface::CursorType m_cursorType;
348     const IDBDatabaseBackendInterface::TaskType m_taskType;
349     const RefPtr<IDBCallbacks> m_callbacks;
350 };
351
352 class CountOperation : public IDBTransactionBackendImpl::Operation {
353 public:
354     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
355     {
356         return adoptPtr(new CountOperation(backingStore, databaseId, objectStoreId, indexId, keyRange, callbacks));
357     }
358     virtual void perform(IDBTransactionBackendImpl*);
359 private:
360     CountOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
361         : m_backingStore(backingStore)
362         , m_databaseId(databaseId)
363         , m_objectStoreId(objectStoreId)
364         , m_indexId(indexId)
365         , m_keyRange(keyRange)
366         , m_callbacks(callbacks)
367     {
368     }
369
370     const RefPtr<IDBBackingStore> m_backingStore;
371     const int64_t m_databaseId;
372     const int64_t m_objectStoreId;
373     const int64_t m_indexId;
374     const RefPtr<IDBKeyRange> m_keyRange;
375     const RefPtr<IDBCallbacks> m_callbacks;
376 };
377
378 class DeleteRangeOperation : public IDBTransactionBackendImpl::Operation {
379 public:
380     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
381     {
382         return adoptPtr(new DeleteRangeOperation(backingStore, databaseId, objectStoreId, keyRange, callbacks));
383     }
384     virtual void perform(IDBTransactionBackendImpl*);
385 private:
386     DeleteRangeOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
387         : m_backingStore(backingStore)
388         , m_databaseId(databaseId)
389         , m_objectStoreId(objectStoreId)
390         , m_keyRange(keyRange)
391         , m_callbacks(callbacks)
392     {
393     }
394
395     const RefPtr<IDBBackingStore> m_backingStore;
396     const int64_t m_databaseId;
397     const int64_t m_objectStoreId;
398     const RefPtr<IDBKeyRange> m_keyRange;
399     const RefPtr<IDBCallbacks> m_callbacks;
400 };
401
402 class ClearOperation : public IDBTransactionBackendImpl::Operation {
403 public:
404     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBCallbacks> callbacks)
405     {
406         return adoptPtr(new ClearOperation(backingStore, databaseId, objectStoreId, callbacks));
407     }
408     virtual void perform(IDBTransactionBackendImpl*);
409 private:
410     ClearOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBCallbacks> callbacks)
411         : m_backingStore(backingStore)
412         , m_databaseId(databaseId)
413         , m_objectStoreId(objectStoreId)
414         , m_callbacks(callbacks)
415     {
416     }
417
418     const RefPtr<IDBBackingStore> m_backingStore;
419     const int64_t m_databaseId;
420     const int64_t m_objectStoreId;
421     const RefPtr<IDBCallbacks> m_callbacks;
422 };
423
424 class IDBDatabaseBackendImpl::PendingOpenCall {
425 public:
426     static PassOwnPtr<PendingOpenCall> create(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, int64_t transactionId, int64_t version)
427     {
428         return adoptPtr(new PendingOpenCall(callbacks, databaseCallbacks, transactionId, version));
429     }
430     PassRefPtr<IDBCallbacks> callbacks() { return m_callbacks; }
431     PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks() { return m_databaseCallbacks; }
432     int64_t version() { return m_version; }
433     int64_t transactionId() const { return m_transactionId; }
434
435 private:
436     PendingOpenCall(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, int64_t transactionId, int64_t version)
437         : m_callbacks(callbacks)
438         , m_databaseCallbacks(databaseCallbacks)
439         , m_version(version)
440         , m_transactionId(transactionId)
441     {
442     }
443     RefPtr<IDBCallbacks> m_callbacks;
444     RefPtr<IDBDatabaseCallbacks> m_databaseCallbacks;
445     int64_t m_version;
446     const int64_t m_transactionId;
447 };
448
449 class IDBDatabaseBackendImpl::PendingDeleteCall {
450 public:
451     static PassOwnPtr<PendingDeleteCall> create(PassRefPtr<IDBCallbacks> callbacks)
452     {
453         return adoptPtr(new PendingDeleteCall(callbacks));
454     }
455     PassRefPtr<IDBCallbacks> callbacks() { return m_callbacks; }
456
457 private:
458     PendingDeleteCall(PassRefPtr<IDBCallbacks> callbacks)
459         : m_callbacks(callbacks)
460     {
461     }
462     RefPtr<IDBCallbacks> m_callbacks;
463 };
464
465 PassRefPtr<IDBDatabaseBackendImpl> IDBDatabaseBackendImpl::create(const String& name, IDBBackingStore* database, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier)
466 {
467     RefPtr<IDBDatabaseBackendImpl> backend = adoptRef(new IDBDatabaseBackendImpl(name, database, factory, uniqueIdentifier));
468     if (!backend->openInternal())
469         return 0;
470     return backend.release();
471 }
472
473 namespace {
474 const char* NoStringVersion = "";
475 }
476
477 IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBBackingStore* backingStore, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier)
478     : m_backingStore(backingStore)
479     , m_metadata(name, InvalidId, NoStringVersion, IDBDatabaseMetadata::NoIntVersion, InvalidId)
480     , m_identifier(uniqueIdentifier)
481     , m_factory(factory)
482     , m_transactionCoordinator(IDBTransactionCoordinator::create())
483     , m_closingConnection(false)
484 {
485     ASSERT(!m_metadata.name.isNull());
486 }
487
488 void IDBDatabaseBackendImpl::addObjectStore(const IDBObjectStoreMetadata& objectStore, int64_t newMaxObjectStoreId)
489 {
490     ASSERT(!m_metadata.objectStores.contains(objectStore.id));
491     if (newMaxObjectStoreId != IDBObjectStoreMetadata::InvalidId) {
492         ASSERT(m_metadata.maxObjectStoreId < newMaxObjectStoreId);
493         m_metadata.maxObjectStoreId = newMaxObjectStoreId;
494     }
495     m_metadata.objectStores.set(objectStore.id, objectStore);
496 }
497
498 void IDBDatabaseBackendImpl::removeObjectStore(int64_t objectStoreId)
499 {
500     ASSERT(m_metadata.objectStores.contains(objectStoreId));
501     m_metadata.objectStores.remove(objectStoreId);
502 }
503
504 void IDBDatabaseBackendImpl::addIndex(int64_t objectStoreId, const IDBIndexMetadata& index, int64_t newMaxIndexId)
505 {
506     ASSERT(m_metadata.objectStores.contains(objectStoreId));
507     IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
508
509     ASSERT(!objectStore.indexes.contains(index.id));
510     objectStore.indexes.set(index.id, index);
511     if (newMaxIndexId != IDBIndexMetadata::InvalidId) {
512         ASSERT(objectStore.maxIndexId < newMaxIndexId);
513         objectStore.maxIndexId = newMaxIndexId;
514     }
515     m_metadata.objectStores.set(objectStoreId, objectStore);
516 }
517
518 void IDBDatabaseBackendImpl::removeIndex(int64_t objectStoreId, int64_t indexId)
519 {
520     ASSERT(m_metadata.objectStores.contains(objectStoreId));
521     IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
522
523     ASSERT(objectStore.indexes.contains(indexId));
524     objectStore.indexes.remove(indexId);
525     m_metadata.objectStores.set(objectStoreId, objectStore);
526 }
527
528 bool IDBDatabaseBackendImpl::openInternal()
529 {
530     bool success = false;
531     bool ok = m_backingStore->getIDBDatabaseMetaData(m_metadata.name, &m_metadata, success);
532     ASSERT_WITH_MESSAGE(success == (m_metadata.id != InvalidId), "success = %s, m_id = %lld", success ? "true" : "false", static_cast<long long>(m_metadata.id));
533     if (!ok)
534         return false;
535     if (success) {
536         m_backingStore->getObjectStores(m_metadata.id, &m_metadata.objectStores);
537         return true;
538     }
539     return m_backingStore->createIDBDatabaseMetaData(m_metadata.name, m_metadata.version, m_metadata.intVersion, m_metadata.id);
540 }
541
542 IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl()
543 {
544 }
545
546 PassRefPtr<IDBBackingStore> IDBDatabaseBackendImpl::backingStore() const
547 {
548     return m_backingStore;
549 }
550
551 IDBDatabaseMetadata IDBDatabaseBackendImpl::metadata() const
552 {
553     return m_metadata;
554 }
555
556 void IDBDatabaseBackendImpl::createObjectStore(int64_t transactionId, int64_t objectStoreId, const String& name, const IDBKeyPath& keyPath, bool autoIncrement)
557 {
558     IDB_TRACE("IDBDatabaseBackendImpl::createObjectStore");
559     ASSERT(!m_metadata.objectStores.contains(objectStoreId));
560
561     ASSERT(m_transactions.contains(transactionId));
562     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
563
564     IDBObjectStoreMetadata objectStoreMetadata(name, objectStoreId, keyPath, autoIncrement, IDBObjectStoreBackendInterface::MinimumIndexId);
565
566     transaction->scheduleTask(CreateObjectStoreOperation::create(m_backingStore, objectStoreMetadata), CreateObjectStoreAbortOperation::create(this, objectStoreId));
567
568     addObjectStore(objectStoreMetadata, objectStoreId);
569 }
570
571 void CreateObjectStoreOperation::perform(IDBTransactionBackendImpl* transaction)
572 {
573     IDB_TRACE("CreateObjectStoreOperation");
574     if (!m_backingStore->createObjectStore(transaction->backingStoreTransaction(), transaction->database()->id(), m_objectStoreMetadata.id, m_objectStoreMetadata.name, m_objectStoreMetadata.keyPath, m_objectStoreMetadata.autoIncrement)) {
575         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error creating object store '%s'.", m_objectStoreMetadata.name.utf8().data()));
576         transaction->abort(error.release());
577         return;
578     }
579 }
580
581 void IDBDatabaseBackendImpl::deleteObjectStore(int64_t transactionId, int64_t objectStoreId)
582 {
583     IDB_TRACE("IDBDatabaseBackendImpl::deleteObjectStore");
584     ASSERT(m_metadata.objectStores.contains(objectStoreId));
585     const IDBObjectStoreMetadata& objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
586
587     ASSERT(m_transactions.contains(transactionId));
588     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
589     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
590
591     transaction->scheduleTask(DeleteObjectStoreOperation::create(m_backingStore, objectStoreMetadata),  DeleteObjectStoreAbortOperation::create(this, objectStoreMetadata));
592     removeObjectStore(objectStoreId);
593 }
594
595 void IDBDatabaseBackendImpl::createIndex(int64_t transactionId, int64_t objectStoreId, int64_t indexId, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry)
596 {
597     IDB_TRACE("IDBDatabaseBackendImpl::createIndex");
598     ASSERT(m_metadata.objectStores.contains(objectStoreId));
599     const IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
600
601     ASSERT(!objectStore.indexes.contains(indexId));
602     const IDBIndexMetadata indexMetadata(name, indexId, keyPath, unique, multiEntry);
603
604     ASSERT(m_transactions.contains(transactionId));
605     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
606     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
607
608     transaction->scheduleTask(CreateIndexOperation::create(m_backingStore, objectStoreId, indexMetadata), CreateIndexAbortOperation::create(this, objectStoreId, indexId));
609
610     addIndex(objectStoreId, indexMetadata, indexId);
611 }
612
613
614 void CreateIndexOperation::perform(IDBTransactionBackendImpl* transaction)
615 {
616     IDB_TRACE("CreateIndexOperation");
617     if (!m_backingStore->createIndex(transaction->backingStoreTransaction(), transaction->database()->id(), m_objectStoreId, m_indexMetadata.id, m_indexMetadata.name, m_indexMetadata.keyPath, m_indexMetadata.unique, m_indexMetadata.multiEntry)) {
618         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error when trying to create index '%s'.", m_indexMetadata.name.utf8().data())));
619         return;
620     }
621 }
622
623 void CreateIndexAbortOperation::perform(IDBTransactionBackendImpl* transaction)
624 {
625     IDB_TRACE("CreateIndexAbortOperation");
626     ASSERT(!transaction);
627     m_database->removeIndex(m_objectStoreId, m_indexId);
628 }
629
630 void IDBDatabaseBackendImpl::deleteIndex(int64_t transactionId, int64_t objectStoreId, int64_t indexId)
631 {
632     IDB_TRACE("IDBDatabaseBackendImpl::deleteIndex");
633     ASSERT(m_metadata.objectStores.contains(objectStoreId));
634     const IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
635
636     ASSERT(objectStore.indexes.contains(indexId));
637     const IDBIndexMetadata& indexMetadata = objectStore.indexes.get(indexId);
638
639     ASSERT(m_transactions.contains(transactionId));
640     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
641     ASSERT(transaction->mode() == IDBTransaction::VERSION_CHANGE);
642
643     transaction->scheduleTask(DeleteIndexOperation::create(m_backingStore, objectStoreId, indexId), DeleteIndexAbortOperation::create(this, objectStoreId, indexMetadata));
644
645     removeIndex(objectStoreId, indexId);
646 }
647
648 void DeleteIndexOperation::perform(IDBTransactionBackendImpl* transaction)
649 {
650     IDB_TRACE("DeleteIndexOperation");
651     m_backingStore->deleteIndex(transaction->backingStoreTransaction(), transaction->database()->id(), m_objectStoreId, m_indexId);
652 }
653
654 void DeleteIndexAbortOperation::perform(IDBTransactionBackendImpl* transaction)
655 {
656     IDB_TRACE("DeleteIndexAbortOperation");
657     ASSERT(!transaction);
658     m_database->addIndex(m_objectStoreId, m_indexMetadata, IDBIndexMetadata::InvalidId);
659 }
660
661 void IDBDatabaseBackendImpl::commit(int64_t transactionId)
662 {
663     ASSERT(m_transactions.contains(transactionId));
664     m_transactions.get(transactionId)->commit();
665 }
666
667 void IDBDatabaseBackendImpl::abort(int64_t transactionId)
668 {
669     ASSERT(m_transactions.contains(transactionId));
670     m_transactions.get(transactionId)->abort();
671 }
672
673 void IDBDatabaseBackendImpl::get(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, bool keyOnly, PassRefPtr<IDBCallbacks> callbacks)
674 {
675     IDB_TRACE("IDBDatabaseBackendImpl::get");
676     ASSERT(m_transactions.contains(transactionId));
677     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
678
679     transaction->scheduleTask(GetOperation::create(m_backingStore, m_metadata, objectStoreId, indexId, keyRange, keyOnly ? IDBCursorBackendInterface::KeyOnly : IDBCursorBackendInterface::KeyAndValue, callbacks));
680 }
681
682 void GetOperation::perform(IDBTransactionBackendImpl* transaction)
683 {
684     IDB_TRACE("GetOperation");
685
686     RefPtr<IDBKey> key;
687
688     if (m_keyRange->isOnlyKey())
689         key = m_keyRange->lower();
690     else {
691         RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
692         if (m_indexId == IDBIndexMetadata::InvalidId) {
693             ASSERT(m_cursorType != IDBCursorBackendInterface::KeyOnly);
694             // ObjectStore Retrieval Operation
695             backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IDBCursor::NEXT);
696         } else {
697             if (m_cursorType == IDBCursorBackendInterface::KeyOnly)
698                 // Index Value Retrieval Operation
699                 backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IDBCursor::NEXT);
700             else
701                 // Index Referenced Value Retrieval Operation
702                 backingStoreCursor = m_backingStore->openIndexCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IDBCursor::NEXT);
703         }
704
705         if (!backingStoreCursor) {
706             m_callbacks->onSuccess();
707             return;
708         }
709
710         key = backingStoreCursor->key();
711     }
712
713     RefPtr<IDBKey> primaryKey;
714     bool ok;
715     if (m_indexId == IDBIndexMetadata::InvalidId) {
716         // Object Store Retrieval Operation
717         Vector<uint8_t> value;
718         ok = m_backingStore->getRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, *key, value);
719         if (!ok) {
720             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
721             return;
722         }
723
724         if (value.isEmpty()) {
725             m_callbacks->onSuccess();
726             return;
727         }
728
729         if (m_autoIncrement && !m_keyPath.isNull()) {
730             m_callbacks->onSuccess(SerializedScriptValue::createFromWireBytes(value), key, m_keyPath);
731             return;
732         }
733
734         m_callbacks->onSuccess(SerializedScriptValue::createFromWireBytes(value));
735         return;
736
737     }
738
739     // From here we are dealing only with indexes.
740     ok = m_backingStore->getPrimaryKeyViaIndex(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, *key, primaryKey);
741     if (!ok) {
742         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getPrimaryKeyViaIndex."));
743         return;
744     }
745     if (m_cursorType == IDBCursorBackendInterface::KeyOnly) {
746         // Index Value Retrieval Operation
747         m_callbacks->onSuccess(primaryKey.get());
748         return;
749     }
750
751     // Index Referenced Value Retrieval Operation
752     Vector<uint8_t> value;
753     ok = m_backingStore->getRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, *primaryKey, value);
754     if (!ok) {
755         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
756         return;
757     }
758
759     if (value.isEmpty()) {
760         m_callbacks->onSuccess();
761         return;
762     }
763     if (m_autoIncrement && !m_keyPath.isNull()) {
764         m_callbacks->onSuccess(SerializedScriptValue::createFromWireBytes(value), primaryKey, m_keyPath);
765         return;
766     }
767     m_callbacks->onSuccess(SerializedScriptValue::createFromWireBytes(value));
768 }
769
770 void IDBDatabaseBackendImpl::put(int64_t transactionId, int64_t objectStoreId, Vector<uint8_t>* value, PassRefPtr<IDBKey> key, PutMode putMode, PassRefPtr<IDBCallbacks> callbacks, const Vector<int64_t>& indexIds, const Vector<IndexKeys>& indexKeys)
771 {
772     IDB_TRACE("IDBDatabaseBackendImpl::put");
773
774     ASSERT(m_transactions.contains(transactionId));
775     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
776     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
777
778     const IDBObjectStoreMetadata objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
779
780     ASSERT(objectStoreMetadata.autoIncrement || key.get());
781
782     transaction->scheduleTask(PutOperation::create(m_backingStore, id(), objectStoreMetadata, *value, key, putMode, callbacks, indexIds, indexKeys));
783 }
784
785 void PutOperation::perform(IDBTransactionBackendImpl* transaction)
786 {
787     IDB_TRACE("PutOperation");
788     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
789     ASSERT(m_indexIds.size() == m_indexKeys.size());
790     bool keyWasGenerated = false;
791
792     RefPtr<IDBKey> key;
793     if (m_putMode != IDBDatabaseBackendInterface::CursorUpdate && m_objectStore.autoIncrement && !m_key) {
794         RefPtr<IDBKey> autoIncKey = IDBObjectStoreBackendImpl::generateKey(m_backingStore, transaction, m_databaseId, m_objectStore.id);
795         keyWasGenerated = true;
796         if (!autoIncKey->isValid()) {
797             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Maximum key generator value reached."));
798             return;
799         }
800         key = autoIncKey;
801     } else
802         key = m_key;
803
804     ASSERT(key && key->isValid());
805
806     IDBBackingStore::RecordIdentifier recordIdentifier;
807     if (m_putMode == IDBDatabaseBackendInterface::AddOnly) {
808         bool found = false;
809         bool ok = m_backingStore->keyExistsInObjectStore(transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id, *key, &recordIdentifier, found);
810         if (!ok) {
811             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error checking key existence."));
812             return;
813         }
814         if (found) {
815             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Key already exists in the object store."));
816             return;
817         }
818     }
819
820     Vector<OwnPtr<IDBObjectStoreBackendImpl::IndexWriter> > indexWriters;
821     String errorMessage;
822     bool obeysConstraints = false;
823     bool backingStoreSuccess = IDBObjectStoreBackendImpl::makeIndexWriters(transaction, m_backingStore.get(), m_databaseId, m_objectStore, key, keyWasGenerated, m_indexIds, m_indexKeys, &indexWriters, &errorMessage, obeysConstraints);
824     if (!backingStoreSuccess) {
825         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
826         return;
827     }
828     if (!obeysConstraints) {
829         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
830         return;
831     }
832
833     // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
834     backingStoreSuccess = m_backingStore->putRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id, *key, m_value, &recordIdentifier);
835     if (!backingStoreSuccess) {
836         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error performing put/add."));
837         return;
838     }
839
840     for (size_t i = 0; i < indexWriters.size(); ++i) {
841         IDBObjectStoreBackendImpl::IndexWriter* indexWriter = indexWriters[i].get();
842         indexWriter->writeIndexKeys(recordIdentifier, *m_backingStore, transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id);
843     }
844
845     if (m_objectStore.autoIncrement && m_putMode != IDBDatabaseBackendInterface::CursorUpdate && key->type() == IDBKey::NumberType) {
846         bool ok = IDBObjectStoreBackendImpl::updateKeyGenerator(m_backingStore, transaction, m_databaseId, m_objectStore.id, key.get(), !keyWasGenerated);
847         if (!ok) {
848             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error updating key generator."));
849             return;
850         }
851     }
852
853     m_callbacks->onSuccess(key.release());
854 }
855
856
857 void IDBDatabaseBackendImpl::setIndexKeys(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKey> prpPrimaryKey, const Vector<int64_t>& indexIds, const Vector<IndexKeys>& indexKeys)
858 {
859     IDB_TRACE("IDBDatabaseBackendImpl::setIndexKeys");
860     if (!m_transactions.contains(transactionId))
861         return;
862
863     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
864     if (transaction->isFinished())
865         return;
866
867     RefPtr<IDBKey> primaryKey = prpPrimaryKey;
868     RefPtr<IDBBackingStore> store = backingStore();
869     // FIXME: This method could be asynchronous, but we need to evaluate if it's worth the extra complexity.
870     IDBBackingStore::RecordIdentifier recordIdentifier;
871     bool found = false;
872     bool ok = store->keyExistsInObjectStore(transaction->backingStoreTransaction(), m_metadata.id, objectStoreId, *primaryKey, &recordIdentifier, found);
873     if (!ok) {
874         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error setting index keys."));
875         return;
876     }
877     if (!found) {
878         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error setting index keys for object store."));
879         transaction->abort(error.release());
880         return;
881     }
882
883     Vector<OwnPtr<IDBObjectStoreBackendImpl::IndexWriter> > indexWriters;
884     String errorMessage;
885     bool obeysConstraints = false;
886     ASSERT(m_metadata.objectStores.contains(objectStoreId));
887     const IDBObjectStoreMetadata& objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
888     bool backingStoreSuccess = IDBObjectStoreBackendImpl::makeIndexWriters(transaction, store.get(), id(), objectStoreMetadata, primaryKey, false, indexIds, indexKeys, &indexWriters, &errorMessage, obeysConstraints);
889     if (!backingStoreSuccess) {
890         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
891         return;
892     }
893     if (!obeysConstraints) {
894         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
895         return;
896     }
897
898     for (size_t i = 0; i < indexWriters.size(); ++i) {
899         IDBObjectStoreBackendImpl::IndexWriter* indexWriter = indexWriters[i].get();
900         indexWriter->writeIndexKeys(recordIdentifier, *store.get(), transaction->backingStoreTransaction(), id(), objectStoreId);
901     }
902 }
903
904 void IDBDatabaseBackendImpl::setIndexesReady(int64_t transactionId, int64_t objectStoreId, const Vector<int64_t>& indexIds)
905 {
906     IDB_TRACE("IDBObjectStoreBackendImpl::setIndexesReady");
907
908     if (!m_transactions.contains(transactionId))
909         return;
910
911     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
912     if (transaction->isFinished())
913         return;
914
915     if (!transaction->scheduleTask(IDBTransactionBackendInterface::PreemptiveTask, SetIndexesReadyOperation::create(indexIds.size())))
916         ASSERT_NOT_REACHED();
917 }
918
919 void SetIndexesReadyOperation::perform(IDBTransactionBackendImpl* transaction)
920 {
921     IDB_TRACE("SetIndexesReadyOperation");
922     for (size_t i = 0; i < m_indexCount; ++i)
923         transaction->didCompletePreemptiveEvent();
924 }
925
926 void IDBDatabaseBackendImpl::openCursor(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, unsigned short direction, bool keyOnly, TaskType taskType, PassRefPtr<IDBCallbacks> callbacks)
927 {
928     IDB_TRACE("IDBDatabaseBackendImpl::openCursor");
929     ASSERT(m_transactions.contains(transactionId));
930     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
931
932     transaction->scheduleTask(OpenCursorOperation::create(m_backingStore, id(), objectStoreId, indexId, keyRange, direction, keyOnly ? IDBCursorBackendInterface::KeyOnly : IDBCursorBackendInterface::KeyAndValue, taskType, callbacks));
933 }
934
935 void OpenCursorOperation::perform(IDBTransactionBackendImpl* transaction)
936 {
937     IDB_TRACE("OpenCursorOperation");
938
939     // The frontend has begun indexing, so this pauses the transaction
940     // until the indexing is complete. This can't happen any earlier
941     // because we don't want to switch to early mode in case multiple
942     // indexes are being created in a row, with put()'s in between.
943     if (m_taskType == IDBDatabaseBackendInterface::PreemptiveTask)
944         transaction->addPreemptiveEvent();
945
946     IDBCursor::Direction direction = static_cast<IDBCursor::Direction>(m_direction);
947     RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
948     if (m_indexId == IDBIndexMetadata::InvalidId) {
949         ASSERT(m_cursorType != IDBCursorBackendInterface::KeyOnly);
950         backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), direction);
951     } else {
952         ASSERT(m_taskType == IDBDatabaseBackendInterface::NormalTask);
953         if (m_cursorType == IDBCursorBackendInterface::KeyOnly)
954             backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), direction);
955         else
956             backingStoreCursor = m_backingStore->openIndexCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), direction);
957     }
958
959     if (!backingStoreCursor) {
960         m_callbacks->onSuccess(static_cast<SerializedScriptValue*>(0));
961         return;
962     }
963
964     IDBTransactionBackendInterface::TaskType taskType(static_cast<IDBTransactionBackendInterface::TaskType>(m_taskType));
965     RefPtr<IDBCursorBackendImpl> cursor = IDBCursorBackendImpl::create(backingStoreCursor.get(), m_cursorType, taskType, transaction, m_objectStoreId);
966     m_callbacks->onSuccess(cursor, cursor->key(), cursor->primaryKey(), cursor->value());
967 }
968
969 void IDBDatabaseBackendImpl::count(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
970 {
971     IDB_TRACE("IDBDatabaseBackendImpl::count");
972     ASSERT(m_transactions.contains(transactionId));
973     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
974     ASSERT(m_metadata.objectStores.contains(objectStoreId));
975     transaction->scheduleTask(CountOperation::create(m_backingStore, id(), objectStoreId, indexId, keyRange, callbacks));
976 }
977
978 void CountOperation::perform(IDBTransactionBackendImpl* transaction)
979 {
980     IDB_TRACE("CountOperation");
981     uint32_t count = 0;
982     RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
983
984     if (m_indexId == IDBIndexMetadata::InvalidId)
985         backingStoreCursor = m_backingStore->openObjectStoreKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IDBCursor::NEXT);
986     else
987         backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IDBCursor::NEXT);
988     if (!backingStoreCursor) {
989         m_callbacks->onSuccess(count);
990         return;
991     }
992
993     do {
994         ++count;
995     } while (backingStoreCursor->continueFunction(0));
996
997     m_callbacks->onSuccess(count);
998 }
999
1000 void IDBDatabaseBackendImpl::deleteRange(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
1001 {
1002     IDB_TRACE("IDBDatabaseBackendImpl::deleteRange");
1003
1004     ASSERT(m_transactions.contains(transactionId));
1005     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
1006     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
1007
1008     transaction->scheduleTask(DeleteRangeOperation::create(m_backingStore, id(), objectStoreId, keyRange, callbacks));
1009 }
1010
1011 void DeleteRangeOperation::perform(IDBTransactionBackendImpl* transaction)
1012 {
1013     IDB_TRACE("DeleteRangeOperation");
1014     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IDBCursor::NEXT);
1015     if (backingStoreCursor) {
1016         do {
1017             m_backingStore->deleteRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, backingStoreCursor->recordIdentifier());
1018         } while (backingStoreCursor->continueFunction(0));
1019     }
1020
1021     m_callbacks->onSuccess();
1022 }
1023
1024 void IDBDatabaseBackendImpl::clear(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBCallbacks> callbacks)
1025 {
1026     IDB_TRACE("IDBDatabaseBackendImpl::clear");
1027
1028     ASSERT(m_transactions.contains(transactionId));
1029     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
1030     ASSERT(transaction->mode() != IDBTransaction::READ_ONLY);
1031
1032     transaction->scheduleTask(ClearOperation::create(m_backingStore, id(), objectStoreId, callbacks));
1033 }
1034
1035 void ClearOperation::perform(IDBTransactionBackendImpl* transaction)
1036 {
1037     IDB_TRACE("ObjectStoreClearOperation");
1038     m_backingStore->clearObjectStore(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId);
1039     m_callbacks->onSuccess();
1040 }
1041
1042 void DeleteObjectStoreOperation::perform(IDBTransactionBackendImpl* transaction)
1043 {
1044     IDB_TRACE("DeleteObjectStoreOperation");
1045     bool ok = m_backingStore->deleteObjectStore(transaction->backingStoreTransaction(), transaction->database()->id(), m_objectStoreMetadata.id);
1046     if (!ok) {
1047         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting object store '%s'.", m_objectStoreMetadata.name.utf8().data()));
1048         transaction->abort(error);
1049     }
1050 }
1051
1052 void IDBDatabaseBackendImpl::VersionChangeOperation::perform(IDBTransactionBackendImpl* transaction)
1053 {
1054     IDB_TRACE("VersionChangeOperation");
1055     int64_t databaseId = m_database->id();
1056     int64_t oldVersion = m_database->m_metadata.intVersion;
1057     ASSERT(m_version > oldVersion);
1058     m_database->m_metadata.intVersion = m_version;
1059     if (!m_database->m_backingStore->updateIDBDatabaseIntVersion(transaction->backingStoreTransaction(), databaseId, m_database->m_metadata.intVersion)) {
1060         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error writing data to stable storage when updating version.");
1061         m_callbacks->onError(error);
1062         transaction->abort(error);
1063         return;
1064     }
1065     ASSERT(!m_database->m_pendingSecondHalfOpen);
1066     m_database->m_pendingSecondHalfOpen = PendingOpenCall::create(m_callbacks, m_databaseCallbacks, m_transactionId, m_version);
1067     m_callbacks->onUpgradeNeeded(oldVersion, transaction, m_database);
1068 }
1069
1070 void IDBDatabaseBackendImpl::transactionStarted(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
1071 {
1072     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
1073     if (transaction->mode() == IDBTransaction::VERSION_CHANGE) {
1074         ASSERT(!m_runningVersionChangeTransaction);
1075         m_runningVersionChangeTransaction = transaction;
1076     }
1077 }
1078
1079 void IDBDatabaseBackendImpl::transactionFinished(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
1080 {
1081     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
1082     ASSERT(m_transactions.contains(transaction->id()));
1083     ASSERT(m_transactions.get(transaction->id()) == transaction.get());
1084     m_transactions.remove(transaction->id());
1085     if (transaction->mode() == IDBTransaction::VERSION_CHANGE) {
1086         ASSERT(transaction.get() == m_runningVersionChangeTransaction.get());
1087         m_runningVersionChangeTransaction.clear();
1088     }
1089 }
1090
1091 void IDBDatabaseBackendImpl::transactionFinishedAndAbortFired(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
1092 {
1093     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
1094     if (transaction->mode() == IDBTransaction::VERSION_CHANGE) {
1095         // If this was an open-with-version call, there will be a "second
1096         // half" open call waiting for us in processPendingCalls.
1097         // FIXME: When we no longer support setVersion, assert such a thing.
1098         if (m_pendingSecondHalfOpen) {
1099             m_pendingSecondHalfOpen->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "Version change transaction was aborted in upgradeneeded event handler."));
1100             m_pendingSecondHalfOpen.release();
1101         }
1102         processPendingCalls();
1103     }
1104 }
1105
1106 void IDBDatabaseBackendImpl::transactionFinishedAndCompleteFired(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
1107 {
1108     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
1109     if (transaction->mode() == IDBTransaction::VERSION_CHANGE)
1110         processPendingCalls();
1111 }
1112
1113 size_t IDBDatabaseBackendImpl::connectionCount()
1114 {
1115     // This does not include pending open calls, as those should not block version changes and deletes.
1116     return m_databaseCallbacksSet.size();
1117 }
1118
1119 void IDBDatabaseBackendImpl::processPendingCalls()
1120 {
1121     if (m_pendingSecondHalfOpen) {
1122         ASSERT(m_pendingSecondHalfOpen->version() == m_metadata.intVersion);
1123         ASSERT(m_metadata.id != InvalidId);
1124         m_pendingSecondHalfOpen->callbacks()->onSuccess(this);
1125         m_pendingSecondHalfOpen.release();
1126         // Fall through when complete, as pending deletes may be (partially) unblocked.
1127     }
1128
1129     // Note that this check is only an optimization to reduce queue-churn and
1130     // not necessary for correctness; deleteDatabase and openConnection will
1131     // requeue their calls if this condition is true.
1132     if (m_runningVersionChangeTransaction)
1133         return;
1134
1135     if (!m_pendingDeleteCalls.isEmpty() && isDeleteDatabaseBlocked())
1136         return;
1137     while (!m_pendingDeleteCalls.isEmpty()) {
1138         OwnPtr<PendingDeleteCall> pendingDeleteCall = m_pendingDeleteCalls.takeFirst();
1139         deleteDatabaseFinal(pendingDeleteCall->callbacks());
1140     }
1141     // deleteDatabaseFinal should never re-queue calls.
1142     ASSERT(m_pendingDeleteCalls.isEmpty());
1143
1144     // This check is also not really needed, openConnection would just requeue its calls.
1145     if (m_runningVersionChangeTransaction)
1146         return;
1147
1148     // Open calls can be requeued if an open call started a version change transaction.
1149     Deque<OwnPtr<PendingOpenCall> > pendingOpenCalls;
1150     m_pendingOpenCalls.swap(pendingOpenCalls);
1151     while (!pendingOpenCalls.isEmpty()) {
1152         OwnPtr<PendingOpenCall> pendingOpenCall = pendingOpenCalls.takeFirst();
1153         openConnection(pendingOpenCall->callbacks(), pendingOpenCall->databaseCallbacks(), pendingOpenCall->transactionId(), pendingOpenCall->version());
1154     }
1155 }
1156
1157 // FIXME: Remove this method in https://bugs.webkit.org/show_bug.cgi?id=103923.
1158 PassRefPtr<IDBTransactionBackendInterface> IDBDatabaseBackendImpl::createTransaction(int64_t transactionId, const Vector<int64_t>& objectStoreIds, IDBTransaction::Mode mode)
1159 {
1160     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::create(transactionId, objectStoreIds, mode, this);
1161     ASSERT(!m_transactions.contains(transactionId));
1162     m_transactions.add(transactionId, transaction.get());
1163     return transaction.release();
1164 }
1165
1166 void IDBDatabaseBackendImpl::createTransaction(int64_t transactionId, PassRefPtr<IDBDatabaseCallbacks> callbacks, const Vector<int64_t>& objectStoreIds, unsigned short mode)
1167 {
1168     ASSERT_NOT_REACHED();
1169 }
1170
1171 void IDBDatabaseBackendImpl::openConnection(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, int64_t version)
1172 {
1173     ASSERT(m_backingStore.get());
1174     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
1175     RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
1176
1177     if (!m_pendingDeleteCalls.isEmpty() || m_runningVersionChangeTransaction) {
1178         m_pendingOpenCalls.append(PendingOpenCall::create(callbacks, databaseCallbacks, transactionId, version));
1179         return;
1180     }
1181
1182     if (m_metadata.id == InvalidId) {
1183         // The database was deleted then immediately re-opened; openInternal() recreates it in the backing store.
1184         if (openInternal())
1185             ASSERT(m_metadata.intVersion == IDBDatabaseMetadata::NoIntVersion);
1186         else {
1187             String message;
1188             RefPtr<IDBDatabaseError> error;
1189             if (version == IDBDatabaseMetadata::NoIntVersion)
1190                 message = "Internal error opening database with no version specified.";
1191             else
1192                 message = String::format("Internal error opening database with version %lld", static_cast<long long>(version));
1193             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, message));
1194             return;
1195         }
1196     }
1197
1198     // We infer that the database didn't exist from its lack of either type of version.
1199     bool isNewDatabase = m_metadata.version == NoStringVersion && m_metadata.intVersion == IDBDatabaseMetadata::NoIntVersion;
1200
1201     if (version == IDBDatabaseMetadata::DefaultIntVersion) {
1202         // For unit tests only - skip upgrade steps. Calling from script with DefaultIntVersion throws exception.
1203         ASSERT(isNewDatabase);
1204         m_databaseCallbacksSet.add(databaseCallbacks);
1205         callbacks->onSuccess(this);
1206         return;
1207     }
1208
1209     if (version == IDBDatabaseMetadata::NoIntVersion) {
1210         if (!isNewDatabase) {
1211             m_databaseCallbacksSet.add(RefPtr<IDBDatabaseCallbacks>(databaseCallbacks));
1212             callbacks->onSuccess(this);
1213             return;
1214         }
1215         // Spec says: If no version is specified and no database exists, set database version to 1.
1216         version = 1;
1217     }
1218
1219     if (version > m_metadata.intVersion) {
1220         runIntVersionChangeTransaction(callbacks, databaseCallbacks, transactionId, version);
1221         return;
1222     }
1223     if (version < m_metadata.intVersion) {
1224         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::VersionError, String::format("The requested version (%lld) is less than the existing version (%lld).", static_cast<long long>(version), static_cast<long long>(m_metadata.intVersion))));
1225         return;
1226     }
1227     ASSERT(version == m_metadata.intVersion);
1228     m_databaseCallbacksSet.add(databaseCallbacks);
1229     callbacks->onSuccess(this);
1230 }
1231
1232 void IDBDatabaseBackendImpl::runIntVersionChangeTransaction(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, int64_t requestedVersion)
1233 {
1234     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
1235     RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
1236     ASSERT(callbacks);
1237     for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) {
1238         // Front end ensures the event is not fired at connections that have closePending set.
1239         if (*it != databaseCallbacks)
1240             (*it)->onVersionChange(m_metadata.intVersion, requestedVersion);
1241     }
1242     // The spec dictates we wait until all the version change events are
1243     // delivered and then check m_databaseCallbacks.empty() before proceeding
1244     // or firing a blocked event, but instead we should be consistent with how
1245     // the old setVersion (incorrectly) did it.
1246     // FIXME: Remove the call to onBlocked and instead wait until the frontend
1247     // tells us that all the blocked events have been delivered. See
1248     // https://bugs.webkit.org/show_bug.cgi?id=71130
1249     if (connectionCount())
1250         callbacks->onBlocked(m_metadata.intVersion);
1251     // FIXME: Add test for m_runningVersionChangeTransaction.
1252     if (m_runningVersionChangeTransaction || connectionCount()) {
1253         m_pendingOpenCalls.append(PendingOpenCall::create(callbacks, databaseCallbacks, transactionId, requestedVersion));
1254         return;
1255     }
1256
1257     Vector<int64_t> objectStoreIds;
1258     RefPtr<IDBTransactionBackendInterface> transactionInterface = createTransaction(transactionId, objectStoreIds, IDBTransaction::VERSION_CHANGE);
1259     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::from(transactionInterface.get());
1260
1261     if (!transaction->scheduleTask(VersionChangeOperation::create(this, transactionId, requestedVersion, callbacks, databaseCallbacks), VersionChangeAbortOperation::create(this, m_metadata.version, m_metadata.intVersion))) {
1262         ASSERT_NOT_REACHED();
1263     }
1264     ASSERT(!m_pendingSecondHalfOpen);
1265     m_databaseCallbacksSet.add(databaseCallbacks);
1266 }
1267
1268 void IDBDatabaseBackendImpl::deleteDatabase(PassRefPtr<IDBCallbacks> prpCallbacks)
1269 {
1270     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
1271     if (isDeleteDatabaseBlocked()) {
1272         for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) {
1273             // Front end ensures the event is not fired at connections that have closePending set.
1274             (*it)->onVersionChange(NoStringVersion);
1275         }
1276         // FIXME: Only fire onBlocked if there are open connections after the
1277         // VersionChangeEvents are received, not just set up to fire.
1278         // https://bugs.webkit.org/show_bug.cgi?id=71130
1279         callbacks->onBlocked();
1280         m_pendingDeleteCalls.append(PendingDeleteCall::create(callbacks.release()));
1281         return;
1282     }
1283     deleteDatabaseFinal(callbacks.release());
1284 }
1285
1286 bool IDBDatabaseBackendImpl::isDeleteDatabaseBlocked()
1287 {
1288     return connectionCount();
1289 }
1290
1291 void IDBDatabaseBackendImpl::deleteDatabaseFinal(PassRefPtr<IDBCallbacks> callbacks)
1292 {
1293     ASSERT(!isDeleteDatabaseBlocked());
1294     ASSERT(m_backingStore);
1295     if (!m_backingStore->deleteDatabase(m_metadata.name)) {
1296         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error deleting database."));
1297         return;
1298     }
1299     m_metadata.version = NoStringVersion;
1300     m_metadata.id = InvalidId;
1301     m_metadata.intVersion = IDBDatabaseMetadata::NoIntVersion;
1302     m_metadata.objectStores.clear();
1303     callbacks->onSuccess();
1304 }
1305
1306 void IDBDatabaseBackendImpl::close(PassRefPtr<IDBDatabaseCallbacks> prpCallbacks)
1307 {
1308     RefPtr<IDBDatabaseCallbacks> callbacks = prpCallbacks;
1309     ASSERT(m_databaseCallbacksSet.contains(callbacks));
1310
1311     m_databaseCallbacksSet.remove(callbacks);
1312     if (m_pendingSecondHalfOpen && m_pendingSecondHalfOpen->databaseCallbacks() == callbacks) {
1313         m_pendingSecondHalfOpen->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "The connection was closed."));
1314         m_pendingSecondHalfOpen.release();
1315     }
1316
1317     if (connectionCount() > 1)
1318         return;
1319
1320     // processPendingCalls allows the inspector to process a pending open call
1321     // and call close, reentering IDBDatabaseBackendImpl::close. Then the
1322     // backend would be removed both by the inspector closing its connection, and
1323     // by the connection that first called close.
1324     // To avoid that situation, don't proceed in case of reentrancy.
1325     if (m_closingConnection)
1326         return;
1327     m_closingConnection = true;
1328     processPendingCalls();
1329
1330     // FIXME: Add a test for the m_pendingOpenCalls cases below.
1331     if (!connectionCount() && !m_pendingOpenCalls.size() && !m_pendingDeleteCalls.size()) {
1332         TransactionMap transactions(m_transactions);
1333         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Connection is closing.");
1334         for (TransactionMap::const_iterator::Values it = transactions.values().begin(), end = transactions.values().end(); it != end; ++it)
1335             (*it)->abort(error);
1336
1337         ASSERT(m_transactions.isEmpty());
1338
1339         m_backingStore.clear();
1340         // This check should only be false in tests.
1341         if (m_factory)
1342             m_factory->removeIDBDatabaseBackend(m_identifier);
1343     }
1344     m_closingConnection = false;
1345 }
1346
1347 void CreateObjectStoreAbortOperation::perform(IDBTransactionBackendImpl* transaction)
1348 {
1349     IDB_TRACE("CreateObjectStoreAbortOperation");
1350     ASSERT(!transaction);
1351     m_database->removeObjectStore(m_objectStoreId);
1352 }
1353
1354 void DeleteObjectStoreAbortOperation::perform(IDBTransactionBackendImpl* transaction)
1355 {
1356     IDB_TRACE("DeleteObjectStoreAbortOperation");
1357     ASSERT(!transaction);
1358     m_database->addObjectStore(m_objectStoreMetadata, IDBObjectStoreMetadata::InvalidId);
1359 }
1360
1361 void IDBDatabaseBackendImpl::VersionChangeAbortOperation::perform(IDBTransactionBackendImpl* transaction)
1362 {
1363     IDB_TRACE("VersionChangeAbortOperation");
1364     ASSERT(!transaction);
1365     m_database->m_metadata.version = m_previousVersion;
1366     m_database->m_metadata.intVersion = m_previousIntVersion;
1367 }
1368
1369 } // namespace WebCore
1370
1371 #endif // ENABLE(INDEXED_DATABASE)