Unreviewed, rolling out r145435.
[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 "IDBKeyRange.h"
36 #include "IDBObjectStoreBackendImpl.h"
37 #include "IDBTracing.h"
38 #include "IDBTransactionBackendImpl.h"
39 #include "IDBTransactionCoordinator.h"
40 #include "SharedBuffer.h"
41
42 namespace WebCore {
43
44 class CreateObjectStoreOperation : public IDBTransactionBackendImpl::Operation {
45 public:
46     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, const IDBObjectStoreMetadata& objectStoreMetadata)
47     {
48         return adoptPtr(new CreateObjectStoreOperation(backingStore, objectStoreMetadata));
49     }
50     virtual void perform(IDBTransactionBackendImpl*);
51 private:
52     CreateObjectStoreOperation(PassRefPtr<IDBBackingStore> backingStore, const IDBObjectStoreMetadata& objectStoreMetadata)
53         : m_backingStore(backingStore)
54         , m_objectStoreMetadata(objectStoreMetadata)
55     {
56     }
57
58     const RefPtr<IDBBackingStore> m_backingStore;
59     const IDBObjectStoreMetadata m_objectStoreMetadata;
60 };
61
62 class DeleteObjectStoreOperation : public IDBTransactionBackendImpl::Operation {
63 public:
64     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, const IDBObjectStoreMetadata& objectStoreMetadata)
65     {
66         return adoptPtr(new DeleteObjectStoreOperation(backingStore, objectStoreMetadata));
67     }
68     virtual void perform(IDBTransactionBackendImpl*);
69 private:
70     DeleteObjectStoreOperation(PassRefPtr<IDBBackingStore> backingStore, const IDBObjectStoreMetadata& objectStoreMetadata)
71         : m_backingStore(backingStore)
72         , m_objectStoreMetadata(objectStoreMetadata)
73     {
74     }
75
76     const RefPtr<IDBBackingStore> m_backingStore;
77     const IDBObjectStoreMetadata m_objectStoreMetadata;
78 };
79
80 class IDBDatabaseBackendImpl::VersionChangeOperation : public IDBTransactionBackendImpl::Operation {
81 public:
82     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t transactionId, int64_t version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks)
83     {
84         return adoptPtr(new VersionChangeOperation(database, transactionId, version, callbacks, databaseCallbacks));
85     }
86     virtual void perform(IDBTransactionBackendImpl*);
87 private:
88     VersionChangeOperation(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t transactionId, int64_t version, PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks)
89         : m_database(database)
90         , m_transactionId(transactionId)
91         , m_version(version)
92         , m_callbacks(callbacks)
93         , m_databaseCallbacks(databaseCallbacks)
94     {
95     }
96
97     RefPtr<IDBDatabaseBackendImpl> m_database;
98     int64_t m_transactionId;
99     int64_t m_version;
100     RefPtr<IDBCallbacks> m_callbacks;
101     RefPtr<IDBDatabaseCallbacks> m_databaseCallbacks;
102 };
103
104 class CreateObjectStoreAbortOperation : public IDBTransactionBackendImpl::Operation {
105 public:
106     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId)
107     {
108         return adoptPtr(new CreateObjectStoreAbortOperation(database, objectStoreId));
109     }
110     virtual void perform(IDBTransactionBackendImpl*);
111 private:
112     CreateObjectStoreAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId)
113         : m_database(database)
114         , m_objectStoreId(objectStoreId)
115     {
116     }
117
118     const RefPtr<IDBDatabaseBackendImpl> m_database;
119     const int64_t m_objectStoreId;
120 };
121
122 class DeleteObjectStoreAbortOperation : public IDBTransactionBackendImpl::Operation {
123 public:
124     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, const IDBObjectStoreMetadata& objectStore)
125     {
126         return adoptPtr(new DeleteObjectStoreAbortOperation(database, objectStore));
127     }
128     virtual void perform(IDBTransactionBackendImpl*);
129 private:
130     DeleteObjectStoreAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, const IDBObjectStoreMetadata& objectStoreMetadata)
131         : m_database(database)
132         , m_objectStoreMetadata(objectStoreMetadata)
133     {
134     }
135
136     RefPtr<IDBDatabaseBackendImpl> m_database;
137     IDBObjectStoreMetadata m_objectStoreMetadata;
138 };
139
140 class IDBDatabaseBackendImpl::VersionChangeAbortOperation : public IDBTransactionBackendImpl::Operation {
141 public:
142     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, const String& previousVersion, int64_t previousIntVersion)
143     {
144         return adoptPtr(new VersionChangeAbortOperation(database, previousVersion, previousIntVersion));
145     }
146     virtual void perform(IDBTransactionBackendImpl*);
147 private:
148     VersionChangeAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, const String& previousVersion, int64_t previousIntVersion)
149         : m_database(database)
150         , m_previousVersion(previousVersion)
151         , m_previousIntVersion(previousIntVersion)
152     {
153     }
154
155     RefPtr<IDBDatabaseBackendImpl> m_database;
156     String m_previousVersion;
157     int64_t m_previousIntVersion;
158 };
159
160 class CreateIndexOperation : public IDBTransactionBackendImpl::Operation {
161 public:
162     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
163     {
164         return adoptPtr(new CreateIndexOperation(backingStore, objectStoreId, indexMetadata));
165     }
166     virtual void perform(IDBTransactionBackendImpl*);
167 private:
168     CreateIndexOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
169         : m_backingStore(backingStore)
170         , m_objectStoreId(objectStoreId)
171         , m_indexMetadata(indexMetadata)
172     {
173     }
174
175     const RefPtr<IDBBackingStore> m_backingStore;
176     const int64_t m_objectStoreId;
177     const IDBIndexMetadata m_indexMetadata;
178 };
179
180 class DeleteIndexOperation : public IDBTransactionBackendImpl::Operation {
181 public:
182     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t objectStoreId, int64_t indexId)
183     {
184         return adoptPtr(new DeleteIndexOperation(backingStore, objectStoreId, indexId));
185     }
186     virtual void perform(IDBTransactionBackendImpl*);
187 private:
188     DeleteIndexOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t objectStoreId, int64_t indexId)
189         : m_backingStore(backingStore)
190         , m_objectStoreId(objectStoreId)
191         , m_indexId(indexId)
192     {
193     }
194
195     const RefPtr<IDBBackingStore> m_backingStore;
196     const int64_t m_objectStoreId;
197     const int64_t m_indexId;
198 };
199
200 class CreateIndexAbortOperation : public IDBTransactionBackendImpl::Operation {
201 public:
202     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId, int64_t indexId)
203     {
204         return adoptPtr(new CreateIndexAbortOperation(database, objectStoreId, indexId));
205     }
206     virtual void perform(IDBTransactionBackendImpl*);
207 private:
208     CreateIndexAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId, int64_t indexId)
209         : m_database(database)
210         , m_objectStoreId(objectStoreId)
211         , m_indexId(indexId)
212     {
213     }
214
215     const RefPtr<IDBDatabaseBackendImpl> m_database;
216     const int64_t m_objectStoreId;
217     const int64_t m_indexId;
218 };
219
220 class DeleteIndexAbortOperation : public IDBTransactionBackendImpl::Operation {
221 public:
222     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
223     {
224         return adoptPtr(new DeleteIndexAbortOperation(database, objectStoreId, indexMetadata));
225     }
226     virtual void perform(IDBTransactionBackendImpl*);
227 private:
228     DeleteIndexAbortOperation(PassRefPtr<IDBDatabaseBackendImpl> database, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
229         : m_database(database)
230         , m_objectStoreId(objectStoreId)
231         , m_indexMetadata(indexMetadata)
232     {
233     }
234
235     const RefPtr<IDBDatabaseBackendImpl> m_database;
236     const int64_t m_objectStoreId;
237     const IDBIndexMetadata m_indexMetadata;
238 };
239
240 class GetOperation : public IDBTransactionBackendImpl::Operation {
241 public:
242     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, const IDBDatabaseMetadata& metadata, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, IndexedDB::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks)
243     {
244         return adoptPtr(new GetOperation(backingStore, metadata, objectStoreId, indexId, keyRange, cursorType, callbacks));
245     }
246     virtual void perform(IDBTransactionBackendImpl*);
247 private:
248     GetOperation(PassRefPtr<IDBBackingStore> backingStore, const IDBDatabaseMetadata& metadata, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, IndexedDB::CursorType cursorType, PassRefPtr<IDBCallbacks> callbacks)
249         : m_backingStore(backingStore)
250         , m_databaseId(metadata.id)
251         , m_objectStoreId(objectStoreId)
252         , m_indexId(indexId)
253         , m_keyPath(metadata.objectStores.get(objectStoreId).keyPath)
254         , m_autoIncrement(metadata.objectStores.get(objectStoreId).autoIncrement)
255         , m_keyRange(keyRange)
256         , m_cursorType(cursorType)
257         , m_callbacks(callbacks)
258     {
259         ASSERT(metadata.objectStores.contains(objectStoreId));
260         ASSERT(metadata.objectStores.get(objectStoreId).id == objectStoreId);
261     }
262
263     const RefPtr<IDBBackingStore> m_backingStore;
264     const int64_t m_databaseId;
265     const int64_t m_objectStoreId;
266     const int64_t m_indexId;
267     const IDBKeyPath m_keyPath;
268     const bool m_autoIncrement;
269     const RefPtr<IDBKeyRange> m_keyRange;
270     const IndexedDB::CursorType m_cursorType;
271     const RefPtr<IDBCallbacks> m_callbacks;
272 };
273
274 class PutOperation : public IDBTransactionBackendImpl::Operation {
275 public:
276     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)
277     {
278         return adoptPtr(new PutOperation(backingStore, databaseId, objectStore, value, key, putMode, callbacks, indexIds, indexKeys));
279     }
280     virtual void perform(IDBTransactionBackendImpl*);
281 private:
282     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)
283         : m_backingStore(backingStore)
284         , m_databaseId(databaseId)
285         , m_objectStore(objectStore)
286         , m_value(value)
287         , m_key(key)
288         , m_putMode(putMode)
289         , m_callbacks(callbacks)
290         , m_indexIds(indexIds)
291         , m_indexKeys(indexKeys)
292     {
293     }
294
295     const RefPtr<IDBBackingStore> m_backingStore;
296     const int64_t m_databaseId;
297     const IDBObjectStoreMetadata m_objectStore;
298     const RefPtr<SharedBuffer> m_value;
299     const RefPtr<IDBKey> m_key;
300     const IDBDatabaseBackendInterface::PutMode m_putMode;
301     const RefPtr<IDBCallbacks> m_callbacks;
302     const Vector<int64_t> m_indexIds;
303     const Vector<IDBDatabaseBackendInterface::IndexKeys> m_indexKeys;
304 };
305
306 class SetIndexesReadyOperation : public IDBTransactionBackendImpl::Operation {
307 public:
308     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(size_t indexCount)
309     {
310         return adoptPtr(new SetIndexesReadyOperation(indexCount));
311     }
312     virtual void perform(IDBTransactionBackendImpl*);
313 private:
314     SetIndexesReadyOperation(size_t indexCount)
315         : m_indexCount(indexCount)
316     {
317     }
318
319     const size_t m_indexCount;
320 };
321
322 class OpenCursorOperation : public IDBTransactionBackendImpl::Operation {
323 public:
324     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, IndexedDB::CursorDirection direction, IndexedDB::CursorType cursorType, IDBDatabaseBackendInterface::TaskType taskType, PassRefPtr<IDBCallbacks> callbacks)
325     {
326         return adoptPtr(new OpenCursorOperation(backingStore, databaseId, objectStoreId, indexId, keyRange, direction, cursorType, taskType, callbacks));
327     }
328     virtual void perform(IDBTransactionBackendImpl*);
329 private:
330     OpenCursorOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, IndexedDB::CursorDirection direction, IndexedDB::CursorType cursorType, IDBDatabaseBackendInterface::TaskType taskType, PassRefPtr<IDBCallbacks> callbacks)
331         : m_backingStore(backingStore)
332         , m_databaseId(databaseId)
333         , m_objectStoreId(objectStoreId)
334         , m_indexId(indexId)
335         , m_keyRange(keyRange)
336         , m_direction(direction)
337         , m_cursorType(cursorType)
338         , m_taskType(taskType)
339         , m_callbacks(callbacks)
340     {
341     }
342
343     const RefPtr<IDBBackingStore> m_backingStore;
344     const int64_t m_databaseId;
345     const int64_t m_objectStoreId;
346     const int64_t m_indexId;
347     const PassRefPtr<IDBKeyRange> m_keyRange;
348     const IndexedDB::CursorDirection m_direction;
349     const IndexedDB::CursorType m_cursorType;
350     const IDBDatabaseBackendInterface::TaskType m_taskType;
351     const RefPtr<IDBCallbacks> m_callbacks;
352 };
353
354 class CountOperation : public IDBTransactionBackendImpl::Operation {
355 public:
356     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
357     {
358         return adoptPtr(new CountOperation(backingStore, databaseId, objectStoreId, indexId, keyRange, callbacks));
359     }
360     virtual void perform(IDBTransactionBackendImpl*);
361 private:
362     CountOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
363         : m_backingStore(backingStore)
364         , m_databaseId(databaseId)
365         , m_objectStoreId(objectStoreId)
366         , m_indexId(indexId)
367         , m_keyRange(keyRange)
368         , m_callbacks(callbacks)
369     {
370     }
371
372     const RefPtr<IDBBackingStore> m_backingStore;
373     const int64_t m_databaseId;
374     const int64_t m_objectStoreId;
375     const int64_t m_indexId;
376     const RefPtr<IDBKeyRange> m_keyRange;
377     const RefPtr<IDBCallbacks> m_callbacks;
378 };
379
380 class DeleteRangeOperation : public IDBTransactionBackendImpl::Operation {
381 public:
382     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
383     {
384         return adoptPtr(new DeleteRangeOperation(backingStore, databaseId, objectStoreId, keyRange, callbacks));
385     }
386     virtual void perform(IDBTransactionBackendImpl*);
387 private:
388     DeleteRangeOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
389         : m_backingStore(backingStore)
390         , m_databaseId(databaseId)
391         , m_objectStoreId(objectStoreId)
392         , m_keyRange(keyRange)
393         , m_callbacks(callbacks)
394     {
395     }
396
397     const RefPtr<IDBBackingStore> m_backingStore;
398     const int64_t m_databaseId;
399     const int64_t m_objectStoreId;
400     const RefPtr<IDBKeyRange> m_keyRange;
401     const RefPtr<IDBCallbacks> m_callbacks;
402 };
403
404 class ClearOperation : public IDBTransactionBackendImpl::Operation {
405 public:
406     static PassOwnPtr<IDBTransactionBackendImpl::Operation> create(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBCallbacks> callbacks)
407     {
408         return adoptPtr(new ClearOperation(backingStore, databaseId, objectStoreId, callbacks));
409     }
410     virtual void perform(IDBTransactionBackendImpl*);
411 private:
412     ClearOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t databaseId, int64_t objectStoreId, PassRefPtr<IDBCallbacks> callbacks)
413         : m_backingStore(backingStore)
414         , m_databaseId(databaseId)
415         , m_objectStoreId(objectStoreId)
416         , m_callbacks(callbacks)
417     {
418     }
419
420     const RefPtr<IDBBackingStore> m_backingStore;
421     const int64_t m_databaseId;
422     const int64_t m_objectStoreId;
423     const RefPtr<IDBCallbacks> m_callbacks;
424 };
425
426 class IDBDatabaseBackendImpl::PendingOpenCall {
427 public:
428     static PassOwnPtr<PendingOpenCall> create(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, int64_t transactionId, int64_t version)
429     {
430         return adoptPtr(new PendingOpenCall(callbacks, databaseCallbacks, transactionId, version));
431     }
432     PassRefPtr<IDBCallbacks> callbacks() { return m_callbacks; }
433     PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks() { return m_databaseCallbacks; }
434     int64_t version() { return m_version; }
435     int64_t transactionId() const { return m_transactionId; }
436
437 private:
438     PendingOpenCall(PassRefPtr<IDBCallbacks> callbacks, PassRefPtr<IDBDatabaseCallbacks> databaseCallbacks, int64_t transactionId, int64_t version)
439         : m_callbacks(callbacks)
440         , m_databaseCallbacks(databaseCallbacks)
441         , m_version(version)
442         , m_transactionId(transactionId)
443     {
444     }
445     RefPtr<IDBCallbacks> m_callbacks;
446     RefPtr<IDBDatabaseCallbacks> m_databaseCallbacks;
447     int64_t m_version;
448     const int64_t m_transactionId;
449 };
450
451 class IDBDatabaseBackendImpl::PendingDeleteCall {
452 public:
453     static PassOwnPtr<PendingDeleteCall> create(PassRefPtr<IDBCallbacks> callbacks)
454     {
455         return adoptPtr(new PendingDeleteCall(callbacks));
456     }
457     PassRefPtr<IDBCallbacks> callbacks() { return m_callbacks; }
458
459 private:
460     PendingDeleteCall(PassRefPtr<IDBCallbacks> callbacks)
461         : m_callbacks(callbacks)
462     {
463     }
464     RefPtr<IDBCallbacks> m_callbacks;
465 };
466
467 PassRefPtr<IDBDatabaseBackendImpl> IDBDatabaseBackendImpl::create(const String& name, IDBBackingStore* database, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier)
468 {
469     RefPtr<IDBDatabaseBackendImpl> backend = adoptRef(new IDBDatabaseBackendImpl(name, database, factory, uniqueIdentifier));
470     if (!backend->openInternal())
471         return 0;
472     return backend.release();
473 }
474
475 namespace {
476 const char* NoStringVersion = "";
477 }
478
479 IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBBackingStore* backingStore, IDBFactoryBackendImpl* factory, const String& uniqueIdentifier)
480     : m_backingStore(backingStore)
481     , m_metadata(name, InvalidId, NoStringVersion, IDBDatabaseMetadata::NoIntVersion, InvalidId)
482     , m_identifier(uniqueIdentifier)
483     , m_factory(factory)
484     , m_transactionCoordinator(IDBTransactionCoordinator::create())
485     , m_closingConnection(false)
486 {
487     ASSERT(!m_metadata.name.isNull());
488 }
489
490 void IDBDatabaseBackendImpl::addObjectStore(const IDBObjectStoreMetadata& objectStore, int64_t newMaxObjectStoreId)
491 {
492     ASSERT(!m_metadata.objectStores.contains(objectStore.id));
493     if (newMaxObjectStoreId != IDBObjectStoreMetadata::InvalidId) {
494         ASSERT(m_metadata.maxObjectStoreId < newMaxObjectStoreId);
495         m_metadata.maxObjectStoreId = newMaxObjectStoreId;
496     }
497     m_metadata.objectStores.set(objectStore.id, objectStore);
498 }
499
500 void IDBDatabaseBackendImpl::removeObjectStore(int64_t objectStoreId)
501 {
502     ASSERT(m_metadata.objectStores.contains(objectStoreId));
503     m_metadata.objectStores.remove(objectStoreId);
504 }
505
506 void IDBDatabaseBackendImpl::addIndex(int64_t objectStoreId, const IDBIndexMetadata& index, int64_t newMaxIndexId)
507 {
508     ASSERT(m_metadata.objectStores.contains(objectStoreId));
509     IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
510
511     ASSERT(!objectStore.indexes.contains(index.id));
512     objectStore.indexes.set(index.id, index);
513     if (newMaxIndexId != IDBIndexMetadata::InvalidId) {
514         ASSERT(objectStore.maxIndexId < newMaxIndexId);
515         objectStore.maxIndexId = newMaxIndexId;
516     }
517     m_metadata.objectStores.set(objectStoreId, objectStore);
518 }
519
520 void IDBDatabaseBackendImpl::removeIndex(int64_t objectStoreId, int64_t indexId)
521 {
522     ASSERT(m_metadata.objectStores.contains(objectStoreId));
523     IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
524
525     ASSERT(objectStore.indexes.contains(indexId));
526     objectStore.indexes.remove(indexId);
527     m_metadata.objectStores.set(objectStoreId, objectStore);
528 }
529
530 bool IDBDatabaseBackendImpl::openInternal()
531 {
532     bool success = false;
533     bool ok = m_backingStore->getIDBDatabaseMetaData(m_metadata.name, &m_metadata, success);
534     ASSERT_WITH_MESSAGE(success == (m_metadata.id != InvalidId), "success = %s, m_id = %lld", success ? "true" : "false", static_cast<long long>(m_metadata.id));
535     if (!ok)
536         return false;
537     if (success) {
538         m_backingStore->getObjectStores(m_metadata.id, &m_metadata.objectStores);
539         return true;
540     }
541     return m_backingStore->createIDBDatabaseMetaData(m_metadata.name, m_metadata.version, m_metadata.intVersion, m_metadata.id);
542 }
543
544 IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl()
545 {
546 }
547
548 PassRefPtr<IDBBackingStore> IDBDatabaseBackendImpl::backingStore() const
549 {
550     return m_backingStore;
551 }
552
553 void IDBDatabaseBackendImpl::createObjectStore(int64_t transactionId, int64_t objectStoreId, const String& name, const IDBKeyPath& keyPath, bool autoIncrement)
554 {
555     IDB_TRACE("IDBDatabaseBackendImpl::createObjectStore");
556     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
557     if (!transaction)
558         return;
559     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
560
561     ASSERT(!m_metadata.objectStores.contains(objectStoreId));
562     IDBObjectStoreMetadata objectStoreMetadata(name, objectStoreId, keyPath, autoIncrement, IDBDatabaseBackendInterface::MinimumIndexId);
563
564     transaction->scheduleTask(CreateObjectStoreOperation::create(m_backingStore, objectStoreMetadata), CreateObjectStoreAbortOperation::create(this, objectStoreId));
565
566     addObjectStore(objectStoreMetadata, objectStoreId);
567 }
568
569 void CreateObjectStoreOperation::perform(IDBTransactionBackendImpl* transaction)
570 {
571     IDB_TRACE("CreateObjectStoreOperation");
572     if (!m_backingStore->createObjectStore(transaction->backingStoreTransaction(), transaction->database()->id(), m_objectStoreMetadata.id, m_objectStoreMetadata.name, m_objectStoreMetadata.keyPath, m_objectStoreMetadata.autoIncrement)) {
573         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error creating object store '%s'.", m_objectStoreMetadata.name.utf8().data()));
574         transaction->abort(error.release());
575         return;
576     }
577 }
578
579 void IDBDatabaseBackendImpl::deleteObjectStore(int64_t transactionId, int64_t objectStoreId)
580 {
581     IDB_TRACE("IDBDatabaseBackendImpl::deleteObjectStore");
582     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
583     if (!transaction)
584         return;
585     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
586
587     ASSERT(m_metadata.objectStores.contains(objectStoreId));
588     const IDBObjectStoreMetadata& objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
589
590     transaction->scheduleTask(DeleteObjectStoreOperation::create(m_backingStore, objectStoreMetadata),  DeleteObjectStoreAbortOperation::create(this, objectStoreMetadata));
591     removeObjectStore(objectStoreId);
592 }
593
594 void IDBDatabaseBackendImpl::createIndex(int64_t transactionId, int64_t objectStoreId, int64_t indexId, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry)
595 {
596     IDB_TRACE("IDBDatabaseBackendImpl::createIndex");
597     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
598     if (!transaction)
599         return;
600     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
601
602     ASSERT(m_metadata.objectStores.contains(objectStoreId));
603     const IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
604
605     ASSERT(!objectStore.indexes.contains(indexId));
606     const IDBIndexMetadata indexMetadata(name, indexId, keyPath, unique, multiEntry);
607
608     transaction->scheduleTask(CreateIndexOperation::create(m_backingStore, objectStoreId, indexMetadata), CreateIndexAbortOperation::create(this, objectStoreId, indexId));
609
610     addIndex(objectStoreId, indexMetadata, indexId);
611 }
612
613 void CreateIndexOperation::perform(IDBTransactionBackendImpl* transaction)
614 {
615     IDB_TRACE("CreateIndexOperation");
616     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)) {
617         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error when trying to create index '%s'.", m_indexMetadata.name.utf8().data())));
618         return;
619     }
620 }
621
622 void CreateIndexAbortOperation::perform(IDBTransactionBackendImpl* transaction)
623 {
624     IDB_TRACE("CreateIndexAbortOperation");
625     ASSERT(!transaction);
626     m_database->removeIndex(m_objectStoreId, m_indexId);
627 }
628
629 void IDBDatabaseBackendImpl::deleteIndex(int64_t transactionId, int64_t objectStoreId, int64_t indexId)
630 {
631     IDB_TRACE("IDBDatabaseBackendImpl::deleteIndex");
632     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
633     if (!transaction)
634         return;
635     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
636
637     ASSERT(m_metadata.objectStores.contains(objectStoreId));
638     const IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
639
640     ASSERT(objectStore.indexes.contains(indexId));
641     const IDBIndexMetadata& indexMetadata = objectStore.indexes.get(indexId);
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     // 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.
664     if (m_transactions.contains(transactionId))
665         m_transactions.get(transactionId)->commit();
666 }
667
668 void IDBDatabaseBackendImpl::abort(int64_t transactionId)
669 {
670     // If the transaction is unknown, then it has already been aborted by the backend before this call so it is safe to ignore it.
671     if (m_transactions.contains(transactionId))
672         m_transactions.get(transactionId)->abort();
673 }
674
675 void IDBDatabaseBackendImpl::abort(int64_t transactionId, PassRefPtr<IDBDatabaseError> error)
676 {
677     // If the transaction is unknown, then it has already been aborted by the backend before this call so it is safe to ignore it.
678     if (m_transactions.contains(transactionId))
679         m_transactions.get(transactionId)->abort(error);
680 }
681
682 void IDBDatabaseBackendImpl::get(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, bool keyOnly, PassRefPtr<IDBCallbacks> callbacks)
683 {
684     IDB_TRACE("IDBDatabaseBackendImpl::get");
685     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
686     if (!transaction)
687         return;
688
689     transaction->scheduleTask(GetOperation::create(m_backingStore, m_metadata, objectStoreId, indexId, keyRange, keyOnly ? IndexedDB::CursorKeyOnly : IndexedDB::CursorKeyAndValue, callbacks));
690 }
691
692 void GetOperation::perform(IDBTransactionBackendImpl* transaction)
693 {
694     IDB_TRACE("GetOperation");
695
696     RefPtr<IDBKey> key;
697
698     if (m_keyRange->isOnlyKey())
699         key = m_keyRange->lower();
700     else {
701         RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
702         if (m_indexId == IDBIndexMetadata::InvalidId) {
703             ASSERT(m_cursorType != IndexedDB::CursorKeyOnly);
704             // ObjectStore Retrieval Operation
705             backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IndexedDB::CursorNext);
706         } else {
707             if (m_cursorType == IndexedDB::CursorKeyOnly)
708                 // Index Value Retrieval Operation
709                 backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
710             else
711                 // Index Referenced Value Retrieval Operation
712                 backingStoreCursor = m_backingStore->openIndexCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
713         }
714
715         if (!backingStoreCursor) {
716             m_callbacks->onSuccess();
717             return;
718         }
719
720         key = backingStoreCursor->key();
721     }
722
723     RefPtr<IDBKey> primaryKey;
724     bool ok;
725     if (m_indexId == IDBIndexMetadata::InvalidId) {
726         // Object Store Retrieval Operation
727         Vector<char> value;
728         ok = m_backingStore->getRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, *key, value);
729         if (!ok) {
730             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
731             return;
732         }
733
734         if (value.isEmpty()) {
735             m_callbacks->onSuccess();
736             return;
737         }
738
739         if (m_autoIncrement && !m_keyPath.isNull()) {
740             m_callbacks->onSuccess(SharedBuffer::adoptVector(value), key, m_keyPath);
741             return;
742         }
743
744         m_callbacks->onSuccess(SharedBuffer::adoptVector(value));
745         return;
746
747     }
748
749     // From here we are dealing only with indexes.
750     ok = m_backingStore->getPrimaryKeyViaIndex(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, *key, primaryKey);
751     if (!ok) {
752         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getPrimaryKeyViaIndex."));
753         return;
754     }
755     if (!primaryKey) {
756         m_callbacks->onSuccess();
757         return;
758     }
759     if (m_cursorType == IndexedDB::CursorKeyOnly) {
760         // Index Value Retrieval Operation
761         m_callbacks->onSuccess(primaryKey.get());
762         return;
763     }
764
765     // Index Referenced Value Retrieval Operation
766     Vector<char> value;
767     ok = m_backingStore->getRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, *primaryKey, value);
768     if (!ok) {
769         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
770         return;
771     }
772
773     if (value.isEmpty()) {
774         m_callbacks->onSuccess();
775         return;
776     }
777     if (m_autoIncrement && !m_keyPath.isNull()) {
778         m_callbacks->onSuccess(SharedBuffer::adoptVector(value), primaryKey, m_keyPath);
779         return;
780     }
781     m_callbacks->onSuccess(SharedBuffer::adoptVector(value));
782 }
783
784 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)
785 {
786     IDB_TRACE("IDBDatabaseBackendImpl::put");
787     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
788     if (!transaction)
789         return;
790     ASSERT(transaction->mode() != IndexedDB::TransactionReadOnly);
791
792     const IDBObjectStoreMetadata objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
793
794     ASSERT(objectStoreMetadata.autoIncrement || key.get());
795
796     transaction->scheduleTask(PutOperation::create(m_backingStore, id(), objectStoreMetadata, value, key, putMode, callbacks, indexIds, indexKeys));
797 }
798
799 void PutOperation::perform(IDBTransactionBackendImpl* transaction)
800 {
801     IDB_TRACE("PutOperation");
802     ASSERT(transaction->mode() != IndexedDB::TransactionReadOnly);
803     ASSERT(m_indexIds.size() == m_indexKeys.size());
804     bool keyWasGenerated = false;
805
806     RefPtr<IDBKey> key;
807     if (m_putMode != IDBDatabaseBackendInterface::CursorUpdate && m_objectStore.autoIncrement && !m_key) {
808         RefPtr<IDBKey> autoIncKey = IDBObjectStoreBackendImpl::generateKey(m_backingStore, transaction, m_databaseId, m_objectStore.id);
809         keyWasGenerated = true;
810         if (!autoIncKey->isValid()) {
811             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Maximum key generator value reached."));
812             return;
813         }
814         key = autoIncKey;
815     } else
816         key = m_key;
817
818     ASSERT(key && key->isValid());
819
820     IDBBackingStore::RecordIdentifier recordIdentifier;
821     if (m_putMode == IDBDatabaseBackendInterface::AddOnly) {
822         bool found = false;
823         bool ok = m_backingStore->keyExistsInObjectStore(transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id, *key, &recordIdentifier, found);
824         if (!ok) {
825             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error checking key existence."));
826             return;
827         }
828         if (found) {
829             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Key already exists in the object store."));
830             return;
831         }
832     }
833
834     Vector<OwnPtr<IDBObjectStoreBackendImpl::IndexWriter> > indexWriters;
835     String errorMessage;
836     bool obeysConstraints = false;
837     bool backingStoreSuccess = IDBObjectStoreBackendImpl::makeIndexWriters(transaction, m_backingStore.get(), m_databaseId, m_objectStore, key, keyWasGenerated, m_indexIds, m_indexKeys, &indexWriters, &errorMessage, obeysConstraints);
838     if (!backingStoreSuccess) {
839         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
840         return;
841     }
842     if (!obeysConstraints) {
843         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
844         return;
845     }
846
847     // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
848     backingStoreSuccess = m_backingStore->putRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id, *key, m_value, &recordIdentifier);
849     if (!backingStoreSuccess) {
850         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error performing put/add."));
851         return;
852     }
853
854     for (size_t i = 0; i < indexWriters.size(); ++i) {
855         IDBObjectStoreBackendImpl::IndexWriter* indexWriter = indexWriters[i].get();
856         indexWriter->writeIndexKeys(recordIdentifier, *m_backingStore, transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id);
857     }
858
859     if (m_objectStore.autoIncrement && m_putMode != IDBDatabaseBackendInterface::CursorUpdate && key->type() == IDBKey::NumberType) {
860         bool ok = IDBObjectStoreBackendImpl::updateKeyGenerator(m_backingStore, transaction, m_databaseId, m_objectStore.id, key.get(), !keyWasGenerated);
861         if (!ok) {
862             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error updating key generator."));
863             return;
864         }
865     }
866
867     m_callbacks->onSuccess(key.release());
868 }
869
870 void IDBDatabaseBackendImpl::setIndexKeys(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKey> prpPrimaryKey, const Vector<int64_t>& indexIds, const Vector<IndexKeys>& indexKeys)
871 {
872     IDB_TRACE("IDBDatabaseBackendImpl::setIndexKeys");
873     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
874     if (!transaction)
875         return;
876     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
877
878     RefPtr<IDBKey> primaryKey = prpPrimaryKey;
879     RefPtr<IDBBackingStore> store = backingStore();
880     // FIXME: This method could be asynchronous, but we need to evaluate if it's worth the extra complexity.
881     IDBBackingStore::RecordIdentifier recordIdentifier;
882     bool found = false;
883     bool ok = store->keyExistsInObjectStore(transaction->backingStoreTransaction(), m_metadata.id, objectStoreId, *primaryKey, &recordIdentifier, found);
884     if (!ok) {
885         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error setting index keys."));
886         return;
887     }
888     if (!found) {
889         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error setting index keys for object store."));
890         transaction->abort(error.release());
891         return;
892     }
893
894     Vector<OwnPtr<IDBObjectStoreBackendImpl::IndexWriter> > indexWriters;
895     String errorMessage;
896     bool obeysConstraints = false;
897     ASSERT(m_metadata.objectStores.contains(objectStoreId));
898     const IDBObjectStoreMetadata& objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
899     bool backingStoreSuccess = IDBObjectStoreBackendImpl::makeIndexWriters(transaction, store.get(), id(), objectStoreMetadata, primaryKey, false, indexIds, indexKeys, &indexWriters, &errorMessage, obeysConstraints);
900     if (!backingStoreSuccess) {
901         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
902         return;
903     }
904     if (!obeysConstraints) {
905         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
906         return;
907     }
908
909     for (size_t i = 0; i < indexWriters.size(); ++i) {
910         IDBObjectStoreBackendImpl::IndexWriter* indexWriter = indexWriters[i].get();
911         indexWriter->writeIndexKeys(recordIdentifier, *store.get(), transaction->backingStoreTransaction(), id(), objectStoreId);
912     }
913 }
914
915 void IDBDatabaseBackendImpl::setIndexesReady(int64_t transactionId, int64_t objectStoreId, const Vector<int64_t>& indexIds)
916 {
917     IDB_TRACE("IDBObjectStoreBackendImpl::setIndexesReady");
918
919     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
920     if (!transaction)
921         return;
922
923     transaction->scheduleTask(IDBDatabaseBackendInterface::PreemptiveTask, SetIndexesReadyOperation::create(indexIds.size()));
924 }
925
926 void SetIndexesReadyOperation::perform(IDBTransactionBackendImpl* transaction)
927 {
928     IDB_TRACE("SetIndexesReadyOperation");
929     for (size_t i = 0; i < m_indexCount; ++i)
930         transaction->didCompletePreemptiveEvent();
931 }
932
933 void IDBDatabaseBackendImpl::openCursor(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, IndexedDB::CursorDirection direction, bool keyOnly, TaskType taskType, PassRefPtr<IDBCallbacks> callbacks)
934 {
935     IDB_TRACE("IDBDatabaseBackendImpl::openCursor");
936     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
937     if (!transaction)
938         return;
939
940     transaction->scheduleTask(OpenCursorOperation::create(m_backingStore, id(), objectStoreId, indexId, keyRange, direction, keyOnly ? IndexedDB::CursorKeyOnly : IndexedDB::CursorKeyAndValue, taskType, callbacks));
941 }
942
943 void OpenCursorOperation::perform(IDBTransactionBackendImpl* transaction)
944 {
945     IDB_TRACE("OpenCursorOperation");
946
947     // The frontend has begun indexing, so this pauses the transaction
948     // until the indexing is complete. This can't happen any earlier
949     // because we don't want to switch to early mode in case multiple
950     // indexes are being created in a row, with put()'s in between.
951     if (m_taskType == IDBDatabaseBackendInterface::PreemptiveTask)
952         transaction->addPreemptiveEvent();
953
954     RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
955     if (m_indexId == IDBIndexMetadata::InvalidId) {
956         ASSERT(m_cursorType != IndexedDB::CursorKeyOnly);
957         backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), m_direction);
958     } else {
959         ASSERT(m_taskType == IDBDatabaseBackendInterface::NormalTask);
960         if (m_cursorType == IndexedDB::CursorKeyOnly)
961             backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), m_direction);
962         else
963             backingStoreCursor = m_backingStore->openIndexCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), m_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(), IndexedDB::CursorNext);
995     else
996         backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
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() != IndexedDB::TransactionReadOnly);
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(), IndexedDB::CursorNext);
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() != IndexedDB::TransactionReadOnly);
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() == IndexedDB::TransactionVersionChange) {
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() == IndexedDB::TransactionVersionChange) {
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() == IndexedDB::TransactionVersionChange) {
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() == IndexedDB::TransactionVersionChange)
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<IndexedDB::TransactionMode>(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, IndexedDB::TransactionVersionChange);
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)