Modern IDB: After versionchange transactions abort, fire onerror on the original...
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / client / IDBTransactionImpl.cpp
1 /*
2  * Copyright (C) 2015 Apple 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  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "IDBTransactionImpl.h"
28
29 #if ENABLE(INDEXED_DATABASE)
30
31 #include "DOMError.h"
32 #include "EventQueue.h"
33 #include "IDBCursorWithValueImpl.h"
34 #include "IDBDatabaseImpl.h"
35 #include "IDBError.h"
36 #include "IDBEventDispatcher.h"
37 #include "IDBKeyData.h"
38 #include "IDBKeyRangeData.h"
39 #include "IDBObjectStore.h"
40 #include "IDBOpenDBRequestImpl.h"
41 #include "IDBRequestImpl.h"
42 #include "IDBResultData.h"
43 #include "JSDOMWindowBase.h"
44 #include "Logging.h"
45 #include "ScriptExecutionContext.h"
46 #include "TransactionOperation.h"
47
48 namespace WebCore {
49 namespace IDBClient {
50
51 Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info)
52 {
53     return adoptRef(*new IDBTransaction(database, info, nullptr));
54 }
55
56 Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest& request)
57 {
58     return adoptRef(*new IDBTransaction(database, info, &request));
59 }
60
61 IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest* request)
62     : WebCore::IDBTransaction(database.scriptExecutionContext())
63     , m_database(database)
64     , m_info(info)
65     , m_operationTimer(*this, &IDBTransaction::operationTimerFired)
66     , m_openDBRequest(request)
67
68 {
69     relaxAdoptionRequirement();
70
71     if (m_info.mode() == IndexedDB::TransactionMode::VersionChange) {
72         ASSERT(m_openDBRequest);
73         m_originalDatabaseInfo = std::make_unique<IDBDatabaseInfo>(m_database->info());
74         m_startedOnServer = true;
75     } else {
76         activate();
77
78         RefPtr<IDBTransaction> self;
79         JSC::VM& vm = JSDOMWindowBase::commonVM();
80         vm.whenIdle([self, this]() {
81             deactivate();
82         });
83
84         establishOnServer();
85     }
86
87     suspendIfNeeded();
88 }
89
90 IDBTransaction::~IDBTransaction()
91 {
92 }
93
94 const String& IDBTransaction::mode() const
95 {
96     switch (m_info.mode()) {
97     case IndexedDB::TransactionMode::ReadOnly:
98         return IDBTransaction::modeReadOnly();
99     case IndexedDB::TransactionMode::ReadWrite:
100         return IDBTransaction::modeReadWrite();
101     case IndexedDB::TransactionMode::VersionChange:
102         return IDBTransaction::modeVersionChange();
103     }
104
105     RELEASE_ASSERT_NOT_REACHED();
106 }
107
108 WebCore::IDBDatabase* IDBTransaction::db()
109 {
110     return &m_database.get();
111 }
112
113 IDBConnectionToServer& IDBTransaction::serverConnection()
114 {
115     return m_database->serverConnection();
116 }
117
118 RefPtr<DOMError> IDBTransaction::error() const
119 {
120     ASSERT_NOT_REACHED();
121     return nullptr;
122 }
123
124 RefPtr<WebCore::IDBObjectStore> IDBTransaction::objectStore(const String& objectStoreName, ExceptionCode& ec)
125 {
126     LOG(IndexedDB, "IDBTransaction::objectStore");
127
128     if (objectStoreName.isEmpty()) {
129         ec = NOT_FOUND_ERR;
130         return nullptr;
131     }
132
133     if (isFinishedOrFinishing()) {
134         ec = INVALID_STATE_ERR;
135         return nullptr;
136     }
137
138     auto iterator = m_referencedObjectStores.find(objectStoreName);
139     if (iterator != m_referencedObjectStores.end())
140         return iterator->value;
141
142     bool found = false;
143     for (auto& objectStore : m_info.objectStores()) {
144         if (objectStore == objectStoreName) {
145             found = true;
146             break;
147         }
148     }
149
150     auto* info = m_database->info().infoForExistingObjectStore(objectStoreName);
151     if (!info) {
152         ec = NOT_FOUND_ERR;
153         return nullptr;
154     }
155
156     // Version change transactions are scoped to every object store in the database.
157     if (!found && !isVersionChange()) {
158         ec = NOT_FOUND_ERR;
159         return nullptr;
160     }
161
162     auto objectStore = IDBObjectStore::create(*info, *this);
163     m_referencedObjectStores.set(objectStoreName, &objectStore.get());
164
165     return adoptRef(&objectStore.leakRef());
166 }
167
168 void IDBTransaction::abort(ExceptionCode& ec)
169 {
170     LOG(IndexedDB, "IDBTransaction::abort");
171
172     if (isFinishedOrFinishing()) {
173         ec = INVALID_STATE_ERR;
174         return;
175     }
176
177     m_state = IndexedDB::TransactionState::Aborting;
178     m_database->willAbortTransaction(*this);
179
180     m_abortQueue.swap(m_transactionOperationQueue);
181
182     auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::abortOnServerAndCancelRequests);
183     scheduleOperation(WTF::move(operation));
184 }
185
186 void IDBTransaction::abortOnServerAndCancelRequests(TransactionOperation&)
187 {
188     LOG(IndexedDB, "IDBTransaction::abortOnServerAndCancelRequests");
189
190     ASSERT(m_transactionOperationQueue.isEmpty());
191
192     serverConnection().abortTransaction(*this);
193
194     IDBError error(IDBExceptionCode::AbortError);
195     for (auto& operation : m_abortQueue)
196         operation->completed(IDBResultData::error(operation->identifier(), error));
197
198     // Since we're aborting, this abortOnServerAndCancelRequests() operation should be the only
199     // in-progress operation, and it should be impossible to have queued any further operations.
200     ASSERT(m_transactionOperationMap.size() == 1);
201     ASSERT(m_transactionOperationQueue.isEmpty());
202 }
203
204 const char* IDBTransaction::activeDOMObjectName() const
205 {
206     return "IDBTransaction";
207 }
208
209 bool IDBTransaction::canSuspendForPageCache() const
210 {
211     return false;
212 }
213
214 bool IDBTransaction::hasPendingActivity() const
215 {
216     return m_state != IndexedDB::TransactionState::Finished;
217 }
218
219 bool IDBTransaction::isActive() const
220 {
221     return m_state == IndexedDB::TransactionState::Active;
222 }
223
224 bool IDBTransaction::isFinishedOrFinishing() const
225 {
226     return m_state == IndexedDB::TransactionState::Committing
227         || m_state == IndexedDB::TransactionState::Aborting
228         || m_state == IndexedDB::TransactionState::Finished;
229 }
230
231 void IDBTransaction::addRequest(IDBRequest& request)
232 {
233     m_openRequests.add(&request);
234 }
235
236 void IDBTransaction::removeRequest(IDBRequest& request)
237 {
238     ASSERT(m_openRequests.contains(&request));
239     m_openRequests.remove(&request);
240 }
241
242 void IDBTransaction::scheduleOperation(RefPtr<TransactionOperation>&& operation)
243 {
244     ASSERT(!m_transactionOperationMap.contains(operation->identifier()));
245
246     m_transactionOperationQueue.append(operation);
247     m_transactionOperationMap.set(operation->identifier(), WTF::move(operation));
248
249     scheduleOperationTimer();
250 }
251
252 void IDBTransaction::scheduleOperationTimer()
253 {
254     if (!m_operationTimer.isActive())
255         m_operationTimer.startOneShot(0);
256 }
257
258 void IDBTransaction::operationTimerFired()
259 {
260     LOG(IndexedDB, "IDBTransaction::operationTimerFired (%p)", this);
261
262     if (!m_startedOnServer)
263         return;
264
265     if (!m_transactionOperationQueue.isEmpty()) {
266         auto operation = m_transactionOperationQueue.takeFirst();
267         operation->perform();
268
269         return;
270     }
271
272     if (!m_transactionOperationMap.isEmpty() || !m_openRequests.isEmpty())
273         return;
274
275     if (!isFinishedOrFinishing())
276         commit();
277 }
278
279 void IDBTransaction::commit()
280 {
281     LOG(IndexedDB, "IDBTransaction::commit");
282
283     ASSERT(!isFinishedOrFinishing());
284
285     m_state = IndexedDB::TransactionState::Committing;
286     m_database->willCommitTransaction(*this);
287
288     auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::commitOnServer);
289     scheduleOperation(WTF::move(operation));
290 }
291
292 void IDBTransaction::commitOnServer(TransactionOperation&)
293 {
294     LOG(IndexedDB, "IDBTransaction::commitOnServer");
295     serverConnection().commitTransaction(*this);
296 }
297
298 void IDBTransaction::finishAbortOrCommit()
299 {
300     ASSERT(m_state != IndexedDB::TransactionState::Finished);
301     m_state = IndexedDB::TransactionState::Finished;
302
303     m_originalDatabaseInfo = nullptr;
304 }
305
306 void IDBTransaction::didStart(const IDBError& error)
307 {
308     LOG(IndexedDB, "IDBTransaction::didStart");
309
310     m_database->didStartTransaction(*this);
311
312     m_startedOnServer = true;
313
314     // It's possible the transaction failed to start on the server.
315     // That equates to an abort.
316     if (!error.isNull()) {
317         didAbort(error);
318         return;
319     }
320
321     scheduleOperationTimer();
322 }
323
324 void IDBTransaction::notifyDidAbort(const IDBError& error)
325 {
326     m_database->didAbortTransaction(*this);
327     m_idbError = error;
328     fireOnAbort();
329
330     if (isVersionChange()) {
331         ASSERT(m_openDBRequest);
332         m_openDBRequest->fireErrorAfterVersionChangeAbort();
333     }
334 }
335
336 void IDBTransaction::didAbort(const IDBError& error)
337 {
338     LOG(IndexedDB, "IDBTransaction::didAbort");
339
340     if (m_state == IndexedDB::TransactionState::Finished)
341         return;
342
343     notifyDidAbort(error);
344
345     finishAbortOrCommit();
346 }
347
348 void IDBTransaction::didCommit(const IDBError& error)
349 {
350     LOG(IndexedDB, "IDBTransaction::didCommit");
351
352     ASSERT(m_state == IndexedDB::TransactionState::Committing);
353
354     if (error.isNull()) {
355         m_database->didCommitTransaction(*this);
356         fireOnComplete();
357     } else
358         notifyDidAbort(error);
359
360     finishAbortOrCommit();
361 }
362
363 void IDBTransaction::fireOnComplete()
364 {
365     LOG(IndexedDB, "IDBTransaction::fireOnComplete");
366     enqueueEvent(Event::create(eventNames().completeEvent, false, false));
367 }
368
369 void IDBTransaction::fireOnAbort()
370 {
371     LOG(IndexedDB, "IDBTransaction::fireOnAbort");
372     enqueueEvent(Event::create(eventNames().abortEvent, true, false));
373 }
374
375 void IDBTransaction::enqueueEvent(Ref<Event>&& event)
376 {
377     ASSERT(m_state != IndexedDB::TransactionState::Finished);
378
379     if (!scriptExecutionContext())
380         return;
381
382     event->setTarget(this);
383     scriptExecutionContext()->eventQueue().enqueueEvent(WTF::move(event));
384 }
385
386 bool IDBTransaction::dispatchEvent(Event& event)
387 {
388     LOG(IndexedDB, "IDBTransaction::dispatchEvent");
389
390     ASSERT(scriptExecutionContext());
391     ASSERT(event.target() == this);
392     ASSERT(event.type() == eventNames().completeEvent || event.type() == eventNames().abortEvent);
393
394     Vector<RefPtr<EventTarget>> targets;
395     targets.append(this);
396     targets.append(db());
397
398     bool result = IDBEventDispatcher::dispatch(event, targets);
399
400     if (isVersionChange() && event.type() == eventNames().completeEvent) {
401         ASSERT(m_openDBRequest);
402         m_openDBRequest->fireSuccessAfterVersionChangeCommit();
403     }
404
405     return result;
406 }
407
408 Ref<IDBObjectStore> IDBTransaction::createObjectStore(const IDBObjectStoreInfo& info)
409 {
410     LOG(IndexedDB, "IDBTransaction::createObjectStore");
411     ASSERT(isVersionChange());
412
413     Ref<IDBObjectStore> objectStore = IDBObjectStore::create(info, *this);
414     m_referencedObjectStores.set(info.name(), &objectStore.get());
415
416     auto operation = createTransactionOperation(*this, &IDBTransaction::didCreateObjectStoreOnServer, &IDBTransaction::createObjectStoreOnServer, info);
417     scheduleOperation(WTF::move(operation));
418
419     return WTF::move(objectStore);
420 }
421
422 void IDBTransaction::createObjectStoreOnServer(TransactionOperation& operation, const IDBObjectStoreInfo& info)
423 {
424     LOG(IndexedDB, "IDBTransaction::createObjectStoreOnServer");
425
426     ASSERT(isVersionChange());
427
428     m_database->serverConnection().createObjectStore(operation, info);
429 }
430
431 void IDBTransaction::didCreateObjectStoreOnServer(const IDBResultData& resultData)
432 {
433     LOG(IndexedDB, "IDBTransaction::didCreateObjectStoreOnServer");
434
435     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::CreateObjectStoreSuccess || resultData.type() == IDBResultType::Error);
436 }
437
438 Ref<IDBIndex> IDBTransaction::createIndex(IDBObjectStore& objectStore, const IDBIndexInfo& info)
439 {
440     LOG(IndexedDB, "IDBTransaction::createIndex");
441     ASSERT(isVersionChange());
442
443     Ref<IDBIndex> index = IDBIndex::create(info, objectStore);
444
445     auto operation = createTransactionOperation(*this, &IDBTransaction::didCreateIndexOnServer, &IDBTransaction::createIndexOnServer, info);
446     scheduleOperation(WTF::move(operation));
447
448     return WTF::move(index);
449 }
450
451 void IDBTransaction::createIndexOnServer(TransactionOperation& operation, const IDBIndexInfo& info)
452 {
453     LOG(IndexedDB, "IDBTransaction::createIndexOnServer");
454
455     ASSERT(isVersionChange());
456
457     m_database->serverConnection().createIndex(operation, info);
458 }
459
460 void IDBTransaction::didCreateIndexOnServer(const IDBResultData& resultData)
461 {
462     LOG(IndexedDB, "IDBTransaction::didCreateIndexOnServer");
463
464     if (resultData.type() == IDBResultType::CreateIndexSuccess)
465         return;
466
467     ASSERT(resultData.type() == IDBResultType::Error);
468
469     // This operation might have failed because the transaction is already aborting.
470     if (m_state == IndexedDB::TransactionState::Aborting)
471         return;
472
473     // Otherwise, failure to create an index forced abortion of the transaction.
474     ExceptionCode ec;
475     abort(ec);
476 }
477
478 Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBCursorInfo& info)
479 {
480     LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
481
482     return doRequestOpenCursor(context, IDBCursorWithValue::create(*this, objectStore, info));
483 }
484
485 Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBIndex& index, const IDBCursorInfo& info)
486 {
487     LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
488
489     if (info.cursorType() == IndexedDB::CursorType::KeyOnly)
490         return doRequestOpenCursor(context, IDBCursor::create(*this, index, info));
491
492     return doRequestOpenCursor(context, IDBCursorWithValue::create(*this, index, info));
493 }
494
495 Ref<IDBRequest> IDBTransaction::doRequestOpenCursor(ScriptExecutionContext& context, Ref<IDBCursor>&& cursor)
496 {
497     ASSERT(isActive());
498
499     Ref<IDBRequest> request = IDBRequest::create(context, cursor.get(), *this);
500     addRequest(request.get());
501
502     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didOpenCursorOnServer, &IDBTransaction::openCursorOnServer, cursor->info());
503     scheduleOperation(WTF::move(operation));
504
505     return WTF::move(request);
506 }
507
508 void IDBTransaction::openCursorOnServer(TransactionOperation& operation, const IDBCursorInfo& info)
509 {
510     LOG(IndexedDB, "IDBTransaction::openCursorOnServer");
511
512     m_database->serverConnection().openCursor(operation, info);
513 }
514
515 void IDBTransaction::didOpenCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
516 {
517     LOG(IndexedDB, "IDBTransaction::didOpenCursorOnServer");
518
519     request.didOpenOrIterateCursor(resultData);
520 }
521
522 void IDBTransaction::iterateCursor(IDBCursor& cursor, const IDBKeyData& key, unsigned long count)
523 {
524     LOG(IndexedDB, "IDBTransaction::iterateCursor");
525     ASSERT(isActive());
526     ASSERT(cursor.request());
527
528     addRequest(*cursor.request());
529
530     auto operation = createTransactionOperation(*this, *cursor.request(), &IDBTransaction::didIterateCursorOnServer, &IDBTransaction::iterateCursorOnServer, key, count);
531     scheduleOperation(WTF::move(operation));
532 }
533
534 void IDBTransaction::iterateCursorOnServer(TransactionOperation& operation, const IDBKeyData& key, const unsigned long& count)
535 {
536     LOG(IndexedDB, "IDBTransaction::iterateCursorOnServer");
537
538     serverConnection().iterateCursor(operation, key, count);
539 }
540
541 void IDBTransaction::didIterateCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
542 {
543     LOG(IndexedDB, "IDBTransaction::didIterateCursorOnServer");
544
545     request.didOpenOrIterateCursor(resultData);
546 }
547
548 Ref<IDBRequest> IDBTransaction::requestGetRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& keyRangeData)
549 {
550     LOG(IndexedDB, "IDBTransaction::requestGetRecord");
551     ASSERT(isActive());
552     ASSERT(!keyRangeData.isNull);
553
554     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
555     addRequest(request.get());
556
557     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, keyRangeData);
558     scheduleOperation(WTF::move(operation));
559
560     return WTF::move(request);
561 }
562
563 Ref<IDBRequest> IDBTransaction::requestGetValue(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
564 {
565     LOG(IndexedDB, "IDBTransaction::requestGetValue");
566     return requestIndexRecord(context, index, IndexedDB::IndexRecordType::Value, range);
567 }
568
569 Ref<IDBRequest> IDBTransaction::requestGetKey(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
570 {
571     LOG(IndexedDB, "IDBTransaction::requestGetValue");
572     return requestIndexRecord(context, index, IndexedDB::IndexRecordType::Key, range);
573 }
574
575 Ref<IDBRequest> IDBTransaction::requestIndexRecord(ScriptExecutionContext& context, IDBIndex& index, IndexedDB::IndexRecordType type, const IDBKeyRangeData&range)
576 {
577     LOG(IndexedDB, "IDBTransaction::requestGetValue");
578     ASSERT(isActive());
579     ASSERT(!range.isNull);
580
581     Ref<IDBRequest> request = IDBRequest::createGet(context, index, type, *this);
582     addRequest(request.get());
583
584     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, range);
585     scheduleOperation(WTF::move(operation));
586
587     return WTF::move(request);
588 }
589
590 void IDBTransaction::getRecordOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
591 {
592     LOG(IndexedDB, "IDBTransaction::getRecordOnServer");
593
594     serverConnection().getRecord(operation, keyRange);
595 }
596
597 void IDBTransaction::didGetRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
598 {
599     LOG(IndexedDB, "IDBTransaction::didGetRecordOnServer");
600
601     if (resultData.type() == IDBResultType::Error) {
602         request.requestCompleted(resultData);
603         return;
604     }
605
606     ASSERT(resultData.type() == IDBResultType::GetRecordSuccess);
607
608     const IDBGetResult& result = resultData.getResult();
609
610     if (request.sourceIndexIdentifier() && request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key) {
611         if (!result.keyData().isNull())
612             request.setResult(&result.keyData());
613         else
614             request.setResultToUndefined();
615     } else {
616         if (resultData.getResult().valueBuffer().data())
617             request.setResultToStructuredClone(resultData.getResult().valueBuffer());
618         else
619             request.setResultToUndefined();
620     }
621
622     request.requestCompleted(resultData);
623 }
624
625 Ref<IDBRequest> IDBTransaction::requestCount(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
626 {
627     LOG(IndexedDB, "IDBTransaction::requestCount (IDBObjectStore)");
628     ASSERT(isActive());
629     ASSERT(!range.isNull);
630
631     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
632     addRequest(request.get());
633
634     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
635
636     return request;
637 }
638
639 Ref<IDBRequest> IDBTransaction::requestCount(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
640 {
641     LOG(IndexedDB, "IDBTransaction::requestCount (IDBIndex)");
642     ASSERT(isActive());
643     ASSERT(!range.isNull);
644
645     Ref<IDBRequest> request = IDBRequest::createCount(context, index, *this);
646     addRequest(request.get());
647
648     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
649
650     return request;
651 }
652
653 void IDBTransaction::getCountOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
654 {
655     LOG(IndexedDB, "IDBTransaction::getCountOnServer");
656
657     serverConnection().getCount(operation, keyRange);
658 }
659
660 void IDBTransaction::didGetCountOnServer(IDBRequest& request, const IDBResultData& resultData)
661 {
662     LOG(IndexedDB, "IDBTransaction::didGetCountOnServer");
663
664     request.setResult(resultData.resultInteger());
665     request.requestCompleted(resultData);
666 }
667
668 Ref<IDBRequest> IDBTransaction::requestDeleteRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
669 {
670     LOG(IndexedDB, "IDBTransaction::requestDeleteRecord");
671     ASSERT(isActive());
672     ASSERT(!range.isNull);
673
674     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
675     addRequest(request.get());
676
677     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didDeleteRecordOnServer, &IDBTransaction::deleteRecordOnServer, range));
678     return request;
679 }
680
681 void IDBTransaction::deleteRecordOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
682 {
683     LOG(IndexedDB, "IDBTransaction::deleteRecordOnServer");
684
685     serverConnection().deleteRecord(operation, keyRange);
686 }
687
688 void IDBTransaction::didDeleteRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
689 {
690     LOG(IndexedDB, "IDBTransaction::didDeleteRecordOnServer");
691
692     request.setResultToUndefined();
693     request.requestCompleted(resultData);
694 }
695
696 Ref<IDBRequest> IDBTransaction::requestClearObjectStore(ScriptExecutionContext& context, IDBObjectStore& objectStore)
697 {
698     LOG(IndexedDB, "IDBTransaction::requestClearObjectStore");
699     ASSERT(isActive());
700
701     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
702     addRequest(request.get());
703
704     uint64_t objectStoreIdentifier = objectStore.info().identifier();
705     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didClearObjectStoreOnServer, &IDBTransaction::clearObjectStoreOnServer, objectStoreIdentifier);
706     scheduleOperation(WTF::move(operation));
707
708     return WTF::move(request);
709 }
710
711 void IDBTransaction::clearObjectStoreOnServer(TransactionOperation& operation, const uint64_t& objectStoreIdentifier)
712 {
713     LOG(IndexedDB, "IDBTransaction::clearObjectStoreOnServer");
714
715     serverConnection().clearObjectStore(operation, objectStoreIdentifier);
716 }
717
718 void IDBTransaction::didClearObjectStoreOnServer(IDBRequest& request, const IDBResultData& resultData)
719 {
720     LOG(IndexedDB, "IDBTransaction::didClearObjectStoreOnServer");
721
722     request.setResultToUndefined();
723     request.requestCompleted(resultData);
724 }
725
726 Ref<IDBRequest> IDBTransaction::requestPutOrAdd(ScriptExecutionContext& context, IDBObjectStore& objectStore, IDBKey* key, SerializedScriptValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
727 {
728     LOG(IndexedDB, "IDBTransaction::requestPutOrAdd");
729     ASSERT(isActive());
730     ASSERT(!isReadOnly());
731     ASSERT(objectStore.info().autoIncrement() || key);
732
733     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
734     addRequest(request.get());
735
736     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didPutOrAddOnServer, &IDBTransaction::putOrAddOnServer, key, &value, overwriteMode);
737     scheduleOperation(WTF::move(operation));
738
739     return WTF::move(request);
740 }
741
742 void IDBTransaction::putOrAddOnServer(TransactionOperation& operation, RefPtr<IDBKey> key, RefPtr<SerializedScriptValue> value, const IndexedDB::ObjectStoreOverwriteMode& overwriteMode)
743 {
744     LOG(IndexedDB, "IDBTransaction::putOrAddOnServer");
745
746     ASSERT(!isReadOnly());
747
748     serverConnection().putOrAdd(operation, key, value, overwriteMode);
749 }
750
751 void IDBTransaction::didPutOrAddOnServer(IDBRequest& request, const IDBResultData& resultData)
752 {
753     LOG(IndexedDB, "IDBTransaction::didPutOrAddOnServer");
754
755     request.setResult(resultData.resultKey());
756     request.requestCompleted(resultData);
757 }
758
759 void IDBTransaction::deleteObjectStore(const String& objectStoreName)
760 {
761     LOG(IndexedDB, "IDBTransaction::deleteObjectStore");
762
763     ASSERT(isVersionChange());
764
765     if (auto objectStore = m_referencedObjectStores.take(objectStoreName))
766         objectStore->markAsDeleted();
767
768     auto operation = createTransactionOperation(*this, &IDBTransaction::didDeleteObjectStoreOnServer, &IDBTransaction::deleteObjectStoreOnServer, objectStoreName);
769     scheduleOperation(WTF::move(operation));
770 }
771
772 void IDBTransaction::deleteObjectStoreOnServer(TransactionOperation& operation, const String& objectStoreName)
773 {
774     LOG(IndexedDB, "IDBTransaction::deleteObjectStoreOnServer");
775     ASSERT(isVersionChange());
776
777     serverConnection().deleteObjectStore(operation, objectStoreName);
778 }
779
780 void IDBTransaction::didDeleteObjectStoreOnServer(const IDBResultData& resultData)
781 {
782     LOG(IndexedDB, "IDBTransaction::didDeleteObjectStoreOnServer");
783     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteObjectStoreSuccess || resultData.type() == IDBResultType::Error);
784 }
785
786 void IDBTransaction::deleteIndex(uint64_t objectStoreIdentifier, const String& indexName)
787 {
788     LOG(IndexedDB, "IDBTransaction::deleteIndex");
789
790     ASSERT(isVersionChange());
791
792     auto operation = createTransactionOperation(*this, &IDBTransaction::didDeleteIndexOnServer, &IDBTransaction::deleteIndexOnServer, objectStoreIdentifier, indexName);
793     scheduleOperation(WTF::move(operation));
794 }
795
796 void IDBTransaction::deleteIndexOnServer(TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const String& indexName)
797 {
798     LOG(IndexedDB, "IDBTransaction::deleteIndexOnServer");
799     ASSERT(isVersionChange());
800
801     serverConnection().deleteIndex(operation, objectStoreIdentifier, indexName);
802 }
803
804 void IDBTransaction::didDeleteIndexOnServer(const IDBResultData& resultData)
805 {
806     LOG(IndexedDB, "IDBTransaction::didDeleteIndexOnServer");
807     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteIndexSuccess || resultData.type() == IDBResultType::Error);
808 }
809
810 void IDBTransaction::operationDidComplete(TransactionOperation& operation)
811 {
812     ASSERT(m_transactionOperationMap.get(operation.identifier()) == &operation);
813     m_transactionOperationMap.remove(operation.identifier());
814
815     scheduleOperationTimer();
816 }
817
818 void IDBTransaction::establishOnServer()
819 {
820     LOG(IndexedDB, "IDBTransaction::establishOnServer");
821
822     serverConnection().establishTransaction(*this);
823 }
824
825 void IDBTransaction::activate()
826 {
827     if (isFinishedOrFinishing())
828         return;
829
830     m_state = IndexedDB::TransactionState::Active;
831 }
832
833 void IDBTransaction::deactivate()
834 {
835     if (m_state == IndexedDB::TransactionState::Active)
836         m_state = IndexedDB::TransactionState::Inactive;
837
838     scheduleOperationTimer();
839 }
840
841 } // namespace IDBClient
842 } // namespace WebCore
843
844 #endif // ENABLE(INDEXED_DATABASE)