Modern IDB: storage/indexeddb/delete-in-upgradeneeded-close-in-versionchange.html...
[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 "IDBDatabaseException.h"
35 #include "IDBDatabaseImpl.h"
36 #include "IDBError.h"
37 #include "IDBEventDispatcher.h"
38 #include "IDBKeyData.h"
39 #include "IDBKeyRangeData.h"
40 #include "IDBObjectStore.h"
41 #include "IDBOpenDBRequestImpl.h"
42 #include "IDBRequestImpl.h"
43 #include "IDBResultData.h"
44 #include "JSDOMWindowBase.h"
45 #include "Logging.h"
46 #include "ScriptExecutionContext.h"
47 #include "TransactionOperation.h"
48
49 namespace WebCore {
50 namespace IDBClient {
51
52 Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info)
53 {
54     return adoptRef(*new IDBTransaction(database, info, nullptr));
55 }
56
57 Ref<IDBTransaction> IDBTransaction::create(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest& request)
58 {
59     return adoptRef(*new IDBTransaction(database, info, &request));
60 }
61
62 IDBTransaction::IDBTransaction(IDBDatabase& database, const IDBTransactionInfo& info, IDBOpenDBRequest* request)
63     : WebCore::IDBTransaction(database.scriptExecutionContext())
64     , m_database(database)
65     , m_info(info)
66     , m_operationTimer(*this, &IDBTransaction::operationTimerFired)
67     , m_openDBRequest(request)
68
69 {
70     relaxAdoptionRequirement();
71
72     if (m_info.mode() == IndexedDB::TransactionMode::VersionChange) {
73         ASSERT(m_openDBRequest);
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     return m_domError;
121 }
122
123 RefPtr<WebCore::IDBObjectStore> IDBTransaction::objectStore(const String& objectStoreName, ExceptionCodeWithMessage& ec)
124 {
125     LOG(IndexedDB, "IDBTransaction::objectStore");
126
127     if (isFinishedOrFinishing()) {
128         ec.code = IDBDatabaseException::InvalidStateError;
129         ec.message = ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The transaction finished.");
130         return nullptr;
131     }
132
133     auto iterator = m_referencedObjectStores.find(objectStoreName);
134     if (iterator != m_referencedObjectStores.end())
135         return iterator->value;
136
137     bool found = false;
138     for (auto& objectStore : m_info.objectStores()) {
139         if (objectStore == objectStoreName) {
140             found = true;
141             break;
142         }
143     }
144
145     auto* info = m_database->info().infoForExistingObjectStore(objectStoreName);
146     if (!info) {
147         ec.code = IDBDatabaseException::NotFoundError;
148         ec.message = ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found.");
149         return nullptr;
150     }
151
152     // Version change transactions are scoped to every object store in the database.
153     if (!info || (!found && !isVersionChange())) {
154         ec.code = IDBDatabaseException::NotFoundError;
155         ec.message = ASCIILiteral("Failed to execute 'objectStore' on 'IDBTransaction': The specified object store was not found.");
156         return nullptr;
157     }
158
159     auto objectStore = IDBObjectStore::create(*info, *this);
160     m_referencedObjectStores.set(objectStoreName, &objectStore.get());
161
162     return adoptRef(&objectStore.leakRef());
163 }
164
165
166 void IDBTransaction::abortDueToFailedRequest(DOMError& error)
167 {
168     LOG(IndexedDB, "IDBTransaction::abortDueToFailedRequest");
169     if (isFinishedOrFinishing())
170         return;
171
172     m_domError = &error;
173     ExceptionCodeWithMessage ec;
174     abort(ec);
175 }
176
177 void IDBTransaction::abort(ExceptionCodeWithMessage& ec)
178 {
179     LOG(IndexedDB, "IDBTransaction::abort");
180
181     if (isFinishedOrFinishing()) {
182         ec.code = IDBDatabaseException::InvalidStateError;
183         ec.message = ASCIILiteral("Failed to execute 'abort' on 'IDBTransaction': The transaction is inactive or finished.");
184         return;
185     }
186
187     m_state = IndexedDB::TransactionState::Aborting;
188     m_database->willAbortTransaction(*this);
189
190     if (isVersionChange()) {
191         for (auto& objectStore : m_referencedObjectStores.values())
192             objectStore->rollbackInfoForVersionChangeAbort();
193
194         ASSERT(m_openDBRequest);
195         m_openDBRequest->versionChangeTransactionWillFinish();
196     }
197     
198     m_abortQueue.swap(m_transactionOperationQueue);
199
200     auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::abortOnServerAndCancelRequests);
201     scheduleOperation(WTF::move(operation));
202 }
203
204 void IDBTransaction::abortOnServerAndCancelRequests(TransactionOperation&)
205 {
206     LOG(IndexedDB, "IDBTransaction::abortOnServerAndCancelRequests");
207
208     ASSERT(m_transactionOperationQueue.isEmpty());
209
210     serverConnection().abortTransaction(*this);
211
212     IDBError error(IDBDatabaseException::AbortError);
213     for (auto& operation : m_abortQueue)
214         operation->completed(IDBResultData::error(operation->identifier(), error));
215
216     // Since we're aborting, this abortOnServerAndCancelRequests() operation should be the only
217     // in-progress operation, and it should be impossible to have queued any further operations.
218     ASSERT(m_transactionOperationMap.size() == 1);
219     ASSERT(m_transactionOperationQueue.isEmpty());
220 }
221
222 const char* IDBTransaction::activeDOMObjectName() const
223 {
224     return "IDBTransaction";
225 }
226
227 bool IDBTransaction::canSuspendForDocumentSuspension() const
228 {
229     return false;
230 }
231
232 bool IDBTransaction::hasPendingActivity() const
233 {
234     return !m_contextStopped && m_state != IndexedDB::TransactionState::Finished;
235 }
236
237 void IDBTransaction::stop()
238 {
239     ASSERT(!m_contextStopped);
240     m_contextStopped = true;
241 }
242
243 bool IDBTransaction::isActive() const
244 {
245     return m_state == IndexedDB::TransactionState::Active;
246 }
247
248 bool IDBTransaction::isFinishedOrFinishing() const
249 {
250     return m_state == IndexedDB::TransactionState::Committing
251         || m_state == IndexedDB::TransactionState::Aborting
252         || m_state == IndexedDB::TransactionState::Finished;
253 }
254
255 void IDBTransaction::addRequest(IDBRequest& request)
256 {
257     m_openRequests.add(&request);
258 }
259
260 void IDBTransaction::removeRequest(IDBRequest& request)
261 {
262     ASSERT(m_openRequests.contains(&request));
263     m_openRequests.remove(&request);
264 }
265
266 void IDBTransaction::scheduleOperation(RefPtr<TransactionOperation>&& operation)
267 {
268     ASSERT(!m_transactionOperationMap.contains(operation->identifier()));
269
270     m_transactionOperationQueue.append(operation);
271     m_transactionOperationMap.set(operation->identifier(), WTF::move(operation));
272
273     scheduleOperationTimer();
274 }
275
276 void IDBTransaction::scheduleOperationTimer()
277 {
278     if (!m_operationTimer.isActive())
279         m_operationTimer.startOneShot(0);
280 }
281
282 void IDBTransaction::operationTimerFired()
283 {
284     LOG(IndexedDB, "IDBTransaction::operationTimerFired (%p)", this);
285
286     if (!m_startedOnServer)
287         return;
288
289     if (!m_transactionOperationQueue.isEmpty()) {
290         auto operation = m_transactionOperationQueue.takeFirst();
291         operation->perform();
292
293         return;
294     }
295
296     if (!m_transactionOperationMap.isEmpty() || !m_openRequests.isEmpty())
297         return;
298
299     if (!isFinishedOrFinishing())
300         commit();
301 }
302
303 void IDBTransaction::commit()
304 {
305     LOG(IndexedDB, "IDBTransaction::commit");
306
307     ASSERT(!isFinishedOrFinishing());
308
309     m_state = IndexedDB::TransactionState::Committing;
310     m_database->willCommitTransaction(*this);
311
312     if (isVersionChange()) {
313         ASSERT(m_openDBRequest);
314         m_openDBRequest->versionChangeTransactionWillFinish();
315     }
316
317     auto operation = createTransactionOperation(*this, nullptr, &IDBTransaction::commitOnServer);
318     scheduleOperation(WTF::move(operation));
319 }
320
321 void IDBTransaction::commitOnServer(TransactionOperation&)
322 {
323     LOG(IndexedDB, "IDBTransaction::commitOnServer");
324     serverConnection().commitTransaction(*this);
325 }
326
327 void IDBTransaction::finishAbortOrCommit()
328 {
329     ASSERT(m_state != IndexedDB::TransactionState::Finished);
330     m_state = IndexedDB::TransactionState::Finished;
331 }
332
333 void IDBTransaction::didStart(const IDBError& error)
334 {
335     LOG(IndexedDB, "IDBTransaction::didStart");
336
337     m_database->didStartTransaction(*this);
338
339     m_startedOnServer = true;
340
341     // It's possible the transaction failed to start on the server.
342     // That equates to an abort.
343     if (!error.isNull()) {
344         didAbort(error);
345         return;
346     }
347
348     scheduleOperationTimer();
349 }
350
351 void IDBTransaction::notifyDidAbort(const IDBError& error)
352 {
353     m_database->didAbortTransaction(*this);
354     m_idbError = error;
355     fireOnAbort();
356
357     if (isVersionChange()) {
358         ASSERT(m_openDBRequest);
359         m_openDBRequest->fireErrorAfterVersionChangeCompletion();
360     }
361 }
362
363 void IDBTransaction::didAbort(const IDBError& error)
364 {
365     LOG(IndexedDB, "IDBTransaction::didAbort");
366
367     if (m_state == IndexedDB::TransactionState::Finished)
368         return;
369
370     notifyDidAbort(error);
371
372     finishAbortOrCommit();
373 }
374
375 void IDBTransaction::didCommit(const IDBError& error)
376 {
377     LOG(IndexedDB, "IDBTransaction::didCommit");
378
379     ASSERT(m_state == IndexedDB::TransactionState::Committing);
380
381     if (error.isNull()) {
382         m_database->didCommitTransaction(*this);
383         fireOnComplete();
384     } else
385         notifyDidAbort(error);
386
387     finishAbortOrCommit();
388 }
389
390 void IDBTransaction::fireOnComplete()
391 {
392     LOG(IndexedDB, "IDBTransaction::fireOnComplete");
393     enqueueEvent(Event::create(eventNames().completeEvent, false, false));
394 }
395
396 void IDBTransaction::fireOnAbort()
397 {
398     LOG(IndexedDB, "IDBTransaction::fireOnAbort");
399     enqueueEvent(Event::create(eventNames().abortEvent, true, false));
400 }
401
402 void IDBTransaction::enqueueEvent(Ref<Event>&& event)
403 {
404     ASSERT(m_state != IndexedDB::TransactionState::Finished);
405
406     if (!scriptExecutionContext() || m_contextStopped)
407         return;
408
409     event->setTarget(this);
410     scriptExecutionContext()->eventQueue().enqueueEvent(WTF::move(event));
411 }
412
413 bool IDBTransaction::dispatchEvent(Event& event)
414 {
415     LOG(IndexedDB, "IDBTransaction::dispatchEvent");
416
417     ASSERT(scriptExecutionContext());
418     ASSERT(!m_contextStopped);
419     ASSERT(event.target() == this);
420     ASSERT(event.type() == eventNames().completeEvent || event.type() == eventNames().abortEvent);
421
422     Vector<RefPtr<EventTarget>> targets;
423     targets.append(this);
424     targets.append(db());
425
426     bool result = IDBEventDispatcher::dispatch(event, targets);
427
428     if (isVersionChange() && event.type() == eventNames().completeEvent) {
429         ASSERT(m_openDBRequest);
430
431         if (m_database->isClosingOrClosed())
432             m_openDBRequest->fireErrorAfterVersionChangeCompletion();
433         else
434             m_openDBRequest->fireSuccessAfterVersionChangeCommit();
435     }
436
437     return result;
438 }
439
440 Ref<IDBObjectStore> IDBTransaction::createObjectStore(const IDBObjectStoreInfo& info)
441 {
442     LOG(IndexedDB, "IDBTransaction::createObjectStore");
443     ASSERT(isVersionChange());
444
445     Ref<IDBObjectStore> objectStore = IDBObjectStore::create(info, *this);
446     m_referencedObjectStores.set(info.name(), &objectStore.get());
447
448     auto operation = createTransactionOperation(*this, &IDBTransaction::didCreateObjectStoreOnServer, &IDBTransaction::createObjectStoreOnServer, info);
449     scheduleOperation(WTF::move(operation));
450
451     return WTF::move(objectStore);
452 }
453
454 void IDBTransaction::createObjectStoreOnServer(TransactionOperation& operation, const IDBObjectStoreInfo& info)
455 {
456     LOG(IndexedDB, "IDBTransaction::createObjectStoreOnServer");
457
458     ASSERT(isVersionChange());
459
460     m_database->serverConnection().createObjectStore(operation, info);
461 }
462
463 void IDBTransaction::didCreateObjectStoreOnServer(const IDBResultData& resultData)
464 {
465     LOG(IndexedDB, "IDBTransaction::didCreateObjectStoreOnServer");
466
467     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::CreateObjectStoreSuccess || resultData.type() == IDBResultType::Error);
468 }
469
470 Ref<IDBIndex> IDBTransaction::createIndex(IDBObjectStore& objectStore, const IDBIndexInfo& info)
471 {
472     LOG(IndexedDB, "IDBTransaction::createIndex");
473     ASSERT(isVersionChange());
474
475     Ref<IDBIndex> index = IDBIndex::create(info, objectStore);
476
477     auto operation = createTransactionOperation(*this, &IDBTransaction::didCreateIndexOnServer, &IDBTransaction::createIndexOnServer, info);
478     scheduleOperation(WTF::move(operation));
479
480     return WTF::move(index);
481 }
482
483 void IDBTransaction::createIndexOnServer(TransactionOperation& operation, const IDBIndexInfo& info)
484 {
485     LOG(IndexedDB, "IDBTransaction::createIndexOnServer");
486
487     ASSERT(isVersionChange());
488
489     m_database->serverConnection().createIndex(operation, info);
490 }
491
492 void IDBTransaction::didCreateIndexOnServer(const IDBResultData& resultData)
493 {
494     LOG(IndexedDB, "IDBTransaction::didCreateIndexOnServer");
495
496     if (resultData.type() == IDBResultType::CreateIndexSuccess)
497         return;
498
499     ASSERT(resultData.type() == IDBResultType::Error);
500
501     // This operation might have failed because the transaction is already aborting.
502     if (m_state == IndexedDB::TransactionState::Aborting)
503         return;
504
505     // Otherwise, failure to create an index forced abortion of the transaction.
506     abortDueToFailedRequest(DOMError::create(IDBDatabaseException::getErrorName(resultData.error().code())));
507 }
508
509 Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBCursorInfo& info)
510 {
511     LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
512
513     return doRequestOpenCursor(context, IDBCursorWithValue::create(*this, objectStore, info));
514 }
515
516 Ref<IDBRequest> IDBTransaction::requestOpenCursor(ScriptExecutionContext& context, IDBIndex& index, const IDBCursorInfo& info)
517 {
518     LOG(IndexedDB, "IDBTransaction::requestOpenCursor");
519
520     if (info.cursorType() == IndexedDB::CursorType::KeyOnly)
521         return doRequestOpenCursor(context, IDBCursor::create(*this, index, info));
522
523     return doRequestOpenCursor(context, IDBCursorWithValue::create(*this, index, info));
524 }
525
526 Ref<IDBRequest> IDBTransaction::doRequestOpenCursor(ScriptExecutionContext& context, Ref<IDBCursor>&& cursor)
527 {
528     ASSERT(isActive());
529
530     Ref<IDBRequest> request = IDBRequest::create(context, cursor.get(), *this);
531     addRequest(request.get());
532
533     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didOpenCursorOnServer, &IDBTransaction::openCursorOnServer, cursor->info());
534     scheduleOperation(WTF::move(operation));
535
536     return WTF::move(request);
537 }
538
539 void IDBTransaction::openCursorOnServer(TransactionOperation& operation, const IDBCursorInfo& info)
540 {
541     LOG(IndexedDB, "IDBTransaction::openCursorOnServer");
542
543     m_database->serverConnection().openCursor(operation, info);
544 }
545
546 void IDBTransaction::didOpenCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
547 {
548     LOG(IndexedDB, "IDBTransaction::didOpenCursorOnServer");
549
550     request.didOpenOrIterateCursor(resultData);
551 }
552
553 void IDBTransaction::iterateCursor(IDBCursor& cursor, const IDBKeyData& key, unsigned long count)
554 {
555     LOG(IndexedDB, "IDBTransaction::iterateCursor");
556     ASSERT(isActive());
557     ASSERT(cursor.request());
558
559     addRequest(*cursor.request());
560
561     auto operation = createTransactionOperation(*this, *cursor.request(), &IDBTransaction::didIterateCursorOnServer, &IDBTransaction::iterateCursorOnServer, key, count);
562     scheduleOperation(WTF::move(operation));
563 }
564
565 void IDBTransaction::iterateCursorOnServer(TransactionOperation& operation, const IDBKeyData& key, const unsigned long& count)
566 {
567     LOG(IndexedDB, "IDBTransaction::iterateCursorOnServer");
568
569     serverConnection().iterateCursor(operation, key, count);
570 }
571
572 void IDBTransaction::didIterateCursorOnServer(IDBRequest& request, const IDBResultData& resultData)
573 {
574     LOG(IndexedDB, "IDBTransaction::didIterateCursorOnServer");
575
576     request.didOpenOrIterateCursor(resultData);
577 }
578
579 Ref<IDBRequest> IDBTransaction::requestGetRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& keyRangeData)
580 {
581     LOG(IndexedDB, "IDBTransaction::requestGetRecord");
582     ASSERT(isActive());
583     ASSERT(!keyRangeData.isNull);
584
585     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
586     addRequest(request.get());
587
588     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, keyRangeData);
589     scheduleOperation(WTF::move(operation));
590
591     return WTF::move(request);
592 }
593
594 Ref<IDBRequest> IDBTransaction::requestGetValue(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
595 {
596     LOG(IndexedDB, "IDBTransaction::requestGetValue");
597     return requestIndexRecord(context, index, IndexedDB::IndexRecordType::Value, range);
598 }
599
600 Ref<IDBRequest> IDBTransaction::requestGetKey(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
601 {
602     LOG(IndexedDB, "IDBTransaction::requestGetValue");
603     return requestIndexRecord(context, index, IndexedDB::IndexRecordType::Key, range);
604 }
605
606 Ref<IDBRequest> IDBTransaction::requestIndexRecord(ScriptExecutionContext& context, IDBIndex& index, IndexedDB::IndexRecordType type, const IDBKeyRangeData&range)
607 {
608     LOG(IndexedDB, "IDBTransaction::requestGetValue");
609     ASSERT(isActive());
610     ASSERT(!range.isNull);
611
612     Ref<IDBRequest> request = IDBRequest::createGet(context, index, type, *this);
613     addRequest(request.get());
614
615     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didGetRecordOnServer, &IDBTransaction::getRecordOnServer, range);
616     scheduleOperation(WTF::move(operation));
617
618     return WTF::move(request);
619 }
620
621 void IDBTransaction::getRecordOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
622 {
623     LOG(IndexedDB, "IDBTransaction::getRecordOnServer");
624
625     serverConnection().getRecord(operation, keyRange);
626 }
627
628 void IDBTransaction::didGetRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
629 {
630     LOG(IndexedDB, "IDBTransaction::didGetRecordOnServer");
631
632     if (resultData.type() == IDBResultType::Error) {
633         request.requestCompleted(resultData);
634         return;
635     }
636
637     ASSERT(resultData.type() == IDBResultType::GetRecordSuccess);
638
639     const IDBGetResult& result = resultData.getResult();
640
641     if (request.sourceIndexIdentifier() && request.requestedIndexRecordType() == IndexedDB::IndexRecordType::Key) {
642         if (!result.keyData().isNull())
643             request.setResult(&result.keyData());
644         else
645             request.setResultToUndefined();
646     } else {
647         if (resultData.getResult().valueBuffer().data())
648             request.setResultToStructuredClone(resultData.getResult().valueBuffer());
649         else
650             request.setResultToUndefined();
651     }
652
653     request.requestCompleted(resultData);
654 }
655
656 Ref<IDBRequest> IDBTransaction::requestCount(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
657 {
658     LOG(IndexedDB, "IDBTransaction::requestCount (IDBObjectStore)");
659     ASSERT(isActive());
660     ASSERT(!range.isNull);
661
662     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
663     addRequest(request.get());
664
665     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
666
667     return request;
668 }
669
670 Ref<IDBRequest> IDBTransaction::requestCount(ScriptExecutionContext& context, IDBIndex& index, const IDBKeyRangeData& range)
671 {
672     LOG(IndexedDB, "IDBTransaction::requestCount (IDBIndex)");
673     ASSERT(isActive());
674     ASSERT(!range.isNull);
675
676     Ref<IDBRequest> request = IDBRequest::createCount(context, index, *this);
677     addRequest(request.get());
678
679     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didGetCountOnServer, &IDBTransaction::getCountOnServer, range));
680
681     return request;
682 }
683
684 void IDBTransaction::getCountOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
685 {
686     LOG(IndexedDB, "IDBTransaction::getCountOnServer");
687
688     serverConnection().getCount(operation, keyRange);
689 }
690
691 void IDBTransaction::didGetCountOnServer(IDBRequest& request, const IDBResultData& resultData)
692 {
693     LOG(IndexedDB, "IDBTransaction::didGetCountOnServer");
694
695     request.setResult(resultData.resultInteger());
696     request.requestCompleted(resultData);
697 }
698
699 Ref<IDBRequest> IDBTransaction::requestDeleteRecord(ScriptExecutionContext& context, IDBObjectStore& objectStore, const IDBKeyRangeData& range)
700 {
701     LOG(IndexedDB, "IDBTransaction::requestDeleteRecord");
702     ASSERT(isActive());
703     ASSERT(!range.isNull);
704
705     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
706     addRequest(request.get());
707
708     scheduleOperation(createTransactionOperation(*this, request.get(), &IDBTransaction::didDeleteRecordOnServer, &IDBTransaction::deleteRecordOnServer, range));
709     return request;
710 }
711
712 void IDBTransaction::deleteRecordOnServer(TransactionOperation& operation, const IDBKeyRangeData& keyRange)
713 {
714     LOG(IndexedDB, "IDBTransaction::deleteRecordOnServer");
715
716     serverConnection().deleteRecord(operation, keyRange);
717 }
718
719 void IDBTransaction::didDeleteRecordOnServer(IDBRequest& request, const IDBResultData& resultData)
720 {
721     LOG(IndexedDB, "IDBTransaction::didDeleteRecordOnServer");
722
723     request.setResultToUndefined();
724     request.requestCompleted(resultData);
725 }
726
727 Ref<IDBRequest> IDBTransaction::requestClearObjectStore(ScriptExecutionContext& context, IDBObjectStore& objectStore)
728 {
729     LOG(IndexedDB, "IDBTransaction::requestClearObjectStore");
730     ASSERT(isActive());
731
732     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
733     addRequest(request.get());
734
735     uint64_t objectStoreIdentifier = objectStore.info().identifier();
736     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didClearObjectStoreOnServer, &IDBTransaction::clearObjectStoreOnServer, objectStoreIdentifier);
737     scheduleOperation(WTF::move(operation));
738
739     return WTF::move(request);
740 }
741
742 void IDBTransaction::clearObjectStoreOnServer(TransactionOperation& operation, const uint64_t& objectStoreIdentifier)
743 {
744     LOG(IndexedDB, "IDBTransaction::clearObjectStoreOnServer");
745
746     serverConnection().clearObjectStore(operation, objectStoreIdentifier);
747 }
748
749 void IDBTransaction::didClearObjectStoreOnServer(IDBRequest& request, const IDBResultData& resultData)
750 {
751     LOG(IndexedDB, "IDBTransaction::didClearObjectStoreOnServer");
752
753     request.setResultToUndefined();
754     request.requestCompleted(resultData);
755 }
756
757 Ref<IDBRequest> IDBTransaction::requestPutOrAdd(ScriptExecutionContext& context, IDBObjectStore& objectStore, IDBKey* key, SerializedScriptValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
758 {
759     LOG(IndexedDB, "IDBTransaction::requestPutOrAdd");
760     ASSERT(isActive());
761     ASSERT(!isReadOnly());
762     ASSERT(objectStore.info().autoIncrement() || key);
763
764     Ref<IDBRequest> request = IDBRequest::create(context, objectStore, *this);
765     addRequest(request.get());
766
767     auto operation = createTransactionOperation(*this, request.get(), &IDBTransaction::didPutOrAddOnServer, &IDBTransaction::putOrAddOnServer, key, &value, overwriteMode);
768     scheduleOperation(WTF::move(operation));
769
770     return WTF::move(request);
771 }
772
773 void IDBTransaction::putOrAddOnServer(TransactionOperation& operation, RefPtr<IDBKey> key, RefPtr<SerializedScriptValue> value, const IndexedDB::ObjectStoreOverwriteMode& overwriteMode)
774 {
775     LOG(IndexedDB, "IDBTransaction::putOrAddOnServer");
776
777     ASSERT(!isReadOnly());
778
779     serverConnection().putOrAdd(operation, key, value, overwriteMode);
780 }
781
782 void IDBTransaction::didPutOrAddOnServer(IDBRequest& request, const IDBResultData& resultData)
783 {
784     LOG(IndexedDB, "IDBTransaction::didPutOrAddOnServer");
785
786     request.setResult(resultData.resultKey());
787     request.requestCompleted(resultData);
788 }
789
790 void IDBTransaction::deleteObjectStore(const String& objectStoreName)
791 {
792     LOG(IndexedDB, "IDBTransaction::deleteObjectStore");
793
794     ASSERT(isVersionChange());
795
796     if (auto objectStore = m_referencedObjectStores.take(objectStoreName))
797         objectStore->markAsDeleted();
798
799     auto operation = createTransactionOperation(*this, &IDBTransaction::didDeleteObjectStoreOnServer, &IDBTransaction::deleteObjectStoreOnServer, objectStoreName);
800     scheduleOperation(WTF::move(operation));
801 }
802
803 void IDBTransaction::deleteObjectStoreOnServer(TransactionOperation& operation, const String& objectStoreName)
804 {
805     LOG(IndexedDB, "IDBTransaction::deleteObjectStoreOnServer");
806     ASSERT(isVersionChange());
807
808     serverConnection().deleteObjectStore(operation, objectStoreName);
809 }
810
811 void IDBTransaction::didDeleteObjectStoreOnServer(const IDBResultData& resultData)
812 {
813     LOG(IndexedDB, "IDBTransaction::didDeleteObjectStoreOnServer");
814     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteObjectStoreSuccess || resultData.type() == IDBResultType::Error);
815 }
816
817 void IDBTransaction::deleteIndex(uint64_t objectStoreIdentifier, const String& indexName)
818 {
819     LOG(IndexedDB, "IDBTransaction::deleteIndex");
820
821     ASSERT(isVersionChange());
822
823     auto operation = createTransactionOperation(*this, &IDBTransaction::didDeleteIndexOnServer, &IDBTransaction::deleteIndexOnServer, objectStoreIdentifier, indexName);
824     scheduleOperation(WTF::move(operation));
825 }
826
827 void IDBTransaction::deleteIndexOnServer(TransactionOperation& operation, const uint64_t& objectStoreIdentifier, const String& indexName)
828 {
829     LOG(IndexedDB, "IDBTransaction::deleteIndexOnServer");
830     ASSERT(isVersionChange());
831
832     serverConnection().deleteIndex(operation, objectStoreIdentifier, indexName);
833 }
834
835 void IDBTransaction::didDeleteIndexOnServer(const IDBResultData& resultData)
836 {
837     LOG(IndexedDB, "IDBTransaction::didDeleteIndexOnServer");
838     ASSERT_UNUSED(resultData, resultData.type() == IDBResultType::DeleteIndexSuccess || resultData.type() == IDBResultType::Error);
839 }
840
841 void IDBTransaction::operationDidComplete(TransactionOperation& operation)
842 {
843     ASSERT(m_transactionOperationMap.get(operation.identifier()) == &operation);
844     m_transactionOperationMap.remove(operation.identifier());
845
846     scheduleOperationTimer();
847 }
848
849 void IDBTransaction::establishOnServer()
850 {
851     LOG(IndexedDB, "IDBTransaction::establishOnServer");
852
853     serverConnection().establishTransaction(*this);
854 }
855
856 void IDBTransaction::activate()
857 {
858     if (isFinishedOrFinishing())
859         return;
860
861     m_state = IndexedDB::TransactionState::Active;
862 }
863
864 void IDBTransaction::deactivate()
865 {
866     if (m_state == IndexedDB::TransactionState::Active)
867         m_state = IndexedDB::TransactionState::Inactive;
868
869     scheduleOperationTimer();
870 }
871
872 } // namespace IDBClient
873 } // namespace WebCore
874
875 #endif // ENABLE(INDEXED_DATABASE)