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