76d8368c149761b40f2ff88a76706f71975cb2ad
[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, const IDBIndexMetadata& indexMetadata)
183     {
184         return adoptPtr(new DeleteIndexOperation(backingStore, objectStoreId, indexMetadata));
185     }
186     virtual void perform(IDBTransactionBackendImpl*);
187 private:
188     DeleteIndexOperation(PassRefPtr<IDBBackingStore> backingStore, int64_t objectStoreId, const IDBIndexMetadata& indexMetadata)
189         : m_backingStore(backingStore)
190         , m_objectStoreId(objectStoreId)
191         , m_indexMetadata(indexMetadata)
192     {
193     }
194
195     const RefPtr<IDBBackingStore> m_backingStore;
196     const int64_t m_objectStoreId;
197     const IDBIndexMetadata m_indexMetadata;
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         return m_backingStore->getObjectStores(m_metadata.id, &m_metadata.objectStores);
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() == IndexedDB::TransactionVersionChange);
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() == IndexedDB::TransactionVersionChange);
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() == IndexedDB::TransactionVersionChange);
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() == IndexedDB::TransactionVersionChange);
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, indexMetadata), DeleteIndexAbortOperation::create(this, objectStoreId, indexMetadata));
643
644     removeIndex(objectStoreId, indexId);
645 }
646
647 void DeleteIndexOperation::perform(IDBTransactionBackendImpl* transaction)
648 {
649     IDB_TRACE("DeleteIndexOperation");
650     bool ok = m_backingStore->deleteIndex(transaction->backingStoreTransaction(), transaction->database()->id(), m_objectStoreId, m_indexMetadata.id);
651     if (!ok) {
652         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting index '%s'.", m_indexMetadata.name.utf8().data()));
653         transaction->abort(error);
654     }
655 }
656
657 void DeleteIndexAbortOperation::perform(IDBTransactionBackendImpl* transaction)
658 {
659     IDB_TRACE("DeleteIndexAbortOperation");
660     ASSERT(!transaction);
661     m_database->addIndex(m_objectStoreId, m_indexMetadata, IDBIndexMetadata::InvalidId);
662 }
663
664 void IDBDatabaseBackendImpl::commit(int64_t transactionId)
665 {
666     // 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.
667     if (m_transactions.contains(transactionId))
668         m_transactions.get(transactionId)->commit();
669 }
670
671 void IDBDatabaseBackendImpl::abort(int64_t transactionId)
672 {
673     // If the transaction is unknown, then it has already been aborted by the backend before this call so it is safe to ignore it.
674     if (m_transactions.contains(transactionId))
675         m_transactions.get(transactionId)->abort();
676 }
677
678 void IDBDatabaseBackendImpl::abort(int64_t transactionId, PassRefPtr<IDBDatabaseError> error)
679 {
680     // If the transaction is unknown, then it has already been aborted by the backend before this call so it is safe to ignore it.
681     if (m_transactions.contains(transactionId))
682         m_transactions.get(transactionId)->abort(error);
683 }
684
685 void IDBDatabaseBackendImpl::get(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, bool keyOnly, PassRefPtr<IDBCallbacks> callbacks)
686 {
687     IDB_TRACE("IDBDatabaseBackendImpl::get");
688     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
689     if (!transaction)
690         return;
691
692     transaction->scheduleTask(GetOperation::create(m_backingStore, m_metadata, objectStoreId, indexId, keyRange, keyOnly ? IndexedDB::CursorKeyOnly : IndexedDB::CursorKeyAndValue, callbacks));
693 }
694
695 void GetOperation::perform(IDBTransactionBackendImpl* transaction)
696 {
697     IDB_TRACE("GetOperation");
698
699     RefPtr<IDBKey> key;
700
701     if (m_keyRange->isOnlyKey())
702         key = m_keyRange->lower();
703     else {
704         RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
705         if (m_indexId == IDBIndexMetadata::InvalidId) {
706             ASSERT(m_cursorType != IndexedDB::CursorKeyOnly);
707             // ObjectStore Retrieval Operation
708             backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IndexedDB::CursorNext);
709         } else {
710             if (m_cursorType == IndexedDB::CursorKeyOnly)
711                 // Index Value Retrieval Operation
712                 backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
713             else
714                 // Index Referenced Value Retrieval Operation
715                 backingStoreCursor = m_backingStore->openIndexCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
716         }
717
718         if (!backingStoreCursor) {
719             m_callbacks->onSuccess();
720             return;
721         }
722
723         key = backingStoreCursor->key();
724     }
725
726     RefPtr<IDBKey> primaryKey;
727     bool ok;
728     if (m_indexId == IDBIndexMetadata::InvalidId) {
729         // Object Store Retrieval Operation
730         Vector<char> value;
731         ok = m_backingStore->getRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, *key, value);
732         if (!ok) {
733             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
734             return;
735         }
736
737         if (value.isEmpty()) {
738             m_callbacks->onSuccess();
739             return;
740         }
741
742         if (m_autoIncrement && !m_keyPath.isNull()) {
743             m_callbacks->onSuccess(SharedBuffer::adoptVector(value), key, m_keyPath);
744             return;
745         }
746
747         m_callbacks->onSuccess(SharedBuffer::adoptVector(value));
748         return;
749
750     }
751
752     // From here we are dealing only with indexes.
753     ok = m_backingStore->getPrimaryKeyViaIndex(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, *key, primaryKey);
754     if (!ok) {
755         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getPrimaryKeyViaIndex."));
756         return;
757     }
758     if (!primaryKey) {
759         m_callbacks->onSuccess();
760         return;
761     }
762     if (m_cursorType == IndexedDB::CursorKeyOnly) {
763         // Index Value Retrieval Operation
764         m_callbacks->onSuccess(primaryKey.get());
765         return;
766     }
767
768     // Index Referenced Value Retrieval Operation
769     Vector<char> value;
770     ok = m_backingStore->getRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, *primaryKey, value);
771     if (!ok) {
772         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error in getRecord."));
773         return;
774     }
775
776     if (value.isEmpty()) {
777         m_callbacks->onSuccess();
778         return;
779     }
780     if (m_autoIncrement && !m_keyPath.isNull()) {
781         m_callbacks->onSuccess(SharedBuffer::adoptVector(value), primaryKey, m_keyPath);
782         return;
783     }
784     m_callbacks->onSuccess(SharedBuffer::adoptVector(value));
785 }
786
787 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)
788 {
789     IDB_TRACE("IDBDatabaseBackendImpl::put");
790     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
791     if (!transaction)
792         return;
793     ASSERT(transaction->mode() != IndexedDB::TransactionReadOnly);
794
795     const IDBObjectStoreMetadata objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
796
797     ASSERT(objectStoreMetadata.autoIncrement || key.get());
798
799     transaction->scheduleTask(PutOperation::create(m_backingStore, id(), objectStoreMetadata, value, key, putMode, callbacks, indexIds, indexKeys));
800 }
801
802 void PutOperation::perform(IDBTransactionBackendImpl* transaction)
803 {
804     IDB_TRACE("PutOperation");
805     ASSERT(transaction->mode() != IndexedDB::TransactionReadOnly);
806     ASSERT(m_indexIds.size() == m_indexKeys.size());
807     bool keyWasGenerated = false;
808
809     RefPtr<IDBKey> key;
810     if (m_putMode != IDBDatabaseBackendInterface::CursorUpdate && m_objectStore.autoIncrement && !m_key) {
811         RefPtr<IDBKey> autoIncKey = IDBObjectStoreBackendImpl::generateKey(m_backingStore, transaction, m_databaseId, m_objectStore.id);
812         keyWasGenerated = true;
813         if (!autoIncKey->isValid()) {
814             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Maximum key generator value reached."));
815             return;
816         }
817         key = autoIncKey;
818     } else
819         key = m_key;
820
821     ASSERT(key && key->isValid());
822
823     IDBBackingStore::RecordIdentifier recordIdentifier;
824     if (m_putMode == IDBDatabaseBackendInterface::AddOnly) {
825         bool found = false;
826         bool ok = m_backingStore->keyExistsInObjectStore(transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id, *key, &recordIdentifier, found);
827         if (!ok) {
828             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error checking key existence."));
829             return;
830         }
831         if (found) {
832             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, "Key already exists in the object store."));
833             return;
834         }
835     }
836
837     Vector<OwnPtr<IDBObjectStoreBackendImpl::IndexWriter> > indexWriters;
838     String errorMessage;
839     bool obeysConstraints = false;
840     bool backingStoreSuccess = IDBObjectStoreBackendImpl::makeIndexWriters(transaction, m_backingStore.get(), m_databaseId, m_objectStore, key, keyWasGenerated, m_indexIds, m_indexKeys, &indexWriters, &errorMessage, obeysConstraints);
841     if (!backingStoreSuccess) {
842         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
843         return;
844     }
845     if (!obeysConstraints) {
846         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
847         return;
848     }
849
850     // Before this point, don't do any mutation. After this point, rollback the transaction in case of error.
851     backingStoreSuccess = m_backingStore->putRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id, *key, m_value, &recordIdentifier);
852     if (!backingStoreSuccess) {
853         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error performing put/add."));
854         return;
855     }
856
857     for (size_t i = 0; i < indexWriters.size(); ++i) {
858         IDBObjectStoreBackendImpl::IndexWriter* indexWriter = indexWriters[i].get();
859         indexWriter->writeIndexKeys(recordIdentifier, *m_backingStore, transaction->backingStoreTransaction(), m_databaseId, m_objectStore.id);
860     }
861
862     if (m_objectStore.autoIncrement && m_putMode != IDBDatabaseBackendInterface::CursorUpdate && key->type() == IDBKey::NumberType) {
863         bool ok = IDBObjectStoreBackendImpl::updateKeyGenerator(m_backingStore, transaction, m_databaseId, m_objectStore.id, key.get(), !keyWasGenerated);
864         if (!ok) {
865             m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error updating key generator."));
866             return;
867         }
868     }
869
870     m_callbacks->onSuccess(key.release());
871 }
872
873 void IDBDatabaseBackendImpl::setIndexKeys(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKey> prpPrimaryKey, const Vector<int64_t>& indexIds, const Vector<IndexKeys>& indexKeys)
874 {
875     IDB_TRACE("IDBDatabaseBackendImpl::setIndexKeys");
876     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
877     if (!transaction)
878         return;
879     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
880
881     RefPtr<IDBKey> primaryKey = prpPrimaryKey;
882     RefPtr<IDBBackingStore> store = backingStore();
883     // FIXME: This method could be asynchronous, but we need to evaluate if it's worth the extra complexity.
884     IDBBackingStore::RecordIdentifier recordIdentifier;
885     bool found = false;
886     bool ok = store->keyExistsInObjectStore(transaction->backingStoreTransaction(), m_metadata.id, objectStoreId, *primaryKey, &recordIdentifier, found);
887     if (!ok) {
888         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error setting index keys."));
889         return;
890     }
891     if (!found) {
892         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error setting index keys for object store."));
893         transaction->abort(error.release());
894         return;
895     }
896
897     Vector<OwnPtr<IDBObjectStoreBackendImpl::IndexWriter> > indexWriters;
898     String errorMessage;
899     bool obeysConstraints = false;
900     ASSERT(m_metadata.objectStores.contains(objectStoreId));
901     const IDBObjectStoreMetadata& objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
902     bool backingStoreSuccess = IDBObjectStoreBackendImpl::makeIndexWriters(transaction, store.get(), id(), objectStoreMetadata, primaryKey, false, indexIds, indexKeys, &indexWriters, &errorMessage, obeysConstraints);
903     if (!backingStoreSuccess) {
904         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
905         return;
906     }
907     if (!obeysConstraints) {
908         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
909         return;
910     }
911
912     for (size_t i = 0; i < indexWriters.size(); ++i) {
913         IDBObjectStoreBackendImpl::IndexWriter* indexWriter = indexWriters[i].get();
914         indexWriter->writeIndexKeys(recordIdentifier, *store.get(), transaction->backingStoreTransaction(), id(), objectStoreId);
915     }
916 }
917
918 void IDBDatabaseBackendImpl::setIndexesReady(int64_t transactionId, int64_t objectStoreId, const Vector<int64_t>& indexIds)
919 {
920     IDB_TRACE("IDBObjectStoreBackendImpl::setIndexesReady");
921
922     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
923     if (!transaction)
924         return;
925
926     transaction->scheduleTask(IDBDatabaseBackendInterface::PreemptiveTask, SetIndexesReadyOperation::create(indexIds.size()));
927 }
928
929 void SetIndexesReadyOperation::perform(IDBTransactionBackendImpl* transaction)
930 {
931     IDB_TRACE("SetIndexesReadyOperation");
932     for (size_t i = 0; i < m_indexCount; ++i)
933         transaction->didCompletePreemptiveEvent();
934 }
935
936 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)
937 {
938     IDB_TRACE("IDBDatabaseBackendImpl::openCursor");
939     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
940     if (!transaction)
941         return;
942
943     transaction->scheduleTask(OpenCursorOperation::create(m_backingStore, id(), objectStoreId, indexId, keyRange, direction, keyOnly ? IndexedDB::CursorKeyOnly : IndexedDB::CursorKeyAndValue, taskType, callbacks));
944 }
945
946 void OpenCursorOperation::perform(IDBTransactionBackendImpl* transaction)
947 {
948     IDB_TRACE("OpenCursorOperation");
949
950     // The frontend has begun indexing, so this pauses the transaction
951     // until the indexing is complete. This can't happen any earlier
952     // because we don't want to switch to early mode in case multiple
953     // indexes are being created in a row, with put()'s in between.
954     if (m_taskType == IDBDatabaseBackendInterface::PreemptiveTask)
955         transaction->addPreemptiveEvent();
956
957     RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
958     if (m_indexId == IDBIndexMetadata::InvalidId) {
959         ASSERT(m_cursorType != IndexedDB::CursorKeyOnly);
960         backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), m_direction);
961     } else {
962         ASSERT(m_taskType == IDBDatabaseBackendInterface::NormalTask);
963         if (m_cursorType == IndexedDB::CursorKeyOnly)
964             backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), m_direction);
965         else
966             backingStoreCursor = m_backingStore->openIndexCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), m_direction);
967     }
968
969     if (!backingStoreCursor) {
970         m_callbacks->onSuccess(static_cast<SharedBuffer*>(0));
971         return;
972     }
973
974     IDBDatabaseBackendInterface::TaskType taskType(static_cast<IDBDatabaseBackendInterface::TaskType>(m_taskType));
975     RefPtr<IDBCursorBackendImpl> cursor = IDBCursorBackendImpl::create(backingStoreCursor.get(), m_cursorType, taskType, transaction, m_objectStoreId);
976     m_callbacks->onSuccess(cursor, cursor->key(), cursor->primaryKey(), cursor->value());
977 }
978
979 void IDBDatabaseBackendImpl::count(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
980 {
981     IDB_TRACE("IDBDatabaseBackendImpl::count");
982     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
983     if (!transaction)
984         return;
985
986     ASSERT(m_metadata.objectStores.contains(objectStoreId));
987     transaction->scheduleTask(CountOperation::create(m_backingStore, id(), objectStoreId, indexId, keyRange, callbacks));
988 }
989
990 void CountOperation::perform(IDBTransactionBackendImpl* transaction)
991 {
992     IDB_TRACE("CountOperation");
993     uint32_t count = 0;
994     RefPtr<IDBBackingStore::Cursor> backingStoreCursor;
995
996     if (m_indexId == IDBIndexMetadata::InvalidId)
997         backingStoreCursor = m_backingStore->openObjectStoreKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IndexedDB::CursorNext);
998     else
999         backingStoreCursor = m_backingStore->openIndexKeyCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_indexId, m_keyRange.get(), IndexedDB::CursorNext);
1000     if (!backingStoreCursor) {
1001         m_callbacks->onSuccess(count);
1002         return;
1003     }
1004
1005     do {
1006         ++count;
1007     } while (backingStoreCursor->continueFunction(0));
1008
1009     m_callbacks->onSuccess(count);
1010 }
1011
1012 void IDBDatabaseBackendImpl::deleteRange(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
1013 {
1014     IDB_TRACE("IDBDatabaseBackendImpl::deleteRange");
1015     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
1016     if (!transaction)
1017         return;
1018     ASSERT(transaction->mode() != IndexedDB::TransactionReadOnly);
1019
1020     transaction->scheduleTask(DeleteRangeOperation::create(m_backingStore, id(), objectStoreId, keyRange, callbacks));
1021 }
1022
1023 void DeleteRangeOperation::perform(IDBTransactionBackendImpl* transaction)
1024 {
1025     IDB_TRACE("DeleteRangeOperation");
1026     RefPtr<IDBBackingStore::Cursor> backingStoreCursor = m_backingStore->openObjectStoreCursor(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, m_keyRange.get(), IndexedDB::CursorNext);
1027     if (backingStoreCursor) {
1028         do {
1029             if (!m_backingStore->deleteRecord(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId, backingStoreCursor->recordIdentifier())) {
1030                 m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error deleting data in range"));
1031                 return;
1032             }
1033         } while (backingStoreCursor->continueFunction(0));
1034     }
1035
1036     m_callbacks->onSuccess();
1037 }
1038
1039 void IDBDatabaseBackendImpl::clear(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBCallbacks> callbacks)
1040 {
1041     IDB_TRACE("IDBDatabaseBackendImpl::clear");
1042     IDBTransactionBackendImpl* transaction = m_transactions.get(transactionId);
1043     if (!transaction)
1044         return;
1045     ASSERT(transaction->mode() != IndexedDB::TransactionReadOnly);
1046
1047     transaction->scheduleTask(ClearOperation::create(m_backingStore, id(), objectStoreId, callbacks));
1048 }
1049
1050 void ClearOperation::perform(IDBTransactionBackendImpl* transaction)
1051 {
1052     IDB_TRACE("ObjectStoreClearOperation");
1053     if (!m_backingStore->clearObjectStore(transaction->backingStoreTransaction(), m_databaseId, m_objectStoreId)) {
1054         m_callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error clearing object store"));
1055         return;
1056     }
1057     m_callbacks->onSuccess();
1058 }
1059
1060 void DeleteObjectStoreOperation::perform(IDBTransactionBackendImpl* transaction)
1061 {
1062     IDB_TRACE("DeleteObjectStoreOperation");
1063     bool ok = m_backingStore->deleteObjectStore(transaction->backingStoreTransaction(), transaction->database()->id(), m_objectStoreMetadata.id);
1064     if (!ok) {
1065         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error deleting object store '%s'.", m_objectStoreMetadata.name.utf8().data()));
1066         transaction->abort(error);
1067     }
1068 }
1069
1070 void IDBDatabaseBackendImpl::VersionChangeOperation::perform(IDBTransactionBackendImpl* transaction)
1071 {
1072     IDB_TRACE("VersionChangeOperation");
1073     int64_t databaseId = m_database->id();
1074     int64_t oldVersion = m_database->m_metadata.intVersion;
1075     ASSERT(m_version > oldVersion);
1076     m_database->m_metadata.intVersion = m_version;
1077     if (!m_database->m_backingStore->updateIDBDatabaseIntVersion(transaction->backingStoreTransaction(), databaseId, m_database->m_metadata.intVersion)) {
1078         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Error writing data to stable storage when updating version.");
1079         m_callbacks->onError(error);
1080         transaction->abort(error);
1081         return;
1082     }
1083     ASSERT(!m_database->m_pendingSecondHalfOpen);
1084     m_database->m_pendingSecondHalfOpen = PendingOpenCall::create(m_callbacks, m_databaseCallbacks, m_transactionId, m_version);
1085     m_callbacks->onUpgradeNeeded(oldVersion, m_database, m_database->metadata());
1086 }
1087
1088 void IDBDatabaseBackendImpl::transactionStarted(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
1089 {
1090     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
1091     if (transaction->mode() == IndexedDB::TransactionVersionChange) {
1092         ASSERT(!m_runningVersionChangeTransaction);
1093         m_runningVersionChangeTransaction = transaction;
1094     }
1095 }
1096
1097 void IDBDatabaseBackendImpl::transactionFinished(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
1098 {
1099     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
1100     ASSERT(m_transactions.contains(transaction->id()));
1101     ASSERT(m_transactions.get(transaction->id()) == transaction.get());
1102     m_transactions.remove(transaction->id());
1103     if (transaction->mode() == IndexedDB::TransactionVersionChange) {
1104         ASSERT(transaction.get() == m_runningVersionChangeTransaction.get());
1105         m_runningVersionChangeTransaction.clear();
1106     }
1107 }
1108
1109 void IDBDatabaseBackendImpl::transactionFinishedAndAbortFired(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
1110 {
1111     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
1112     if (transaction->mode() == IndexedDB::TransactionVersionChange) {
1113         // If this was an open-with-version call, there will be a "second
1114         // half" open call waiting for us in processPendingCalls.
1115         // FIXME: When we no longer support setVersion, assert such a thing.
1116         if (m_pendingSecondHalfOpen) {
1117             m_pendingSecondHalfOpen->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "Version change transaction was aborted in upgradeneeded event handler."));
1118             m_pendingSecondHalfOpen.release();
1119         }
1120         processPendingCalls();
1121     }
1122 }
1123
1124 void IDBDatabaseBackendImpl::transactionFinishedAndCompleteFired(PassRefPtr<IDBTransactionBackendImpl> prpTransaction)
1125 {
1126     RefPtr<IDBTransactionBackendImpl> transaction = prpTransaction;
1127     if (transaction->mode() == IndexedDB::TransactionVersionChange)
1128         processPendingCalls();
1129 }
1130
1131 size_t IDBDatabaseBackendImpl::connectionCount()
1132 {
1133     // This does not include pending open calls, as those should not block version changes and deletes.
1134     return m_databaseCallbacksSet.size();
1135 }
1136
1137 void IDBDatabaseBackendImpl::processPendingCalls()
1138 {
1139     if (m_pendingSecondHalfOpen) {
1140         ASSERT(m_pendingSecondHalfOpen->version() == m_metadata.intVersion);
1141         ASSERT(m_metadata.id != InvalidId);
1142         m_pendingSecondHalfOpen->callbacks()->onSuccess(this, this->metadata());
1143         m_pendingSecondHalfOpen.release();
1144         // Fall through when complete, as pending deletes may be (partially) unblocked.
1145     }
1146
1147     // Note that this check is only an optimization to reduce queue-churn and
1148     // not necessary for correctness; deleteDatabase and openConnection will
1149     // requeue their calls if this condition is true.
1150     if (m_runningVersionChangeTransaction)
1151         return;
1152
1153     if (!m_pendingDeleteCalls.isEmpty() && isDeleteDatabaseBlocked())
1154         return;
1155     while (!m_pendingDeleteCalls.isEmpty()) {
1156         OwnPtr<PendingDeleteCall> pendingDeleteCall = m_pendingDeleteCalls.takeFirst();
1157         deleteDatabaseFinal(pendingDeleteCall->callbacks());
1158     }
1159     // deleteDatabaseFinal should never re-queue calls.
1160     ASSERT(m_pendingDeleteCalls.isEmpty());
1161
1162     // This check is also not really needed, openConnection would just requeue its calls.
1163     if (m_runningVersionChangeTransaction)
1164         return;
1165
1166     // Open calls can be requeued if an open call started a version change transaction.
1167     Deque<OwnPtr<PendingOpenCall> > pendingOpenCalls;
1168     m_pendingOpenCalls.swap(pendingOpenCalls);
1169     while (!pendingOpenCalls.isEmpty()) {
1170         OwnPtr<PendingOpenCall> pendingOpenCall = pendingOpenCalls.takeFirst();
1171         openConnection(pendingOpenCall->callbacks(), pendingOpenCall->databaseCallbacks(), pendingOpenCall->transactionId(), pendingOpenCall->version());
1172     }
1173 }
1174
1175 void IDBDatabaseBackendImpl::createTransaction(int64_t transactionId, PassRefPtr<IDBDatabaseCallbacks> callbacks, const Vector<int64_t>& objectStoreIds, unsigned short mode)
1176 {
1177     RefPtr<IDBTransactionBackendImpl> transaction = IDBTransactionBackendImpl::create(transactionId, callbacks, objectStoreIds, static_cast<IndexedDB::TransactionMode>(mode), this);
1178     ASSERT(!m_transactions.contains(transactionId));
1179     m_transactions.add(transactionId, transaction.get());
1180 }
1181
1182 void IDBDatabaseBackendImpl::openConnection(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, int64_t version)
1183 {
1184     ASSERT(m_backingStore.get());
1185     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
1186     RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
1187
1188     if (!m_pendingDeleteCalls.isEmpty() || m_runningVersionChangeTransaction) {
1189         m_pendingOpenCalls.append(PendingOpenCall::create(callbacks, databaseCallbacks, transactionId, version));
1190         return;
1191     }
1192
1193     if (m_metadata.id == InvalidId) {
1194         // The database was deleted then immediately re-opened; openInternal() recreates it in the backing store.
1195         if (openInternal())
1196             ASSERT(m_metadata.intVersion == IDBDatabaseMetadata::NoIntVersion);
1197         else {
1198             String message;
1199             RefPtr<IDBDatabaseError> error;
1200             if (version == IDBDatabaseMetadata::NoIntVersion)
1201                 message = "Internal error opening database with no version specified.";
1202             else
1203                 message = String::format("Internal error opening database with version %lld", static_cast<long long>(version));
1204             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, message));
1205             return;
1206         }
1207     }
1208
1209     // We infer that the database didn't exist from its lack of either type of version.
1210     bool isNewDatabase = m_metadata.version == NoStringVersion && m_metadata.intVersion == IDBDatabaseMetadata::NoIntVersion;
1211
1212     if (version == IDBDatabaseMetadata::DefaultIntVersion) {
1213         // For unit tests only - skip upgrade steps. Calling from script with DefaultIntVersion throws exception.
1214         ASSERT(isNewDatabase);
1215         m_databaseCallbacksSet.add(databaseCallbacks);
1216         callbacks->onSuccess(this, this->metadata());
1217         return;
1218     }
1219
1220     if (version == IDBDatabaseMetadata::NoIntVersion) {
1221         if (!isNewDatabase) {
1222             m_databaseCallbacksSet.add(RefPtr<IDBDatabaseCallbacks>(databaseCallbacks));
1223             callbacks->onSuccess(this, this->metadata());
1224             return;
1225         }
1226         // Spec says: If no version is specified and no database exists, set database version to 1.
1227         version = 1;
1228     }
1229
1230     if (version > m_metadata.intVersion) {
1231         runIntVersionChangeTransaction(callbacks, databaseCallbacks, transactionId, version);
1232         return;
1233     }
1234     if (version < m_metadata.intVersion) {
1235         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))));
1236         return;
1237     }
1238     ASSERT(version == m_metadata.intVersion);
1239     m_databaseCallbacksSet.add(databaseCallbacks);
1240     callbacks->onSuccess(this, this->metadata());
1241 }
1242
1243 void IDBDatabaseBackendImpl::runIntVersionChangeTransaction(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, int64_t requestedVersion)
1244 {
1245     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
1246     RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
1247     ASSERT(callbacks);
1248     for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) {
1249         // Front end ensures the event is not fired at connections that have closePending set.
1250         if (*it != databaseCallbacks)
1251             (*it)->onVersionChange(m_metadata.intVersion, requestedVersion);
1252     }
1253     // The spec dictates we wait until all the version change events are
1254     // delivered and then check m_databaseCallbacks.empty() before proceeding
1255     // or firing a blocked event, but instead we should be consistent with how
1256     // the old setVersion (incorrectly) did it.
1257     // FIXME: Remove the call to onBlocked and instead wait until the frontend
1258     // tells us that all the blocked events have been delivered. See
1259     // https://bugs.webkit.org/show_bug.cgi?id=71130
1260     if (connectionCount())
1261         callbacks->onBlocked(m_metadata.intVersion);
1262     // FIXME: Add test for m_runningVersionChangeTransaction.
1263     if (m_runningVersionChangeTransaction || connectionCount()) {
1264         m_pendingOpenCalls.append(PendingOpenCall::create(callbacks, databaseCallbacks, transactionId, requestedVersion));
1265         return;
1266     }
1267
1268     Vector<int64_t> objectStoreIds;
1269     createTransaction(transactionId, databaseCallbacks, objectStoreIds, IndexedDB::TransactionVersionChange);
1270     RefPtr<IDBTransactionBackendImpl> transaction = m_transactions.get(transactionId);
1271
1272     transaction->scheduleTask(VersionChangeOperation::create(this, transactionId, requestedVersion, callbacks, databaseCallbacks), VersionChangeAbortOperation::create(this, m_metadata.version, m_metadata.intVersion));
1273
1274     ASSERT(!m_pendingSecondHalfOpen);
1275     m_databaseCallbacksSet.add(databaseCallbacks);
1276 }
1277
1278 void IDBDatabaseBackendImpl::deleteDatabase(PassRefPtr<IDBCallbacks> prpCallbacks)
1279 {
1280     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
1281     if (isDeleteDatabaseBlocked()) {
1282         for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) {
1283             // Front end ensures the event is not fired at connections that have closePending set.
1284             (*it)->onVersionChange(NoStringVersion);
1285         }
1286         // FIXME: Only fire onBlocked if there are open connections after the
1287         // VersionChangeEvents are received, not just set up to fire.
1288         // https://bugs.webkit.org/show_bug.cgi?id=71130
1289         callbacks->onBlocked(m_metadata.intVersion);
1290         m_pendingDeleteCalls.append(PendingDeleteCall::create(callbacks.release()));
1291         return;
1292     }
1293     deleteDatabaseFinal(callbacks.release());
1294 }
1295
1296 bool IDBDatabaseBackendImpl::isDeleteDatabaseBlocked()
1297 {
1298     return connectionCount();
1299 }
1300
1301 void IDBDatabaseBackendImpl::deleteDatabaseFinal(PassRefPtr<IDBCallbacks> callbacks)
1302 {
1303     ASSERT(!isDeleteDatabaseBlocked());
1304     ASSERT(m_backingStore);
1305     if (!m_backingStore->deleteDatabase(m_metadata.name)) {
1306         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error deleting database."));
1307         return;
1308     }
1309     m_metadata.version = NoStringVersion;
1310     m_metadata.id = InvalidId;
1311     m_metadata.intVersion = IDBDatabaseMetadata::NoIntVersion;
1312     m_metadata.objectStores.clear();
1313     callbacks->onSuccess();
1314 }
1315
1316 void IDBDatabaseBackendImpl::close(PassRefPtr<IDBDatabaseCallbacks> prpCallbacks)
1317 {
1318     RefPtr<IDBDatabaseCallbacks> callbacks = prpCallbacks;
1319     ASSERT(m_databaseCallbacksSet.contains(callbacks));
1320
1321     m_databaseCallbacksSet.remove(callbacks);
1322     if (m_pendingSecondHalfOpen && m_pendingSecondHalfOpen->databaseCallbacks() == callbacks) {
1323         m_pendingSecondHalfOpen->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "The connection was closed."));
1324         m_pendingSecondHalfOpen.release();
1325     }
1326
1327     if (connectionCount() > 1)
1328         return;
1329
1330     // processPendingCalls allows the inspector to process a pending open call
1331     // and call close, reentering IDBDatabaseBackendImpl::close. Then the
1332     // backend would be removed both by the inspector closing its connection, and
1333     // by the connection that first called close.
1334     // To avoid that situation, don't proceed in case of reentrancy.
1335     if (m_closingConnection)
1336         return;
1337     m_closingConnection = true;
1338     processPendingCalls();
1339
1340     // FIXME: Add a test for the m_pendingOpenCalls cases below.
1341     if (!connectionCount() && !m_pendingOpenCalls.size() && !m_pendingDeleteCalls.size()) {
1342         TransactionMap transactions(m_transactions);
1343         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Connection is closing.");
1344         for (TransactionMap::const_iterator::Values it = transactions.values().begin(), end = transactions.values().end(); it != end; ++it)
1345             (*it)->abort(error);
1346
1347         ASSERT(m_transactions.isEmpty());
1348
1349         m_backingStore.clear();
1350         // This check should only be false in tests.
1351         if (m_factory)
1352             m_factory->removeIDBDatabaseBackend(m_identifier);
1353     }
1354     m_closingConnection = false;
1355 }
1356
1357 void CreateObjectStoreAbortOperation::perform(IDBTransactionBackendImpl* transaction)
1358 {
1359     IDB_TRACE("CreateObjectStoreAbortOperation");
1360     ASSERT(!transaction);
1361     m_database->removeObjectStore(m_objectStoreId);
1362 }
1363
1364 void DeleteObjectStoreAbortOperation::perform(IDBTransactionBackendImpl* transaction)
1365 {
1366     IDB_TRACE("DeleteObjectStoreAbortOperation");
1367     ASSERT(!transaction);
1368     m_database->addObjectStore(m_objectStoreMetadata, IDBObjectStoreMetadata::InvalidId);
1369 }
1370
1371 void IDBDatabaseBackendImpl::VersionChangeAbortOperation::perform(IDBTransactionBackendImpl* transaction)
1372 {
1373     IDB_TRACE("VersionChangeAbortOperation");
1374     ASSERT(!transaction);
1375     m_database->m_metadata.version = m_previousVersion;
1376     m_database->m_metadata.intVersion = m_previousIntVersion;
1377 }
1378
1379 } // namespace WebCore
1380
1381 #endif // ENABLE(INDEXED_DATABASE)