2 * Copyright (C) 2014, 2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "SQLiteIDBCursor.h"
29 #if ENABLE(INDEXED_DATABASE)
31 #include "IDBCursorInfo.h"
32 #include "IDBGetResult.h"
33 #include "IDBSerialization.h"
35 #include "SQLiteIDBBackingStore.h"
36 #include "SQLiteIDBTransaction.h"
37 #include "SQLiteStatement.h"
38 #include "SQLiteTransaction.h"
40 #include <wtf/text/StringBuilder.h>
45 std::unique_ptr<SQLiteIDBCursor> SQLiteIDBCursor::maybeCreate(SQLiteIDBTransaction& transaction, const IDBCursorInfo& info)
47 auto cursor = std::make_unique<SQLiteIDBCursor>(transaction, info);
49 if (!cursor->establishStatement())
52 if (!cursor->advance(1))
58 std::unique_ptr<SQLiteIDBCursor> SQLiteIDBCursor::maybeCreateBackingStoreCursor(SQLiteIDBTransaction& transaction, const uint64_t objectStoreID, const uint64_t indexID, const IDBKeyRangeData& range)
60 auto cursor = std::make_unique<SQLiteIDBCursor>(transaction, objectStoreID, indexID, range);
62 if (!cursor->establishStatement())
65 if (!cursor->advance(1))
71 SQLiteIDBCursor::SQLiteIDBCursor(SQLiteIDBTransaction& transaction, const IDBCursorInfo& info)
72 : m_transaction(&transaction)
73 , m_cursorIdentifier(info.identifier())
74 , m_objectStoreID(info.objectStoreIdentifier())
75 , m_indexID(info.cursorSource() == IndexedDB::CursorSource::Index ? info.sourceIdentifier() : IDBIndexInfo::InvalidId)
76 , m_cursorDirection(info.cursorDirection())
77 , m_cursorType(info.cursorType())
78 , m_keyRange(info.range())
80 ASSERT(m_objectStoreID);
83 SQLiteIDBCursor::SQLiteIDBCursor(SQLiteIDBTransaction& transaction, const uint64_t objectStoreID, const uint64_t indexID, const IDBKeyRangeData& range)
84 : m_transaction(&transaction)
85 , m_cursorIdentifier(transaction.transactionIdentifier())
86 , m_objectStoreID(objectStoreID)
87 , m_indexID(indexID ? indexID : IDBIndexInfo::InvalidId)
88 , m_cursorDirection(IndexedDB::CursorDirection::Next)
89 , m_cursorType(IndexedDB::CursorType::KeyAndValue)
91 , m_backingStoreCursor(true)
93 ASSERT(m_objectStoreID);
96 SQLiteIDBCursor::~SQLiteIDBCursor()
98 if (m_backingStoreCursor)
99 m_transaction->closeCursor(*this);
102 void SQLiteIDBCursor::currentData(IDBGetResult& result)
104 ASSERT(!m_fetchedRecords.isEmpty());
106 auto& currentRecord = m_fetchedRecords.first();
107 if (currentRecord.completed) {
108 ASSERT(!currentRecord.errored);
113 result = { currentRecord.record.key, currentRecord.record.primaryKey, currentRecord.record.value ? *currentRecord.record.value : IDBValue() };
116 static String buildIndexStatement(const IDBKeyRangeData& keyRange, IndexedDB::CursorDirection cursorDirection)
118 StringBuilder builder;
120 builder.appendLiteral("SELECT rowid, key, value FROM IndexRecords WHERE indexID = ? AND objectStoreID = ? AND key ");
121 if (!keyRange.lowerKey.isNull() && !keyRange.lowerOpen)
122 builder.appendLiteral(">=");
126 builder.appendLiteral(" CAST(? AS TEXT) AND key ");
127 if (!keyRange.upperKey.isNull() && !keyRange.upperOpen)
128 builder.appendLiteral("<=");
132 builder.appendLiteral(" CAST(? AS TEXT) ORDER BY key");
133 if (cursorDirection == IndexedDB::CursorDirection::Prev || cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate)
134 builder.appendLiteral(" DESC");
136 builder.appendLiteral(", value");
137 if (cursorDirection == IndexedDB::CursorDirection::Prev)
138 builder.appendLiteral(" DESC");
142 return builder.toString();
145 static String buildObjectStoreStatement(const IDBKeyRangeData& keyRange, IndexedDB::CursorDirection cursorDirection)
147 StringBuilder builder;
149 builder.appendLiteral("SELECT rowid, key, value FROM Records WHERE objectStoreID = ? AND key ");
151 if (!keyRange.lowerKey.isNull() && !keyRange.lowerOpen)
152 builder.appendLiteral(">=");
156 builder.appendLiteral(" CAST(? AS TEXT) AND key ");
158 if (!keyRange.upperKey.isNull() && !keyRange.upperOpen)
159 builder.appendLiteral("<=");
163 builder.appendLiteral(" CAST(? AS TEXT) ORDER BY key");
165 if (cursorDirection == IndexedDB::CursorDirection::Prev || cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate)
166 builder.appendLiteral(" DESC");
170 return builder.toString();
173 bool SQLiteIDBCursor::establishStatement()
175 ASSERT(!m_statement);
178 if (m_indexID != IDBIndexInfo::InvalidId) {
179 sql = buildIndexStatement(m_keyRange, m_cursorDirection);
180 m_boundID = m_indexID;
182 sql = buildObjectStoreStatement(m_keyRange, m_cursorDirection);
183 m_boundID = m_objectStoreID;
186 m_currentLowerKey = m_keyRange.lowerKey.isNull() ? IDBKeyData::minimum() : m_keyRange.lowerKey;
187 m_currentUpperKey = m_keyRange.upperKey.isNull() ? IDBKeyData::maximum() : m_keyRange.upperKey;
189 return createSQLiteStatement(sql);
192 bool SQLiteIDBCursor::createSQLiteStatement(const String& sql)
194 LOG(IndexedDB, "Creating cursor with SQL query: \"%s\"", sql.utf8().data());
196 ASSERT(!m_currentLowerKey.isNull());
197 ASSERT(!m_currentUpperKey.isNull());
198 ASSERT(m_transaction->sqliteTransaction());
200 m_statement = std::make_unique<SQLiteStatement>(m_transaction->sqliteTransaction()->database(), sql);
202 if (m_statement->prepare() != SQLITE_OK) {
203 LOG_ERROR("Could not create cursor statement (prepare/id) - '%s'", m_transaction->sqliteTransaction()->database().lastErrorMsg());
207 return bindArguments();
210 void SQLiteIDBCursor::objectStoreRecordsChanged()
212 if (m_statementNeedsReset)
215 // If ObjectStore or Index contents changed, we need to reset the statement and bind new parameters to it.
216 // This is to pick up any changes that might exist.
217 // We also need to throw away any fetched records as they may no longer be valid.
219 m_statementNeedsReset = true;
220 ASSERT(!m_fetchedRecords.isEmpty());
222 if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) {
223 m_currentLowerKey = m_fetchedRecords.first().record.key;
224 if (!m_keyRange.lowerOpen) {
225 m_keyRange.lowerOpen = true;
226 m_keyRange.lowerKey = m_currentLowerKey;
227 m_statement = nullptr;
230 m_currentUpperKey = m_fetchedRecords.first().record.key;
231 if (!m_keyRange.upperOpen) {
232 m_keyRange.upperOpen = true;
233 m_keyRange.upperKey = m_currentUpperKey;
234 m_statement = nullptr;
238 m_fetchedRecords.clear();
241 void SQLiteIDBCursor::resetAndRebindStatement()
243 ASSERT(!m_currentLowerKey.isNull());
244 ASSERT(!m_currentUpperKey.isNull());
245 ASSERT(m_transaction->sqliteTransaction());
246 ASSERT(m_statementNeedsReset);
248 m_statementNeedsReset = false;
250 if (!m_statement && !establishStatement()) {
251 LOG_ERROR("Unable to establish new statement for cursor iteration");
255 if (m_statement->reset() != SQLITE_OK) {
256 LOG_ERROR("Could not reset cursor statement to respond to object store changes");
263 bool SQLiteIDBCursor::bindArguments()
265 LOG(IndexedDB, "Cursor is binding lower key '%s' and upper key '%s'", m_currentLowerKey.loggingString().utf8().data(), m_currentUpperKey.loggingString().utf8().data());
267 int currentBindArgument = 1;
269 if (m_statement->bindInt64(currentBindArgument++, m_boundID) != SQLITE_OK) {
270 LOG_ERROR("Could not bind id argument (bound ID)");
274 if (m_indexID != IDBIndexInfo::InvalidId && m_statement->bindInt64(currentBindArgument++, m_objectStoreID) != SQLITE_OK) {
275 LOG_ERROR("Could not bind object store id argument for an index cursor");
279 RefPtr<SharedBuffer> buffer = serializeIDBKeyData(m_currentLowerKey);
280 if (m_statement->bindBlob(currentBindArgument++, buffer->data(), buffer->size()) != SQLITE_OK) {
281 LOG_ERROR("Could not create cursor statement (lower key)");
285 buffer = serializeIDBKeyData(m_currentUpperKey);
286 if (m_statement->bindBlob(currentBindArgument++, buffer->data(), buffer->size()) != SQLITE_OK) {
287 LOG_ERROR("Could not create cursor statement (upper key)");
294 void SQLiteIDBCursor::prefetch()
296 ASSERT(!m_fetchedRecords.isEmpty());
297 if (m_fetchedRecords.last().errored || m_fetchedRecords.last().completed)
300 m_currentKeyForUniqueness = m_fetchedRecords.last().record.key;
304 bool SQLiteIDBCursor::advance(uint64_t count)
308 if (!m_fetchedRecords.isEmpty() && m_fetchedRecords.first().isTerminalRecord()) {
309 LOG_ERROR("Attempt to advance a completed cursor");
313 if (!m_fetchedRecords.isEmpty())
314 m_currentKeyForUniqueness = m_fetchedRecords.last().record.key;
316 // Drop already-fetched records up to `count` to see if we've already fetched the record we're looking for.
317 for (size_t i = 0; i < count && !m_fetchedRecords.isEmpty(); ++i) {
318 if (m_fetchedRecords.first().isTerminalRecord())
321 m_fetchedRecords.removeFirst();
324 // If we still have any records left, the first record is our new current record.
325 if (!m_fetchedRecords.isEmpty())
326 return !m_fetchedRecords.first().isTerminalRecord();
328 ASSERT(m_fetchedRecords.isEmpty());
330 for (uint64_t i = 0; i < count; ++i) {
331 if (!m_fetchedRecords.isEmpty()) {
332 ASSERT(m_fetchedRecords.size() == 1);
333 m_currentKeyForUniqueness = m_fetchedRecords.first().record.key;
334 m_fetchedRecords.removeFirst();
340 ASSERT(!m_fetchedRecords.isEmpty());
341 ASSERT(!m_fetchedRecords.first().errored);
342 if (m_fetchedRecords.first().completed)
349 bool SQLiteIDBCursor::fetch()
351 ASSERT(m_fetchedRecords.isEmpty() || !m_fetchedRecords.last().isTerminalRecord());
353 m_fetchedRecords.append({ });
355 bool isUnique = m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate || m_cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate;
357 return fetchNextRecord(m_fetchedRecords.last());
359 while (!m_fetchedRecords.last().completed) {
360 if (!fetchNextRecord(m_fetchedRecords.last()))
363 // If the new current key is different from the old current key, we're done.
364 if (m_currentKeyForUniqueness.compare(m_fetchedRecords.last().record.key))
371 bool SQLiteIDBCursor::fetchNextRecord(SQLiteCursorRecord& record)
373 if (m_statementNeedsReset)
374 resetAndRebindStatement();
378 result = internalFetchNextRecord(record);
379 } while (result == FetchResult::ShouldFetchAgain);
381 return result == FetchResult::Success;
384 void SQLiteIDBCursor::markAsErrored(SQLiteCursorRecord& record)
387 record.completed = true;
388 record.errored = true;
392 SQLiteIDBCursor::FetchResult SQLiteIDBCursor::internalFetchNextRecord(SQLiteCursorRecord& record)
394 ASSERT(m_transaction->sqliteTransaction());
396 ASSERT(!m_fetchedRecords.isEmpty());
397 ASSERT(!m_fetchedRecords.last().isTerminalRecord());
399 record.record.value = nullptr;
401 int result = m_statement->step();
402 if (result == SQLITE_DONE) {
403 // When a cursor reaches its end, that is indicated by having undefined keys/values
405 record.completed = true;
407 return FetchResult::Success;
410 if (result != SQLITE_ROW) {
411 LOG_ERROR("Error advancing cursor - (%i) %s", result, m_transaction->sqliteTransaction()->database().lastErrorMsg());
412 markAsErrored(record);
413 return FetchResult::Failure;
416 record.rowID = m_statement->getColumnInt64(0);
417 ASSERT(record.rowID);
419 Vector<uint8_t> keyData;
420 m_statement->getColumnBlobAsVector(1, keyData);
422 if (!deserializeIDBKeyData(keyData.data(), keyData.size(), record.record.key)) {
423 LOG_ERROR("Unable to deserialize key data from database while advancing cursor");
424 markAsErrored(record);
425 return FetchResult::Failure;
428 m_statement->getColumnBlobAsVector(2, keyData);
430 // The primaryKey of an ObjectStore cursor is the same as its key.
431 if (m_indexID == IDBIndexInfo::InvalidId) {
432 record.record.primaryKey = record.record.key;
434 Vector<String> blobURLs, blobFilePaths;
435 auto error = m_transaction->backingStore().getBlobRecordsForObjectStoreRecord(record.rowID, blobURLs, blobFilePaths);
436 if (!error.isNull()) {
437 LOG_ERROR("Unable to fetch blob records from database while advancing cursor");
438 markAsErrored(record);
439 return FetchResult::Failure;
442 if (m_cursorType == IndexedDB::CursorType::KeyAndValue)
443 record.record.value = std::make_unique<IDBValue>(ThreadSafeDataBuffer::adoptVector(keyData), blobURLs, blobFilePaths);
445 if (!deserializeIDBKeyData(keyData.data(), keyData.size(), record.record.primaryKey)) {
446 LOG_ERROR("Unable to deserialize value data from database while advancing index cursor");
447 markAsErrored(record);
448 return FetchResult::Failure;
451 SQLiteStatement objectStoreStatement(m_statement->database(), "SELECT value FROM Records WHERE key = CAST(? AS TEXT) and objectStoreID = ?;");
453 if (objectStoreStatement.prepare() != SQLITE_OK
454 || objectStoreStatement.bindBlob(1, keyData.data(), keyData.size()) != SQLITE_OK
455 || objectStoreStatement.bindInt64(2, m_objectStoreID) != SQLITE_OK) {
456 LOG_ERROR("Could not create index cursor statement into object store records (%i) '%s'", m_statement->database().lastError(), m_statement->database().lastErrorMsg());
457 markAsErrored(record);
458 return FetchResult::Failure;
461 int result = objectStoreStatement.step();
463 if (result == SQLITE_ROW) {
464 objectStoreStatement.getColumnBlobAsVector(0, keyData);
465 record.record.value = std::make_unique<IDBValue>(ThreadSafeDataBuffer::adoptVector(keyData));
466 } else if (result == SQLITE_DONE) {
467 // This indicates that the record we're trying to retrieve has been removed from the object store.
469 return FetchResult::ShouldFetchAgain;
471 LOG_ERROR("Could not step index cursor statement into object store records (%i) '%s'", m_statement->database().lastError(), m_statement->database().lastErrorMsg());
472 markAsErrored(record);
473 return FetchResult::Failure;
478 return FetchResult::Success;
481 bool SQLiteIDBCursor::iterate(const IDBKeyData& targetKey, const IDBKeyData& targetPrimaryKey)
483 ASSERT(m_transaction->sqliteTransaction());
486 bool result = advance(1);
487 ASSERT(!m_fetchedRecords.isEmpty());
489 // Iterating with no key is equivalent to advancing 1 step.
490 if (targetKey.isNull() || !result)
493 while (!m_fetchedRecords.first().isTerminalRecord()) {
497 // Search for the next key >= the target if the cursor is a Next cursor, or the next key <= if the cursor is a Previous cursor.
498 if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) {
499 if (m_fetchedRecords.first().record.key.compare(targetKey) >= 0)
501 } else if (m_fetchedRecords.first().record.key.compare(targetKey) <= 0)
507 if (targetPrimaryKey.isValid()) {
508 while (!m_fetchedRecords.first().isTerminalRecord() && !m_fetchedRecords.first().record.key.compare(targetKey)) {
512 // Search for the next primary key >= the primary target if the cursor is a Next cursor, or the next key <= if the cursor is a Previous cursor.
513 if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) {
514 if (m_fetchedRecords.first().record.primaryKey.compare(targetPrimaryKey) >= 0)
516 } else if (m_fetchedRecords.first().record.primaryKey.compare(targetPrimaryKey) <= 0)
526 const IDBKeyData& SQLiteIDBCursor::currentKey() const
528 ASSERT(!m_fetchedRecords.isEmpty());
529 return m_fetchedRecords.first().record.key;
532 const IDBKeyData& SQLiteIDBCursor::currentPrimaryKey() const
534 ASSERT(!m_fetchedRecords.isEmpty());
535 return m_fetchedRecords.first().record.primaryKey;
538 IDBValue* SQLiteIDBCursor::currentValue() const
540 ASSERT(!m_fetchedRecords.isEmpty());
541 return m_fetchedRecords.first().record.value.get();
544 bool SQLiteIDBCursor::didComplete() const
546 ASSERT(!m_fetchedRecords.isEmpty());
547 return m_fetchedRecords.first().completed;
550 bool SQLiteIDBCursor::didError() const
552 ASSERT(!m_fetchedRecords.isEmpty());
553 return m_fetchedRecords.first().errored;
556 int64_t SQLiteIDBCursor::currentRecordRowID() const
558 ASSERT(!m_fetchedRecords.isEmpty());
559 return m_fetchedRecords.first().rowID;
563 } // namespace IDBServer
564 } // namespace WebCore
566 #endif // ENABLE(INDEXED_DATABASE)