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 "UniqueIDBDatabaseTransaction.h"
28
29#if ENABLE(INDEXED_DATABASE)
30
31#include "IDBError.h"
32#include "IDBIterateCursorData.h"
33#include "IDBResultData.h"
34#include "IDBServer.h"
35#include "Logging.h"
36#include "UniqueIDBDatabase.h"
37
38namespace WebCore {
39namespace IDBServer {
40
41Ref<UniqueIDBDatabaseTransaction> UniqueIDBDatabaseTransaction::create(UniqueIDBDatabaseConnection& connection, const IDBTransactionInfo& info)
42{
43 return adoptRef(*new UniqueIDBDatabaseTransaction(connection, info));
44}
45
46UniqueIDBDatabaseTransaction::UniqueIDBDatabaseTransaction(UniqueIDBDatabaseConnection& connection, const IDBTransactionInfo& info)
47 : m_databaseConnection(connection)
48 , m_transactionInfo(info)
49{
50 auto database = m_databaseConnection->database();
51 ASSERT(database);
52
53 if (m_transactionInfo.mode() == IDBTransactionMode::Versionchange)
54 m_originalDatabaseInfo = std::make_unique<IDBDatabaseInfo>(database->info());
55
56 auto& server = database->server();
57 m_server = makeWeakPtr(server);
58 server.registerTransaction(*this);
59}
60
61UniqueIDBDatabaseTransaction::~UniqueIDBDatabaseTransaction()
62{
63 if (auto database = m_databaseConnection->database())
64 database->transactionDestroyed(*this);
65
66 if (m_server)
67 m_server->unregisterTransaction(*this);
68}
69
70IDBDatabaseInfo* UniqueIDBDatabaseTransaction::originalDatabaseInfo() const
71{
72 ASSERT(m_transactionInfo.mode() == IDBTransactionMode::Versionchange);
73 return m_originalDatabaseInfo.get();
74}
75
76void UniqueIDBDatabaseTransaction::abort()
77{
78 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::abort");
79
80 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
81
82 auto database = m_databaseConnection->database();
83 ASSERT(database);
84
85 database->abortTransaction(*this, UniqueIDBDatabase::WaitForPendingTasks::Yes, [this, protectedThis](const IDBError& error) {
86 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::abort (callback)");
87 m_databaseConnection->didAbortTransaction(*this, error);
88 });
89}
90
91void UniqueIDBDatabaseTransaction::abortWithoutCallback()
92{
93 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::abortWithoutCallback");
94
95 m_databaseConnection->abortTransactionWithoutCallback(*this);
96}
97
98bool UniqueIDBDatabaseTransaction::isVersionChange() const
99{
100 return m_transactionInfo.mode() == IDBTransactionMode::Versionchange;
101}
102
103bool UniqueIDBDatabaseTransaction::isReadOnly() const
104{
105 return m_transactionInfo.mode() == IDBTransactionMode::Readonly;
106}
107
108void UniqueIDBDatabaseTransaction::commit()
109{
110 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::commit");
111
112 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
113
114 auto database = m_databaseConnection->database();
115 if (!database || database->hardClosedForUserDelete())
116 return;
117
118 database->commitTransaction(*this, [this, protectedThis](const IDBError& error) {
119 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::commit (callback)");
120 m_databaseConnection->didCommitTransaction(*this, error);
121 });
122}
123
124void UniqueIDBDatabaseTransaction::createObjectStore(const IDBRequestData& requestData, const IDBObjectStoreInfo& info)
125{
126 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::createObjectStore");
127
128 ASSERT(isVersionChange());
129 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
130
131 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
132
133 auto database = m_databaseConnection->database();
134 ASSERT(database);
135
136 database->createObjectStore(*this, info, [this, protectedThis, requestData](const IDBError& error) {
137 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::createObjectStore (callback)");
138 if (error.isNull())
139 m_databaseConnection->didCreateObjectStore(IDBResultData::createObjectStoreSuccess(requestData.requestIdentifier()));
140 else
141 m_databaseConnection->didCreateObjectStore(IDBResultData::error(requestData.requestIdentifier(), error));
142 });
143}
144
145void UniqueIDBDatabaseTransaction::deleteObjectStore(const IDBRequestData& requestData, const String& objectStoreName)
146{
147 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteObjectStore");
148
149 ASSERT(isVersionChange());
150 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
151
152 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
153
154 auto database = m_databaseConnection->database();
155 ASSERT(database);
156
157 database->deleteObjectStore(*this, objectStoreName, [this, protectedThis, requestData](const IDBError& error) {
158 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteObjectStore (callback)");
159 if (error.isNull())
160 m_databaseConnection->didDeleteObjectStore(IDBResultData::deleteObjectStoreSuccess(requestData.requestIdentifier()));
161 else
162 m_databaseConnection->didDeleteObjectStore(IDBResultData::error(requestData.requestIdentifier(), error));
163 });
164}
165
166void UniqueIDBDatabaseTransaction::renameObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& newName)
167{
168 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::renameObjectStore");
169
170 ASSERT(isVersionChange());
171 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
172
173 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
174
175 auto database = m_databaseConnection->database();
176 ASSERT(database);
177
178 database->renameObjectStore(*this, objectStoreIdentifier, newName, [this, protectedThis, requestData](const IDBError& error) {
179 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::renameObjectStore (callback)");
180 if (error.isNull())
181 m_databaseConnection->didRenameObjectStore(IDBResultData::renameObjectStoreSuccess(requestData.requestIdentifier()));
182 else
183 m_databaseConnection->didRenameObjectStore(IDBResultData::error(requestData.requestIdentifier(), error));
184 });
185}
186
187void UniqueIDBDatabaseTransaction::clearObjectStore(const IDBRequestData& requestData, uint64_t objectStoreIdentifier)
188{
189 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::clearObjectStore");
190
191 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
192
193 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
194
195 auto database = m_databaseConnection->database();
196 ASSERT(database);
197
198 database->clearObjectStore(*this, objectStoreIdentifier, [this, protectedThis, requestData](const IDBError& error) {
199 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::clearObjectStore (callback)");
200 if (error.isNull())
201 m_databaseConnection->didClearObjectStore(IDBResultData::clearObjectStoreSuccess(requestData.requestIdentifier()));
202 else
203 m_databaseConnection->didClearObjectStore(IDBResultData::error(requestData.requestIdentifier(), error));
204 });
205}
206
207void UniqueIDBDatabaseTransaction::createIndex(const IDBRequestData& requestData, const IDBIndexInfo& info)
208{
209 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::createIndex");
210
211 ASSERT(isVersionChange());
212 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
213
214 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
215
216 auto database = m_databaseConnection->database();
217 ASSERT(database);
218
219 database->createIndex(*this, info, [this, protectedThis, requestData](const IDBError& error) {
220 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::createIndex (callback)");
221 if (error.isNull())
222 m_databaseConnection->didCreateIndex(IDBResultData::createIndexSuccess(requestData.requestIdentifier()));
223 else
224 m_databaseConnection->didCreateIndex(IDBResultData::error(requestData.requestIdentifier(), error));
225 });
226}
227
228void UniqueIDBDatabaseTransaction::deleteIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, const String& indexName)
229{
230 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteIndex");
231
232 ASSERT(isVersionChange());
233 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
234
235 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
236
237 auto database = m_databaseConnection->database();
238 ASSERT(database);
239
240 database->deleteIndex(*this, objectStoreIdentifier, indexName, [this, protectedThis, requestData](const IDBError& error) {
241 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::createIndex (callback)");
242 if (error.isNull())
243 m_databaseConnection->didDeleteIndex(IDBResultData::deleteIndexSuccess(requestData.requestIdentifier()));
244 else
245 m_databaseConnection->didDeleteIndex(IDBResultData::error(requestData.requestIdentifier(), error));
246 });
247}
248
249void UniqueIDBDatabaseTransaction::renameIndex(const IDBRequestData& requestData, uint64_t objectStoreIdentifier, uint64_t indexIdentifier, const String& newName)
250{
251 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::renameIndex");
252
253 ASSERT(isVersionChange());
254 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
255
256 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
257
258 auto database = m_databaseConnection->database();
259 ASSERT(database);
260
261 database->renameIndex(*this, objectStoreIdentifier, indexIdentifier, newName, [this, protectedThis, requestData](const IDBError& error) {
262 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::renameIndex (callback)");
263 if (error.isNull())
264 m_databaseConnection->didRenameIndex(IDBResultData::renameIndexSuccess(requestData.requestIdentifier()));
265 else
266 m_databaseConnection->didRenameIndex(IDBResultData::error(requestData.requestIdentifier(), error));
267 });
268}
269
270
271void UniqueIDBDatabaseTransaction::putOrAdd(const IDBRequestData& requestData, const IDBKeyData& keyData, const IDBValue& value, IndexedDB::ObjectStoreOverwriteMode overwriteMode)
272{
273 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::putOrAdd");
274
275 ASSERT(!isReadOnly());
276 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
277
278 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
279
280 auto database = m_databaseConnection->database();
281 ASSERT(database);
282
283 database->putOrAdd(requestData, keyData, value, overwriteMode, [this, protectedThis, requestData](const IDBError& error, const IDBKeyData& key) {
284 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::putOrAdd (callback)");
285
286 if (error.isNull())
287 m_databaseConnection->connectionToClient().didPutOrAdd(IDBResultData::putOrAddSuccess(requestData.requestIdentifier(), key));
288 else
289 m_databaseConnection->connectionToClient().didPutOrAdd(IDBResultData::error(requestData.requestIdentifier(), error));
290 });
291}
292
293void UniqueIDBDatabaseTransaction::getRecord(const IDBRequestData& requestData, const IDBGetRecordData& getRecordData)
294{
295 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getRecord");
296
297 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
298
299 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
300
301 auto database = m_databaseConnection->database();
302 ASSERT(database);
303
304 database->getRecord(requestData, getRecordData, [this, protectedThis, requestData](const IDBError& error, const IDBGetResult& result) {
305 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getRecord (callback)");
306
307 if (error.isNull())
308 m_databaseConnection->connectionToClient().didGetRecord(IDBResultData::getRecordSuccess(requestData.requestIdentifier(), result));
309 else
310 m_databaseConnection->connectionToClient().didGetRecord(IDBResultData::error(requestData.requestIdentifier(), error));
311 });
312}
313
314void UniqueIDBDatabaseTransaction::getAllRecords(const IDBRequestData& requestData, const IDBGetAllRecordsData& getAllRecordsData)
315{
316 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getAllRecords");
317
318 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
319
320 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
321
322 auto database = m_databaseConnection->database();
323 ASSERT(database);
324
325 database->getAllRecords(requestData, getAllRecordsData, [this, protectedThis, requestData](const IDBError& error, const IDBGetAllResult& result) {
326 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getAllRecords (callback)");
327
328 if (error.isNull())
329 m_databaseConnection->connectionToClient().didGetAllRecords(IDBResultData::getAllRecordsSuccess(requestData.requestIdentifier(), result));
330 else
331 m_databaseConnection->connectionToClient().didGetAllRecords(IDBResultData::error(requestData.requestIdentifier(), error));
332 });
333}
334
335void UniqueIDBDatabaseTransaction::getCount(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
336{
337 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getCount");
338
339 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
340
341 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
342
343 auto database = m_databaseConnection->database();
344 ASSERT(database);
345
346 database->getCount(requestData, keyRangeData, [this, protectedThis, requestData](const IDBError& error, uint64_t count) {
347 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::getCount (callback)");
348
349 if (error.isNull())
350 m_databaseConnection->connectionToClient().didGetCount(IDBResultData::getCountSuccess(requestData.requestIdentifier(), count));
351 else
352 m_databaseConnection->connectionToClient().didGetCount(IDBResultData::error(requestData.requestIdentifier(), error));
353 });
354}
355
356void UniqueIDBDatabaseTransaction::deleteRecord(const IDBRequestData& requestData, const IDBKeyRangeData& keyRangeData)
357{
358 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteRecord");
359
360 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
361
362 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
363
364 auto database = m_databaseConnection->database();
365 ASSERT(database);
366
367 database->deleteRecord(requestData, keyRangeData, [this, protectedThis, requestData](const IDBError& error) {
368 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::deleteRecord (callback)");
369
370 if (error.isNull())
371 m_databaseConnection->connectionToClient().didDeleteRecord(IDBResultData::deleteRecordSuccess(requestData.requestIdentifier()));
372 else
373 m_databaseConnection->connectionToClient().didDeleteRecord(IDBResultData::error(requestData.requestIdentifier(), error));
374 });
375}
376
377void UniqueIDBDatabaseTransaction::openCursor(const IDBRequestData& requestData, const IDBCursorInfo& info)
378{
379 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::openCursor");
380
381 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
382
383 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
384
385 auto database = m_databaseConnection->database();
386 ASSERT(database);
387
388 database->openCursor(requestData, info, [this, protectedThis, requestData](const IDBError& error, const IDBGetResult& result) {
389 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::openCursor (callback)");
390
391 if (error.isNull())
392 m_databaseConnection->connectionToClient().didOpenCursor(IDBResultData::openCursorSuccess(requestData.requestIdentifier(), result));
393 else
394 m_databaseConnection->connectionToClient().didOpenCursor(IDBResultData::error(requestData.requestIdentifier(), error));
395 });
396}
397
398void UniqueIDBDatabaseTransaction::iterateCursor(const IDBRequestData& requestData, const IDBIterateCursorData& data)
399{
400 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::iterateCursor");
401
402 ASSERT(m_transactionInfo.identifier() == requestData.transactionIdentifier());
403
404 RefPtr<UniqueIDBDatabaseTransaction> protectedThis(this);
405
406 auto database = m_databaseConnection->database();
407 ASSERT(database);
408
409 database->iterateCursor(requestData, data, [this, protectedThis, requestData](const IDBError& error, const IDBGetResult& result) {
410 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::iterateCursor (callback)");
411
412 if (error.isNull())
413 m_databaseConnection->connectionToClient().didIterateCursor(IDBResultData::iterateCursorSuccess(requestData.requestIdentifier(), result));
414 else
415 m_databaseConnection->connectionToClient().didIterateCursor(IDBResultData::error(requestData.requestIdentifier(), error));
416 });
417}
418
419const Vector<uint64_t>& UniqueIDBDatabaseTransaction::objectStoreIdentifiers()
420{
421 if (!m_objectStoreIdentifiers.isEmpty())
422 return m_objectStoreIdentifiers;
423
424 auto& info = m_databaseConnection->database()->info();
425 for (const auto& objectStoreName : info.objectStoreNames()) {
426 auto objectStoreInfo = info.infoForExistingObjectStore(objectStoreName);
427 ASSERT(objectStoreInfo);
428 if (!objectStoreInfo)
429 continue;
430
431 if (m_transactionInfo.objectStores().contains(objectStoreName))
432 m_objectStoreIdentifiers.append(objectStoreInfo->identifier());
433 }
434
435 return m_objectStoreIdentifiers;
436}
437
438void UniqueIDBDatabaseTransaction::didActivateInBackingStore(const IDBError& error)
439{
440 LOG(IndexedDB, "UniqueIDBDatabaseTransaction::didActivateInBackingStore");
441
442 m_databaseConnection->connectionToClient().didStartTransaction(m_transactionInfo.identifier(), error);
443}
444
445} // namespace IDBServer
446} // namespace WebCore
447
448#endif // ENABLE(INDEXED_DATABASE)
449