162e9997d5fde30f543bbb5bf3995c64839e4309
[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 "IDBBackingStoreInterface.h"
32 #include "IDBCursorBackend.h"
33 #include "IDBDatabaseCallbacks.h"
34 #include "IDBDatabaseException.h"
35 #include "IDBFactoryBackendInterface.h"
36 #include "IDBIndexWriter.h"
37 #include "IDBKeyRange.h"
38 #include "IDBRecordIdentifier.h"
39 #include "IDBTransactionBackendInterface.h"
40 #include "IDBTransactionCoordinator.h"
41 #include "Logging.h"
42 #include "SharedBuffer.h"
43 #include <wtf/TemporaryChange.h>
44
45 namespace WebCore {
46
47 PassRefPtr<IDBDatabaseBackendImpl> IDBDatabaseBackendImpl::create(const String& name, IDBBackingStoreInterface* backingStore, IDBFactoryBackendInterface* factory, const String& uniqueIdentifier)
48 {
49     RefPtr<IDBDatabaseBackendImpl> backend = adoptRef(new IDBDatabaseBackendImpl(name, backingStore, factory, uniqueIdentifier));
50     backend->openInternalAsync();
51     
52     return backend.release();
53 }
54
55 IDBDatabaseBackendImpl::IDBDatabaseBackendImpl(const String& name, IDBBackingStoreInterface* backingStore, IDBFactoryBackendInterface* factory, const String& uniqueIdentifier)
56     : m_backingStore(backingStore)
57     , m_metadata(name, InvalidId, 0, InvalidId)
58     , m_identifier(uniqueIdentifier)
59     , m_factory(factory)
60     , m_transactionCoordinator(IDBTransactionCoordinator::create())
61     , m_closingConnection(false)
62 {
63     ASSERT(!m_metadata.name.isNull());
64 }
65
66 void IDBDatabaseBackendImpl::addObjectStore(const IDBObjectStoreMetadata& objectStore, int64_t newMaxObjectStoreId)
67 {
68     ASSERT(!m_metadata.objectStores.contains(objectStore.id));
69     if (newMaxObjectStoreId != IDBObjectStoreMetadata::InvalidId) {
70         ASSERT(m_metadata.maxObjectStoreId < newMaxObjectStoreId);
71         m_metadata.maxObjectStoreId = newMaxObjectStoreId;
72     }
73     m_metadata.objectStores.set(objectStore.id, objectStore);
74 }
75
76 void IDBDatabaseBackendImpl::removeObjectStore(int64_t objectStoreId)
77 {
78     ASSERT(m_metadata.objectStores.contains(objectStoreId));
79     m_metadata.objectStores.remove(objectStoreId);
80 }
81
82 void IDBDatabaseBackendImpl::addIndex(int64_t objectStoreId, const IDBIndexMetadata& index, int64_t newMaxIndexId)
83 {
84     ASSERT(m_metadata.objectStores.contains(objectStoreId));
85     IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
86
87     ASSERT(!objectStore.indexes.contains(index.id));
88     objectStore.indexes.set(index.id, index);
89     if (newMaxIndexId != IDBIndexMetadata::InvalidId) {
90         ASSERT(objectStore.maxIndexId < newMaxIndexId);
91         objectStore.maxIndexId = newMaxIndexId;
92     }
93     m_metadata.objectStores.set(objectStoreId, objectStore);
94 }
95
96 void IDBDatabaseBackendImpl::removeIndex(int64_t objectStoreId, int64_t indexId)
97 {
98     ASSERT(m_metadata.objectStores.contains(objectStoreId));
99     IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
100
101     ASSERT(objectStore.indexes.contains(indexId));
102     objectStore.indexes.remove(indexId);
103     m_metadata.objectStores.set(objectStoreId, objectStore);
104 }
105
106 void IDBDatabaseBackendImpl::openInternalAsync()
107 {
108     RefPtr<IDBDatabaseBackendImpl> self = this;
109     m_backingStore->getOrEstablishIDBDatabaseMetadata(m_metadata.name, [self](const IDBDatabaseMetadata& metadata, bool success) {
110         self->didOpenInternalAsync(metadata, success);
111     });
112 }
113
114 void IDBDatabaseBackendImpl::didOpenInternalAsync(const IDBDatabaseMetadata& metadata, bool success)
115 {
116     if (!success) {
117         processPendingOpenCalls(false);
118         return;
119     }
120
121     m_metadata = metadata;
122
123     processPendingCalls();
124 }
125
126 IDBDatabaseBackendImpl::~IDBDatabaseBackendImpl()
127 {
128 }
129
130 IDBBackingStoreInterface* IDBDatabaseBackendImpl::backingStore() const
131 {
132     return m_backingStore.get();
133 }
134
135 void IDBDatabaseBackendImpl::createObjectStore(int64_t transactionId, int64_t objectStoreId, const String& name, const IDBKeyPath& keyPath, bool autoIncrement)
136 {
137     LOG(StorageAPI, "IDBDatabaseBackendImpl::createObjectStore");
138     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
139     if (!transaction)
140         return;
141     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
142
143     ASSERT(!m_metadata.objectStores.contains(objectStoreId));
144     IDBObjectStoreMetadata objectStoreMetadata(name, objectStoreId, keyPath, autoIncrement, IDBDatabaseBackendInterface::MinimumIndexId);
145
146     transaction->scheduleCreateObjectStoreOperation(objectStoreMetadata);
147     addObjectStore(objectStoreMetadata, objectStoreId);
148 }
149
150 void IDBDatabaseBackendImpl::deleteObjectStore(int64_t transactionId, int64_t objectStoreId)
151 {
152     LOG(StorageAPI, "IDBDatabaseBackendImpl::deleteObjectStore");
153     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
154     if (!transaction)
155         return;
156     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
157
158     ASSERT(m_metadata.objectStores.contains(objectStoreId));
159     const IDBObjectStoreMetadata& objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
160
161     transaction->scheduleDeleteObjectStoreOperation(objectStoreMetadata);
162     removeObjectStore(objectStoreId);
163 }
164
165 void IDBDatabaseBackendImpl::createIndex(int64_t transactionId, int64_t objectStoreId, int64_t indexId, const String& name, const IDBKeyPath& keyPath, bool unique, bool multiEntry)
166 {
167     LOG(StorageAPI, "IDBDatabaseBackendImpl::createIndex");
168     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
169     if (!transaction)
170         return;
171     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
172
173     ASSERT(m_metadata.objectStores.contains(objectStoreId));
174     const IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
175
176     ASSERT(!objectStore.indexes.contains(indexId));
177     const IDBIndexMetadata indexMetadata(name, indexId, keyPath, unique, multiEntry);
178
179     transaction->scheduleCreateIndexOperation(objectStoreId, indexMetadata);
180
181     addIndex(objectStoreId, indexMetadata, indexId);
182 }
183
184 void IDBDatabaseBackendImpl::deleteIndex(int64_t transactionId, int64_t objectStoreId, int64_t indexId)
185 {
186     LOG(StorageAPI, "IDBDatabaseBackendImpl::deleteIndex");
187     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
188     if (!transaction)
189         return;
190     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
191
192     ASSERT(m_metadata.objectStores.contains(objectStoreId));
193     const IDBObjectStoreMetadata objectStore = m_metadata.objectStores.get(objectStoreId);
194
195     ASSERT(objectStore.indexes.contains(indexId));
196     const IDBIndexMetadata& indexMetadata = objectStore.indexes.get(indexId);
197
198     transaction->scheduleDeleteIndexOperation(objectStoreId, indexMetadata);
199
200     removeIndex(objectStoreId, indexId);
201 }
202
203 void IDBDatabaseBackendImpl::commit(int64_t transactionId)
204 {
205     // 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.
206     if (m_transactions.contains(transactionId))
207         m_transactions.get(transactionId)->commit();
208 }
209
210 void IDBDatabaseBackendImpl::abort(int64_t transactionId)
211 {
212     // If the transaction is unknown, then it has already been aborted by the backend before this call so it is safe to ignore it.
213     if (m_transactions.contains(transactionId))
214         m_transactions.get(transactionId)->abort();
215 }
216
217 void IDBDatabaseBackendImpl::abort(int64_t transactionId, PassRefPtr<IDBDatabaseError> error)
218 {
219     // If the transaction is unknown, then it has already been aborted by the backend before this call so it is safe to ignore it.
220     if (m_transactions.contains(transactionId))
221         m_transactions.get(transactionId)->abort(error);
222 }
223
224 void IDBDatabaseBackendImpl::get(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, bool keyOnly, PassRefPtr<IDBCallbacks> callbacks)
225 {
226     LOG(StorageAPI, "IDBDatabaseBackendImpl::get");
227     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
228     if (!transaction)
229         return;
230
231     transaction->scheduleGetOperation(m_metadata, objectStoreId, indexId, keyRange, keyOnly ? IndexedDB::CursorKeyOnly : IndexedDB::CursorKeyAndValue, callbacks);
232 }
233
234 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)
235 {
236     LOG(StorageAPI, "IDBDatabaseBackendImpl::put");
237     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
238     if (!transaction)
239         return;
240     ASSERT(transaction->mode() != IndexedDB::TransactionReadOnly);
241
242     const IDBObjectStoreMetadata objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
243
244     ASSERT(objectStoreMetadata.autoIncrement || key.get());
245
246     transaction->schedulePutOperation(objectStoreMetadata, value, key, putMode, callbacks, indexIds, indexKeys);
247 }
248
249 void IDBDatabaseBackendImpl::setIndexKeys(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKey> prpPrimaryKey, const Vector<int64_t>& indexIds, const Vector<IndexKeys>& indexKeys)
250 {
251     LOG(StorageAPI, "IDBDatabaseBackendImpl::setIndexKeys");
252     ASSERT(prpPrimaryKey);
253
254     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
255     if (!transaction)
256         return;
257     ASSERT(transaction->mode() == IndexedDB::TransactionVersionChange);
258
259     RefPtr<IDBKey> primaryKey = prpPrimaryKey;
260     RefPtr<IDBBackingStoreInterface> store = m_backingStore;
261     // FIXME: This method could be asynchronous, but we need to evaluate if it's worth the extra complexity.
262     RefPtr<IDBRecordIdentifier> recordIdentifier;
263     bool ok = store->keyExistsInObjectStore(transaction->backingStoreTransaction(), m_metadata.id, objectStoreId, *primaryKey, recordIdentifier);
264     if (!ok) {
265         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error setting index keys."));
266         return;
267     }
268     if (!recordIdentifier) {
269         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, String::format("Internal error setting index keys for object store."));
270         transaction->abort(error.release());
271         return;
272     }
273
274     Vector<RefPtr<IDBIndexWriter>> indexWriters;
275     String errorMessage;
276     bool obeysConstraints = false;
277     ASSERT(m_metadata.objectStores.contains(objectStoreId));
278     const IDBObjectStoreMetadata& objectStoreMetadata = m_metadata.objectStores.get(objectStoreId);
279     bool backingStoreSuccess = store->makeIndexWriters(*transaction, id(), objectStoreMetadata, *primaryKey, false, indexIds, indexKeys, indexWriters, &errorMessage, obeysConstraints);
280     if (!backingStoreSuccess) {
281         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error: backing store error updating index keys."));
282         return;
283     }
284     if (!obeysConstraints) {
285         transaction->abort(IDBDatabaseError::create(IDBDatabaseException::ConstraintError, errorMessage));
286         return;
287     }
288
289     for (size_t i = 0; i < indexWriters.size(); ++i) {
290         IDBIndexWriter* indexWriter = indexWriters[i].get();
291         indexWriter->writeIndexKeys(recordIdentifier.get(), *store.get(), transaction->backingStoreTransaction(), id(), objectStoreId);
292     }
293 }
294
295 void IDBDatabaseBackendImpl::setIndexesReady(int64_t transactionId, int64_t, const Vector<int64_t>& indexIds)
296 {
297     LOG(StorageAPI, "IDBDatabaseBackendImpl::setIndexesReady");
298
299     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
300     if (!transaction)
301         return;
302
303     transaction->scheduleSetIndexesReadyOperation(indexIds.size());
304 }
305
306 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)
307 {
308     LOG(StorageAPI, "IDBDatabaseBackendImpl::openCursor");
309     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
310     if (!transaction)
311         return;
312
313     transaction->scheduleOpenCursorOperation(objectStoreId, indexId, keyRange, direction, keyOnly ? IndexedDB::CursorKeyOnly : IndexedDB::CursorKeyAndValue, taskType, callbacks);
314 }
315
316 void IDBDatabaseBackendImpl::count(int64_t transactionId, int64_t objectStoreId, int64_t indexId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
317 {
318     LOG(StorageAPI, "IDBDatabaseBackendImpl::count");
319     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
320     if (!transaction)
321         return;
322
323     ASSERT(m_metadata.objectStores.contains(objectStoreId));
324     transaction->scheduleCountOperation(objectStoreId, indexId, keyRange, callbacks);
325 }
326
327
328 void IDBDatabaseBackendImpl::deleteRange(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBKeyRange> keyRange, PassRefPtr<IDBCallbacks> callbacks)
329 {
330     LOG(StorageAPI, "IDBDatabaseBackendImpl::deleteRange");
331     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
332     if (!transaction)
333         return;
334     ASSERT(transaction->mode() != IndexedDB::TransactionReadOnly);
335
336     transaction->scheduleDeleteRangeOperation(objectStoreId, keyRange, callbacks);
337 }
338
339 void IDBDatabaseBackendImpl::clear(int64_t transactionId, int64_t objectStoreId, PassRefPtr<IDBCallbacks> callbacks)
340 {
341     LOG(StorageAPI, "IDBDatabaseBackendImpl::clear");
342     IDBTransactionBackendInterface* transaction = m_transactions.get(transactionId);
343     if (!transaction)
344         return;
345     ASSERT(transaction->mode() != IndexedDB::TransactionReadOnly);
346
347     transaction->scheduleClearOperation(objectStoreId, callbacks);
348 }
349
350 void IDBDatabaseBackendImpl::transactionStarted(IDBTransactionBackendInterface* transaction)
351 {
352     if (transaction->mode() == IndexedDB::TransactionVersionChange) {
353         ASSERT(!m_runningVersionChangeTransaction);
354         m_runningVersionChangeTransaction = transaction;
355     }
356 }
357
358 void IDBDatabaseBackendImpl::transactionFinished(IDBTransactionBackendInterface* rawTransaction)
359 {
360     RefPtr<IDBTransactionBackendInterface> transaction = rawTransaction;
361     ASSERT(m_transactions.contains(transaction->id()));
362     ASSERT(m_transactions.get(transaction->id()) == transaction.get());
363     m_transactions.remove(transaction->id());
364     if (transaction->mode() == IndexedDB::TransactionVersionChange) {
365         ASSERT(transaction.get() == m_runningVersionChangeTransaction.get());
366         m_runningVersionChangeTransaction.clear();
367     }
368 }
369
370 void IDBDatabaseBackendImpl::transactionFinishedAndAbortFired(IDBTransactionBackendInterface* rawTransaction)
371 {
372     RefPtr<IDBTransactionBackendInterface> transaction = rawTransaction;
373     if (transaction->mode() == IndexedDB::TransactionVersionChange) {
374         // If this was an open-with-version call, there will be a "second
375         // half" open call waiting for us in processPendingCalls.
376         // FIXME: When we no longer support setVersion, assert such a thing.
377         if (m_pendingSecondHalfOpen) {
378             m_pendingSecondHalfOpen->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "Version change transaction was aborted in upgradeneeded event handler."));
379             m_pendingSecondHalfOpen.release();
380         }
381         processPendingCalls();
382     }
383 }
384
385 void IDBDatabaseBackendImpl::transactionFinishedAndCompleteFired(IDBTransactionBackendInterface* rawTransaction)
386 {
387     RefPtr<IDBTransactionBackendInterface> transaction = rawTransaction;
388     if (transaction->mode() == IndexedDB::TransactionVersionChange)
389         processPendingCalls();
390 }
391
392 size_t IDBDatabaseBackendImpl::connectionCount()
393 {
394     // This does not include pending open calls, as those should not block version changes and deletes.
395     return m_databaseCallbacksSet.size();
396 }
397
398 void IDBDatabaseBackendImpl::processPendingCalls()
399 {
400     if (m_pendingSecondHalfOpen) {
401         ASSERT(m_pendingSecondHalfOpen->version() == m_metadata.version);
402         ASSERT(m_metadata.id != InvalidId);
403         m_pendingSecondHalfOpen->callbacks()->onSuccess(this, this->metadata());
404         m_pendingSecondHalfOpen.release();
405         // Fall through when complete, as pending deletes may be (partially) unblocked.
406     }
407
408     // Note that this check is only an optimization to reduce queue-churn and
409     // not necessary for correctness; deleteDatabase and openConnection will
410     // requeue their calls if this condition is true.
411     if (m_runningVersionChangeTransaction)
412         return;
413
414     if (!m_pendingDeleteCalls.isEmpty() && isDeleteDatabaseBlocked())
415         return;
416     while (!m_pendingDeleteCalls.isEmpty()) {
417         OwnPtr<IDBPendingDeleteCall> pendingDeleteCall = m_pendingDeleteCalls.takeFirst();
418         m_deleteCallbacksWaitingCompletion.add(pendingDeleteCall->callbacks());
419         deleteDatabaseAsync(pendingDeleteCall->callbacks());
420     }
421
422     // deleteDatabaseAsync should never re-queue calls.
423     ASSERT(m_pendingDeleteCalls.isEmpty());
424
425     // If there are any database deletions waiting for completion, we're done for now.
426     // Further callbacks will be handled in a future call to processPendingCalls().
427     if (m_deleteCallbacksWaitingCompletion.isEmpty())
428         return;
429
430     if (m_runningVersionChangeTransaction)
431         return;
432
433     processPendingOpenCalls(true);
434 }
435
436 void IDBDatabaseBackendImpl::processPendingOpenCalls(bool success)
437 {
438     // Open calls can be requeued if an open call started a version change transaction or deletes the database.
439     Deque<OwnPtr<IDBPendingOpenCall>> pendingOpenCalls;
440     m_pendingOpenCalls.swap(pendingOpenCalls);
441
442     while (!pendingOpenCalls.isEmpty()) {
443         OwnPtr<IDBPendingOpenCall> pendingOpenCall = pendingOpenCalls.takeFirst();
444         if (success) {
445             if (m_metadata.id == InvalidId) {
446                 // This database was deleted then quickly re-opened.
447                 // openInternalAsync() will recreate it in the backing store and then resume processing pending callbacks.
448                 pendingOpenCalls.prepend(pendingOpenCall.release());
449                 pendingOpenCalls.swap(m_pendingOpenCalls);
450
451                 openInternalAsync();
452                 return;
453             }
454             openConnectionInternal(pendingOpenCall->callbacks(), pendingOpenCall->databaseCallbacks(), pendingOpenCall->transactionId(), pendingOpenCall->version());
455         } else {
456             String message;
457             if (pendingOpenCall->version() == IDBDatabaseMetadata::NoIntVersion)
458                 message = "Internal error opening database with no version specified.";
459             else
460                 message = String::format("Internal error opening database with version %llu", static_cast<unsigned long long>(pendingOpenCall->version()));
461             pendingOpenCall->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, message));
462         }
463     }
464 }
465
466 void IDBDatabaseBackendImpl::createTransaction(int64_t transactionId, PassRefPtr<IDBDatabaseCallbacks> callbacks, const Vector<int64_t>& objectStoreIds, unsigned short mode)
467 {
468     RefPtr<IDBTransactionBackendInterface> transaction = m_factory->maybeCreateTransactionBackend(this, transactionId, callbacks, objectStoreIds, static_cast<IndexedDB::TransactionMode>(mode));
469
470     if (!transaction)
471         return;
472
473     ASSERT(!m_transactions.contains(transactionId));
474     m_transactions.add(transactionId, transaction.get());
475 }
476
477 void IDBDatabaseBackendImpl::openConnection(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, uint64_t version)
478 {
479     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
480     RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
481
482     m_pendingOpenCalls.append(IDBPendingOpenCall::create(*callbacks, *databaseCallbacks, transactionId, version));
483
484     processPendingCalls();
485 }
486
487
488 void IDBDatabaseBackendImpl::openConnectionInternal(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, uint64_t version)
489 {
490     ASSERT(m_backingStore.get());
491     ASSERT(m_pendingDeleteCalls.isEmpty());
492     ASSERT(!m_runningVersionChangeTransaction);
493
494     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
495     RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
496
497     // We infer that the database didn't exist from its lack of either type of version.
498     bool isNewDatabase = m_metadata.version == IDBDatabaseMetadata::NoIntVersion;
499
500     if (version == IDBDatabaseMetadata::DefaultIntVersion) {
501         // FIXME: this comments was related to Chromium code. It may be incorrect
502         // For unit tests only - skip upgrade steps. Calling from script with DefaultIntVersion throws exception.
503         ASSERT(isNewDatabase);
504         m_databaseCallbacksSet.add(databaseCallbacks);
505         callbacks->onSuccess(this, this->metadata());
506         return;
507     }
508
509     if (version == IDBDatabaseMetadata::NoIntVersion) {
510         if (!isNewDatabase) {
511             m_databaseCallbacksSet.add(RefPtr<IDBDatabaseCallbacks>(databaseCallbacks));
512             callbacks->onSuccess(this, this->metadata());
513             return;
514         }
515         // Spec says: If no version is specified and no database exists, set database version to 1.
516         version = 1;
517     }
518
519     if (version > m_metadata.version) {
520         runIntVersionChangeTransaction(callbacks, databaseCallbacks, transactionId, version);
521         return;
522     }
523
524     if (version < m_metadata.version) {
525         callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::VersionError, String::format("The requested version (%llu) is less than the existing version (%llu).", static_cast<unsigned long long>(version), static_cast<unsigned long long>(m_metadata.version))));
526         return;
527     }
528
529     ASSERT(version == m_metadata.version);
530     m_databaseCallbacksSet.add(databaseCallbacks);
531     callbacks->onSuccess(this, this->metadata());
532 }
533
534 void IDBDatabaseBackendImpl::runIntVersionChangeTransaction(PassRefPtr<IDBCallbacks> prpCallbacks, PassRefPtr<IDBDatabaseCallbacks> prpDatabaseCallbacks, int64_t transactionId, int64_t requestedVersion)
535 {
536     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
537     RefPtr<IDBDatabaseCallbacks> databaseCallbacks = prpDatabaseCallbacks;
538     ASSERT(callbacks);
539     for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) {
540         // Front end ensures the event is not fired at connections that have closePending set.
541         if (*it != databaseCallbacks)
542             (*it)->onVersionChange(m_metadata.version, requestedVersion, IndexedDB::NullVersion);
543     }
544     // The spec dictates we wait until all the version change events are
545     // delivered and then check m_databaseCallbacks.empty() before proceeding
546     // or firing a blocked event, but instead we should be consistent with how
547     // the old setVersion (incorrectly) did it.
548     // FIXME: Remove the call to onBlocked and instead wait until the frontend
549     // tells us that all the blocked events have been delivered. See
550     // https://bugs.webkit.org/show_bug.cgi?id=71130
551     if (connectionCount())
552         callbacks->onBlocked(m_metadata.version);
553     // FIXME: Add test for m_runningVersionChangeTransaction.
554     if (m_runningVersionChangeTransaction || connectionCount()) {
555         m_pendingOpenCalls.append(IDBPendingOpenCall::create(*callbacks, *databaseCallbacks, transactionId, requestedVersion));
556         return;
557     }
558
559     Vector<int64_t> objectStoreIds;
560     createTransaction(transactionId, databaseCallbacks, objectStoreIds, IndexedDB::TransactionVersionChange);
561     RefPtr<IDBTransactionBackendInterface> transaction = m_transactions.get(transactionId);
562
563     transaction->scheduleVersionChangeOperation(transactionId, requestedVersion, callbacks, databaseCallbacks, m_metadata);
564
565     ASSERT(!m_pendingSecondHalfOpen);
566     m_databaseCallbacksSet.add(databaseCallbacks);
567 }
568
569 void IDBDatabaseBackendImpl::deleteDatabase(PassRefPtr<IDBCallbacks> prpCallbacks)
570 {
571     RefPtr<IDBCallbacks> callbacks = prpCallbacks;
572     if (isDeleteDatabaseBlocked()) {
573         for (DatabaseCallbacksSet::const_iterator it = m_databaseCallbacksSet.begin(); it != m_databaseCallbacksSet.end(); ++it) {
574             // Front end ensures the event is not fired at connections that have closePending set.
575             (*it)->onVersionChange(m_metadata.version, 0, IndexedDB::NullVersion);
576         }
577         // FIXME: Only fire onBlocked if there are open connections after the
578         // VersionChangeEvents are received, not just set up to fire.
579         // https://bugs.webkit.org/show_bug.cgi?id=71130
580         callbacks->onBlocked(m_metadata.version);
581         m_pendingDeleteCalls.append(IDBPendingDeleteCall::create(callbacks.release()));
582         return;
583     }
584     deleteDatabaseAsync(callbacks.release());
585 }
586
587 bool IDBDatabaseBackendImpl::isDeleteDatabaseBlocked()
588 {
589     return connectionCount();
590 }
591
592 void IDBDatabaseBackendImpl::deleteDatabaseAsync(PassRefPtr<IDBCallbacks> callbacks)
593 {
594     ASSERT(!isDeleteDatabaseBlocked());
595     ASSERT(m_backingStore);
596
597     RefPtr<IDBDatabaseBackendImpl> self(this);
598     m_backingStore->deleteDatabase(m_metadata.name, [self, callbacks](bool success) {
599         ASSERT(self->m_deleteCallbacksWaitingCompletion.contains(callbacks));
600         self->m_deleteCallbacksWaitingCompletion.remove(callbacks);
601
602         // If this IDBDatabaseBackend was closed while waiting for deleteDatabase to complete, no point in performing any callbacks.
603         if (!self->m_backingStore)
604             return;
605
606         if (success) {
607             self->m_metadata.id = InvalidId;
608             self->m_metadata.version = IDBDatabaseMetadata::NoIntVersion;
609             self->m_metadata.objectStores.clear();
610             callbacks->onSuccess();
611         } else
612             callbacks->onError(IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Internal error deleting database."));
613
614         self->processPendingCalls();
615     });
616 }
617
618 void IDBDatabaseBackendImpl::close(PassRefPtr<IDBDatabaseCallbacks> prpCallbacks)
619 {
620     RefPtr<IDBDatabaseCallbacks> callbacks = prpCallbacks;
621     ASSERT(m_databaseCallbacksSet.contains(callbacks));
622
623     m_databaseCallbacksSet.remove(callbacks);
624     if (m_pendingSecondHalfOpen && m_pendingSecondHalfOpen->databaseCallbacks() == callbacks) {
625         m_pendingSecondHalfOpen->callbacks()->onError(IDBDatabaseError::create(IDBDatabaseException::AbortError, "The connection was closed."));
626         m_pendingSecondHalfOpen.release();
627     }
628
629     if (connectionCount() > 1)
630         return;
631
632     // processPendingCalls allows the inspector to process a pending open call
633     // and call close, reentering IDBDatabaseBackendImpl::close. Then the
634     // backend would be removed both by the inspector closing its connection, and
635     // by the connection that first called close.
636     // To avoid that situation, don't proceed in case of reentrancy.
637     if (m_closingConnection)
638         return;
639     TemporaryChange<bool> closingConnection(m_closingConnection, true);
640     processPendingCalls();
641
642     // FIXME: Add a test for the m_pendingOpenCalls cases below.
643     if (!connectionCount() && !m_pendingOpenCalls.size() && !m_pendingDeleteCalls.size()) {
644         TransactionMap transactions(m_transactions);
645         RefPtr<IDBDatabaseError> error = IDBDatabaseError::create(IDBDatabaseException::UnknownError, "Connection is closing.");
646         for (TransactionMap::const_iterator::Values it = transactions.values().begin(), end = transactions.values().end(); it != end; ++it)
647             (*it)->abort(error);
648
649         ASSERT(m_transactions.isEmpty());
650
651         m_backingStore.clear();
652
653         // This check should only be false in unit tests.
654         ASSERT(m_factory);
655         if (m_factory)
656             m_factory->removeIDBDatabaseBackend(m_identifier);
657     }
658 }
659
660 } // namespace WebCore
661
662 #endif // ENABLE(INDEXED_DATABASE)