a9aa7d4bf5e6609ed526b65a562c2ec674ab7d8f
[WebKit-https.git] / Source / WebCore / Modules / indexeddb / server / SQLiteIDBCursor.cpp
1 /*
2  * Copyright (C) 2014, 2016 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 #include "config.h"
26 #include "SQLiteIDBCursor.h"
27
28 #if ENABLE(INDEXED_DATABASE)
29
30 #include "IDBCursorInfo.h"
31 #include "IDBGetResult.h"
32 #include "IDBSerialization.h"
33 #include "Logging.h"
34 #include "SQLiteIDBTransaction.h"
35 #include "SQLiteStatement.h"
36 #include "SQLiteTransaction.h"
37 #include <sqlite3.h>
38
39 namespace WebCore {
40 namespace IDBServer {
41
42 std::unique_ptr<SQLiteIDBCursor> SQLiteIDBCursor::maybeCreate(SQLiteIDBTransaction& transaction, const IDBCursorInfo& info)
43 {
44     auto cursor = std::make_unique<SQLiteIDBCursor>(transaction, info);
45
46     if (!cursor->establishStatement())
47         return nullptr;
48
49     if (!cursor->advance(1))
50         return nullptr;
51
52     return cursor;
53 }
54
55 std::unique_ptr<SQLiteIDBCursor> SQLiteIDBCursor::maybeCreateBackingStoreCursor(SQLiteIDBTransaction& transaction, const uint64_t objectStoreID, const uint64_t indexID, const IDBKeyRangeData& range)
56 {
57     auto cursor = std::make_unique<SQLiteIDBCursor>(transaction, objectStoreID, indexID, range);
58
59     if (!cursor->establishStatement())
60         return nullptr;
61
62     if (!cursor->advance(1))
63         return nullptr;
64
65     return cursor;
66 }
67
68 SQLiteIDBCursor::SQLiteIDBCursor(SQLiteIDBTransaction& transaction, const IDBCursorInfo& info)
69     : m_transaction(&transaction)
70     , m_cursorIdentifier(info.identifier())
71     , m_objectStoreID(info.objectStoreIdentifier())
72     , m_indexID(info.cursorSource() == IndexedDB::CursorSource::Index ? info.sourceIdentifier() : IDBIndexMetadata::InvalidId)
73     , m_cursorDirection(info.cursorDirection())
74     , m_keyRange(info.range())
75 {
76     ASSERT(m_objectStoreID);
77 }
78
79 SQLiteIDBCursor::SQLiteIDBCursor(SQLiteIDBTransaction& transaction, const uint64_t objectStoreID, const uint64_t indexID, const IDBKeyRangeData& range)
80     : m_transaction(&transaction)
81     , m_cursorIdentifier(transaction.transactionIdentifier())
82     , m_objectStoreID(objectStoreID)
83     , m_indexID(indexID ? indexID : IDBIndexMetadata::InvalidId)
84     , m_cursorDirection(IndexedDB::CursorDirection::Next)
85     , m_keyRange(range)
86     , m_backingStoreCursor(true)
87 {
88     ASSERT(m_objectStoreID);
89 }
90
91 SQLiteIDBCursor::~SQLiteIDBCursor()
92 {
93     if (m_backingStoreCursor)
94         m_transaction->closeCursor(*this);
95 }
96
97 void SQLiteIDBCursor::currentData(IDBGetResult& result)
98 {
99     if (m_completed) {
100         ASSERT(!m_errored);
101         result = { };
102         return;
103     }
104
105     result = { m_currentKey, m_currentPrimaryKey, ThreadSafeDataBuffer::copyVector(m_currentValueBuffer) };
106 }
107
108 static String buildIndexStatement(const IDBKeyRangeData& keyRange, IndexedDB::CursorDirection cursorDirection)
109 {
110     StringBuilder builder;
111
112     builder.appendLiteral("SELECT rowid, key, value FROM IndexRecords WHERE indexID = ? AND key ");
113     if (!keyRange.lowerKey.isNull() && !keyRange.lowerOpen)
114         builder.appendLiteral(">=");
115     else
116         builder.append('>');
117
118     builder.appendLiteral(" CAST(? AS TEXT) AND key ");
119     if (!keyRange.upperKey.isNull() && !keyRange.upperOpen)
120         builder.appendLiteral("<=");
121     else
122         builder.append('<');
123
124     builder.appendLiteral(" CAST(? AS TEXT) ORDER BY key");
125     if (cursorDirection == IndexedDB::CursorDirection::Prev || cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate)
126         builder.appendLiteral(" DESC");
127
128     builder.appendLiteral(", value");
129     if (cursorDirection == IndexedDB::CursorDirection::Prev)
130         builder.appendLiteral(" DESC");
131
132     builder.append(';');
133
134     return builder.toString();
135 }
136
137 static String buildObjectStoreStatement(const IDBKeyRangeData& keyRange, IndexedDB::CursorDirection cursorDirection)
138 {
139     StringBuilder builder;
140
141     builder.appendLiteral("SELECT rowid, key, value FROM Records WHERE objectStoreID = ? AND key ");
142
143     if (!keyRange.lowerKey.isNull() && !keyRange.lowerOpen)
144         builder.appendLiteral(">=");
145     else
146         builder.append('>');
147
148     builder.appendLiteral(" CAST(? AS TEXT) AND key ");
149
150     if (!keyRange.upperKey.isNull() && !keyRange.upperOpen)
151         builder.appendLiteral("<=");
152     else
153         builder.append('<');
154
155     builder.appendLiteral(" CAST(? AS TEXT) ORDER BY key");
156
157     if (cursorDirection == IndexedDB::CursorDirection::Prev || cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate)
158         builder.appendLiteral(" DESC");
159
160     builder.append(';');
161
162     return builder.toString();
163 }
164
165 bool SQLiteIDBCursor::establishStatement()
166 {
167     ASSERT(!m_statement);
168     String sql;
169
170     if (m_indexID != IDBIndexMetadata::InvalidId) {
171         sql = buildIndexStatement(m_keyRange, m_cursorDirection);
172         m_boundID = m_indexID;
173     } else {
174         sql = buildObjectStoreStatement(m_keyRange, m_cursorDirection);
175         m_boundID = m_objectStoreID;
176     }
177
178     m_currentLowerKey = m_keyRange.lowerKey.isNull() ? IDBKeyData::minimum() : m_keyRange.lowerKey;
179     m_currentUpperKey = m_keyRange.upperKey.isNull() ? IDBKeyData::maximum() : m_keyRange.upperKey;
180
181     return createSQLiteStatement(sql);
182 }
183
184 bool SQLiteIDBCursor::createSQLiteStatement(const String& sql)
185 {
186     LOG(IndexedDB, "Creating cursor with SQL query: \"%s\"", sql.utf8().data());
187
188     ASSERT(!m_currentLowerKey.isNull());
189     ASSERT(!m_currentUpperKey.isNull());
190     ASSERT(m_transaction->sqliteTransaction());
191
192     m_statement = std::make_unique<SQLiteStatement>(m_transaction->sqliteTransaction()->database(), sql);
193
194     if (m_statement->prepare() != SQLITE_OK) {
195         LOG_ERROR("Could not create cursor statement (prepare/id) - '%s'", m_transaction->sqliteTransaction()->database().lastErrorMsg());
196         return false;
197     }
198
199     return bindArguments();
200 }
201
202 void SQLiteIDBCursor::objectStoreRecordsChanged()
203 {
204     // If ObjectStore or Index contents changed, we need to reset the statement and bind new parameters to it.
205     // This is to pick up any changes that might exist.
206
207     m_statementNeedsReset = true;
208 }
209
210 void SQLiteIDBCursor::resetAndRebindStatement()
211 {
212     ASSERT(!m_currentLowerKey.isNull());
213     ASSERT(!m_currentUpperKey.isNull());
214     ASSERT(m_transaction->sqliteTransaction());
215     ASSERT(m_statement);
216     ASSERT(m_statementNeedsReset);
217
218     m_statementNeedsReset = false;
219
220     // If this cursor never fetched any records, we don't need to reset the statement.
221     if (m_currentKey.isNull())
222         return;
223
224     // Otherwise update the lower key or upper key used for the cursor range.
225     // This is so the cursor can pick up where we left off.
226     // We might also have to change the statement from closed to open so we don't refetch the current key a second time.
227     if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) {
228         m_currentLowerKey = m_currentKey;
229         if (!m_keyRange.lowerOpen) {
230             m_keyRange.lowerOpen = true;
231             m_keyRange.lowerKey = m_currentLowerKey;
232             m_statement = nullptr;
233             m_currentRecordID = -1;
234         }
235     } else {
236         m_currentUpperKey = m_currentKey;
237         if (!m_keyRange.upperOpen) {
238             m_keyRange.upperOpen = true;
239             m_keyRange.upperKey = m_currentUpperKey;
240             m_statement = nullptr;
241             m_currentRecordID = -1;
242         }
243     }
244
245     if (!m_statement && !establishStatement()) {
246         LOG_ERROR("Unable to establish new statement for cursor iteration");
247         return;
248     }
249
250     if (m_statement->reset() != SQLITE_OK) {
251         LOG_ERROR("Could not reset cursor statement to respond to object store changes");
252         return;
253     }
254
255     bindArguments();
256 }
257
258 bool SQLiteIDBCursor::bindArguments()
259 {
260     LOG(IndexedDB, "Cursor is binding lower key '%s' and upper key '%s'", m_currentLowerKey.loggingString().utf8().data(), m_currentUpperKey.loggingString().utf8().data());
261
262     if (m_statement->bindInt64(1, m_boundID) != SQLITE_OK) {
263         LOG_ERROR("Could not bind id argument (bound ID)");
264         return false;
265     }
266
267     RefPtr<SharedBuffer> buffer = serializeIDBKeyData(m_currentLowerKey);
268     if (m_statement->bindBlob(2, buffer->data(), buffer->size()) != SQLITE_OK) {
269         LOG_ERROR("Could not create cursor statement (lower key)");
270         return false;
271     }
272
273     buffer = serializeIDBKeyData(m_currentUpperKey);
274     if (m_statement->bindBlob(3, buffer->data(), buffer->size()) != SQLITE_OK) {
275         LOG_ERROR("Could not create cursor statement (upper key)");
276         return false;
277     }
278
279     return true;
280 }
281
282 bool SQLiteIDBCursor::advance(uint64_t count)
283 {
284     bool isUnique = m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate || m_cursorDirection == IndexedDB::CursorDirection::PrevNoDuplicate;
285
286     if (m_completed) {
287         LOG_ERROR("Attempt to advance a completed cursor");
288         return false;
289     }
290
291     for (uint64_t i = 0; i < count; ++i) {
292         if (!isUnique) {
293             if (!advanceOnce())
294                 return false;
295         } else {
296             if (!advanceUnique())
297                 return false;
298         }
299
300         if (m_completed)
301             break;
302     }
303
304     return true;
305 }
306
307 bool SQLiteIDBCursor::advanceUnique()
308 {
309     IDBKeyData currentKey = m_currentKey;
310
311     while (!m_completed) {
312         if (!advanceOnce())
313             return false;
314
315         // If the new current key is different from the old current key, we're done.
316         if (currentKey.compare(m_currentKey))
317             return true;
318     }
319
320     return false;
321 }
322
323 bool SQLiteIDBCursor::advanceOnce()
324 {
325     if (m_statementNeedsReset)
326         resetAndRebindStatement();
327
328     AdvanceResult result;
329     do {
330         result = internalAdvanceOnce();
331     } while (result == AdvanceResult::ShouldAdvanceAgain);
332
333     return result == AdvanceResult::Success;
334 }
335
336 SQLiteIDBCursor::AdvanceResult SQLiteIDBCursor::internalAdvanceOnce()
337 {
338     ASSERT(m_transaction->sqliteTransaction());
339     ASSERT(m_statement);
340     ASSERT(!m_completed);
341
342     int result = m_statement->step();
343     if (result == SQLITE_DONE) {
344         m_completed = true;
345
346         // When a cursor reaches its end, that is indicated by having undefined keys/values
347         m_currentKey = IDBKeyData();
348         m_currentPrimaryKey = IDBKeyData();
349         m_currentValueBuffer.clear();
350
351         return AdvanceResult::Success;
352     }
353
354     if (result != SQLITE_ROW) {
355         LOG_ERROR("Error advancing cursor - (%i) %s", result, m_transaction->sqliteTransaction()->database().lastErrorMsg());
356         m_completed = true;
357         m_errored = true;
358         return AdvanceResult::Failure;
359     }
360
361     int64_t recordID = m_statement->getColumnInt64(0);
362
363     // If the recordID of the record just fetched is the same as the current record ID
364     // then this statement must have been re-prepared in response to an object store change.
365     // We don't want to re-use the current record so we'll move on to the next one.
366     if (recordID == m_currentRecordID)
367         return AdvanceResult::ShouldAdvanceAgain;
368
369     m_currentRecordID = recordID;
370
371     Vector<uint8_t> keyData;
372     m_statement->getColumnBlobAsVector(1, keyData);
373
374     if (!deserializeIDBKeyData(keyData.data(), keyData.size(), m_currentKey)) {
375         LOG_ERROR("Unable to deserialize key data from database while advancing cursor");
376         m_completed = true;
377         m_errored = true;
378         return AdvanceResult::Failure;
379     }
380
381     m_statement->getColumnBlobAsVector(2, keyData);
382     m_currentValueBuffer = keyData;
383
384     // The primaryKey of an ObjectStore cursor is the same as its key.
385     if (m_indexID == IDBIndexMetadata::InvalidId)
386         m_currentPrimaryKey = m_currentKey;
387     else {
388         if (!deserializeIDBKeyData(keyData.data(), keyData.size(), m_currentPrimaryKey)) {
389             LOG_ERROR("Unable to deserialize value data from database while advancing index cursor");
390             m_completed = true;
391             m_errored = true;
392             return AdvanceResult::Failure;
393         }
394
395         SQLiteStatement objectStoreStatement(m_statement->database(), "SELECT value FROM Records WHERE key = CAST(? AS TEXT) and objectStoreID = ?;");
396
397         if (objectStoreStatement.prepare() != SQLITE_OK
398             || objectStoreStatement.bindBlob(1, m_currentValueBuffer.data(), m_currentValueBuffer.size()) != SQLITE_OK
399             || objectStoreStatement.bindInt64(2, m_objectStoreID) != SQLITE_OK) {
400             LOG_ERROR("Could not create index cursor statement into object store records (%i) '%s'", m_statement->database().lastError(), m_statement->database().lastErrorMsg());
401             m_completed = true;
402             m_errored = true;
403             return AdvanceResult::Failure;
404         }
405
406         int result = objectStoreStatement.step();
407
408         if (result == SQLITE_ROW)
409             objectStoreStatement.getColumnBlobAsVector(0, m_currentValueBuffer);
410         else if (result == SQLITE_DONE) {
411             // This indicates that the record we're trying to retrieve has been removed from the object store.
412             // Skip over it.
413             return AdvanceResult::ShouldAdvanceAgain;
414         } else {
415             LOG_ERROR("Could not step index cursor statement into object store records (%i) '%s'", m_statement->database().lastError(), m_statement->database().lastErrorMsg());
416             m_completed = true;
417             m_errored = true;
418             return AdvanceResult::Failure;
419
420         }
421     }
422
423     return AdvanceResult::Success;
424 }
425
426 bool SQLiteIDBCursor::iterate(const WebCore::IDBKeyData& targetKey)
427 {
428     ASSERT(m_transaction->sqliteTransaction());
429     ASSERT(m_statement);
430
431     bool result = advance(1);
432
433     // Iterating with no key is equivalent to advancing 1 step.
434     if (targetKey.isNull() || !result)
435         return result;
436
437     while (!m_completed) {
438         if (!result)
439             return false;
440
441         // 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.
442         if (m_cursorDirection == IndexedDB::CursorDirection::Next || m_cursorDirection == IndexedDB::CursorDirection::NextNoDuplicate) {
443             if (m_currentKey.compare(targetKey) >= 0)
444                 break;
445         } else if (m_currentKey.compare(targetKey) <= 0)
446             break;
447
448         result = advance(1);
449     }
450
451     return result;
452 }
453
454 } // namespace IDBServer
455 } // namespace WebCore
456
457 #endif // ENABLE(INDEXED_DATABASE)