5486b8451f99ebef60fe2a9c7dd6778628c1b907
[WebKit-https.git] / Source / WebKit2 / DatabaseProcess / IndexedDB / sqlite / UniqueIDBDatabaseBackingStoreSQLite.cpp
1 /*
2  * Copyright (C) 2013 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 "UniqueIDBDatabaseBackingStoreSQLite.h"
28
29 #if ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS)
30
31 #include "ArgumentDecoder.h"
32 #include "IDBSerialization.h"
33 #include "SQLiteIDBTransaction.h"
34 #include <WebCore/FileSystem.h>
35 #include <WebCore/IDBDatabaseMetadata.h>
36 #include <WebCore/IDBKeyData.h>
37 #include <WebCore/IDBKeyRange.h>
38 #include <WebCore/SQLiteDatabase.h>
39 #include <WebCore/SQLiteStatement.h>
40 #include <WebCore/SharedBuffer.h>
41 #include <wtf/MainThread.h>
42
43 using namespace WebCore;
44
45 namespace WebKit {
46
47 // Current version of the metadata schema being used in the metadata database.
48 static const int currentMetadataVersion = 1;
49
50 static int64_t generateDatabaseId()
51 {
52     static int64_t databaseID = 0;
53
54     ASSERT(!isMainThread());
55     return ++databaseID;
56 }
57
58 UniqueIDBDatabaseBackingStoreSQLite::UniqueIDBDatabaseBackingStoreSQLite(const UniqueIDBDatabaseIdentifier& identifier, const String& databaseDirectory)
59     : m_identifier(identifier)
60     , m_absoluteDatabaseDirectory(databaseDirectory)
61 {
62     // The backing store is meant to be created and used entirely on a background thread.
63     ASSERT(!isMainThread());
64 }
65
66 UniqueIDBDatabaseBackingStoreSQLite::~UniqueIDBDatabaseBackingStoreSQLite()
67 {
68     ASSERT(!isMainThread());
69 }
70
71 std::unique_ptr<WebCore::IDBDatabaseMetadata> UniqueIDBDatabaseBackingStoreSQLite::createAndPopulateInitialMetadata()
72 {
73     ASSERT(!isMainThread());
74     ASSERT(m_sqliteDB);
75     ASSERT(m_sqliteDB->isOpen());
76
77     if (!m_sqliteDB->executeCommand("CREATE TABLE IDBDatabaseInfo (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, value TEXT NOT NULL ON CONFLICT FAIL);")) {
78         LOG_ERROR("Could not create IDBDatabaseInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
79         m_sqliteDB = nullptr;
80         return nullptr;
81     }
82
83     if (!m_sqliteDB->executeCommand("CREATE TABLE ObjectStoreInfo (id INTEGER PRIMARY KEY NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT FAIL, name TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT FAIL, keyPath BLOB NOT NULL ON CONFLICT FAIL, autoInc INTEGER NOT NULL ON CONFLICT FAIL, maxIndexID INTEGER NOT NULL ON CONFLICT FAIL);")) {
84         LOG_ERROR("Could not create ObjectStoreInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
85         m_sqliteDB = nullptr;
86         return nullptr;
87     }
88
89     if (!m_sqliteDB->executeCommand("CREATE TABLE IndexInfo (id INTEGER PRIMARY KEY NOT NULL ON CONFLICT FAIL, name TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT FAIL, objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, keyPath BLOB NOT NULL ON CONFLICT FAIL, isUnique INTEGER NOT NULL ON CONFLICT FAIL, multiEntry INTEGER NOT NULL ON CONFLICT FAIL);")) {
90         LOG_ERROR("Could not create IndexInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
91         m_sqliteDB = nullptr;
92         return nullptr;
93     }
94
95     if (!m_sqliteDB->executeCommand("CREATE TABLE Records (objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, key BLOB COLLATE IDBKEY NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, value BLOB NOT NULL ON CONFLICT FAIL);")) {
96         LOG_ERROR("Could not create Records table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
97         m_sqliteDB = nullptr;
98         return nullptr;
99     }
100
101     {
102         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('MetadataVersion', ?);"));
103         if (sql.prepare() != SQLResultOk
104             || sql.bindInt(1, currentMetadataVersion) != SQLResultOk
105             || sql.step() != SQLResultDone) {
106             LOG_ERROR("Could not insert database metadata version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
107             m_sqliteDB = nullptr;
108             return nullptr;
109         }
110     }
111     {
112         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('DatabaseName', ?);"));
113         if (sql.prepare() != SQLResultOk
114             || sql.bindText(1, m_identifier.databaseName()) != SQLResultOk
115             || sql.step() != SQLResultDone) {
116             LOG_ERROR("Could not insert database name into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
117             m_sqliteDB = nullptr;
118             return nullptr;
119         }
120     }
121     {
122         // Database versions are defined to be a uin64_t in the spec but sqlite3 doesn't support native binding of unsigned integers.
123         // Therefore we'll store the version as a String.
124         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('DatabaseVersion', ?);"));
125         if (sql.prepare() != SQLResultOk
126             || sql.bindText(1, String::number(0)) != SQLResultOk
127             || sql.step() != SQLResultDone) {
128             LOG_ERROR("Could not insert default version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
129             m_sqliteDB = nullptr;
130             return nullptr;
131         }
132     }
133
134     if (!m_sqliteDB->executeCommand(ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('MaxObjectStoreID', 1);"))) {
135         LOG_ERROR("Could not insert default version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
136         m_sqliteDB = nullptr;
137         return nullptr;
138     }
139
140     // This initial metadata matches the default values we just put into the metadata database.
141     auto metadata = std::make_unique<IDBDatabaseMetadata>();
142     metadata->name = m_identifier.databaseName();
143     metadata->version = 0;
144     metadata->maxObjectStoreId = 1;
145
146     return metadata;
147 }
148
149 std::unique_ptr<IDBDatabaseMetadata> UniqueIDBDatabaseBackingStoreSQLite::extractExistingMetadata()
150 {
151     ASSERT(!isMainThread());
152     ASSERT(m_sqliteDB);
153
154     if (!m_sqliteDB->tableExists(ASCIILiteral("IDBDatabaseInfo")))
155         return nullptr;
156
157     auto metadata = std::make_unique<IDBDatabaseMetadata>();
158     {
159         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT value FROM IDBDatabaseInfo WHERE key = 'MetadataVersion';"));
160         if (sql.isColumnNull(0))
161             return nullptr;
162         metadata->version = sql.getColumnInt(0);
163     }
164     {
165         SQLiteStatement sql(*m_sqliteDB, "SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseName';");
166         if (sql.isColumnNull(0))
167             return nullptr;
168         metadata->name = sql.getColumnText(0);
169         if (metadata->name != m_identifier.databaseName()) {
170             LOG_ERROR("Database name in the metadata database ('%s') does not match the expected name ('%s')", metadata->name.utf8().data(), m_identifier.databaseName().utf8().data());
171             return nullptr;
172         }
173     }
174     {
175         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseVersion';"));
176         if (sql.isColumnNull(0))
177             return nullptr;
178         String stringVersion = sql.getColumnText(0);
179         bool ok;
180         metadata->version = stringVersion.toUInt64Strict(&ok);
181         if (!ok) {
182             LOG_ERROR("Database version on disk ('%s') does not cleanly convert to an unsigned 64-bit integer version", stringVersion.utf8().data());
183             return nullptr;
184         }
185     }
186
187     {
188         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT id, name, keyPath, autoInc, maxIndexID FROM ObjectStoreInfo;"));
189         if (sql.prepare() != SQLResultOk)
190             return nullptr;
191
192         int result = sql.step();
193         while (result == SQLResultRow) {
194             IDBObjectStoreMetadata metadata;
195             metadata.id = sql.getColumnInt64(0);
196             metadata.name = sql.getColumnText(1);
197
198             int keyPathSize;
199             const uint8_t* keyPathBuffer = static_cast<const uint8_t*>(sql.getColumnBlob(2, keyPathSize));
200
201             std::unique_ptr<IDBKeyPath> keyPath = deserializeIDBKeyPath(keyPathBuffer, keyPathSize);
202
203             if (!keyPath) {
204                 LOG_ERROR("Unable to extract key path metadata from database");
205                 return nullptr;
206             }
207
208             metadata.keyPath = *keyPath;
209             metadata.autoIncrement = sql.getColumnInt(3);
210             metadata.maxIndexId = sql.getColumnInt64(4);
211
212             result = sql.step();
213         }
214
215         if (result != SQLResultDone) {
216             LOG_ERROR("Error fetching object store metadata from database on disk");
217             return nullptr;
218         }
219     }
220
221     // FIXME: Once we save indexes we need to extract their metadata, also.
222
223     return metadata;
224 }
225
226 std::unique_ptr<SQLiteDatabase> UniqueIDBDatabaseBackingStoreSQLite::openSQLiteDatabaseAtPath(const String& path)
227 {
228     ASSERT(!isMainThread());
229
230     auto sqliteDatabase = std::make_unique<SQLiteDatabase>();
231     if (!sqliteDatabase->open(path)) {
232         LOG_ERROR("Failed to open SQLite database at path '%s'", path.utf8().data());
233         return nullptr;
234     }
235
236     // Since a WorkQueue isn't bound to a specific thread, we have to disable threading checks
237     // even though we never access the database from different threads simultaneously.
238     sqliteDatabase->disableThreadingChecks();
239
240     return sqliteDatabase;
241 }
242
243 std::unique_ptr<IDBDatabaseMetadata> UniqueIDBDatabaseBackingStoreSQLite::getOrEstablishMetadata()
244 {
245     ASSERT(!isMainThread());
246
247     String dbFilename = pathByAppendingComponent(m_absoluteDatabaseDirectory, "IndexedDB.sqlite3");
248     m_sqliteDB = openSQLiteDatabaseAtPath(dbFilename);
249     if (!m_sqliteDB)
250         return nullptr;
251
252     RefPtr<UniqueIDBDatabaseBackingStoreSQLite> protector(this);
253     m_sqliteDB->setCollationFunction("IDBKEY", [this](int aLength, const void* a, int bLength, const void* b) {
254         return collate(aLength, a, bLength, b);
255     });
256
257     std::unique_ptr<IDBDatabaseMetadata> metadata = extractExistingMetadata();
258     if (!metadata)
259         metadata = createAndPopulateInitialMetadata();
260
261     if (!metadata)
262         LOG_ERROR("Unable to establish IDB database at path '%s'", dbFilename.utf8().data());
263
264     // The database id is a runtime concept and doesn't need to be stored in the metadata database.
265     metadata->id = generateDatabaseId();
266
267     return metadata;
268 }
269
270 bool UniqueIDBDatabaseBackingStoreSQLite::establishTransaction(const IDBTransactionIdentifier& identifier, const Vector<int64_t>&, WebCore::IndexedDB::TransactionMode mode)
271 {
272     ASSERT(!isMainThread());
273
274     if (!m_transactions.add(identifier, SQLiteIDBTransaction::create(identifier, mode)).isNewEntry) {
275         LOG_ERROR("Attempt to establish transaction identifier that already exists");
276         return false;
277     }
278
279     return true;
280 }
281
282 bool UniqueIDBDatabaseBackingStoreSQLite::beginTransaction(const IDBTransactionIdentifier& identifier)
283 {
284     ASSERT(!isMainThread());
285
286     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
287     if (!transaction) {
288         LOG_ERROR("Attempt to begin a transaction that hasn't been established");
289         return false;
290     }
291
292     return transaction->begin(*m_sqliteDB);
293 }
294
295 bool UniqueIDBDatabaseBackingStoreSQLite::commitTransaction(const IDBTransactionIdentifier& identifier)
296 {
297     ASSERT(!isMainThread());
298
299     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
300     if (!transaction) {
301         LOG_ERROR("Attempt to commit a transaction that hasn't been established");
302         return false;
303     }
304
305     return transaction->commit();
306 }
307
308 bool UniqueIDBDatabaseBackingStoreSQLite::resetTransaction(const IDBTransactionIdentifier& identifier)
309 {
310     ASSERT(!isMainThread());
311
312     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
313     if (!transaction) {
314         LOG_ERROR("Attempt to reset a transaction that hasn't been established");
315         return false;
316     }
317
318     return transaction->reset();
319 }
320
321 bool UniqueIDBDatabaseBackingStoreSQLite::rollbackTransaction(const IDBTransactionIdentifier& identifier)
322 {
323     ASSERT(!isMainThread());
324
325     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
326     if (!transaction) {
327         LOG_ERROR("Attempt to rollback a transaction that hasn't been established");
328         return false;
329     }
330
331     return transaction->rollback();
332 }
333
334 bool UniqueIDBDatabaseBackingStoreSQLite::changeDatabaseVersion(const IDBTransactionIdentifier& identifier, uint64_t newVersion)
335 {
336     ASSERT(!isMainThread());
337     ASSERT(m_sqliteDB);
338     ASSERT(m_sqliteDB->isOpen());
339
340     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
341     if (!transaction || !transaction->inProgress()) {
342         LOG_ERROR("Attempt to change database version with an established, in-progress transaction");
343         return false;
344     }
345     if (transaction->mode() != IndexedDB::TransactionMode::VersionChange) {
346         LOG_ERROR("Attempt to change database version during a non version-change transaction");
347         return false;
348     }
349
350     {
351         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("UPDATE IDBDatabaseInfo SET value = ? where key = 'DatabaseVersion';"));
352         if (sql.prepare() != SQLResultOk
353             || sql.bindText(1, String::number(newVersion)) != SQLResultOk
354             || sql.step() != SQLResultDone) {
355             LOG_ERROR("Could not update database version in IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
356             return false;
357         }
358     }
359
360     return true;
361 }
362
363 bool UniqueIDBDatabaseBackingStoreSQLite::createObjectStore(const IDBTransactionIdentifier& identifier, const IDBObjectStoreMetadata& metadata)
364 {
365     ASSERT(!isMainThread());
366     ASSERT(m_sqliteDB);
367     ASSERT(m_sqliteDB->isOpen());
368
369     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
370     if (!transaction || !transaction->inProgress()) {
371         LOG_ERROR("Attempt to change database version with an established, in-progress transaction");
372         return false;
373     }
374     if (transaction->mode() != IndexedDB::TransactionMode::VersionChange) {
375         LOG_ERROR("Attempt to change database version during a non version-change transaction");
376         return false;
377     }
378
379     RefPtr<SharedBuffer> keyPathBlob = serializeIDBKeyPath(metadata.keyPath);
380     if (!keyPathBlob) {
381         LOG_ERROR("Unable to serialize IDBKeyPath to save in database");
382         return false;
383     }
384
385     SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO ObjectStoreInfo VALUES (?, ?, ?, ?, ?);"));
386     if (sql.prepare() != SQLResultOk
387         || sql.bindInt64(1, metadata.id) != SQLResultOk
388         || sql.bindText(2, metadata.name) != SQLResultOk
389         || sql.bindBlob(3, keyPathBlob->data(), keyPathBlob->size()) != SQLResultOk
390         || sql.bindInt(4, metadata.autoIncrement) != SQLResultOk
391         || sql.bindInt64(5, metadata.maxIndexId) != SQLResultOk
392         || sql.step() != SQLResultDone) {
393         LOG_ERROR("Could not add object store '%s' to ObjectStoreInfo table (%i) - %s", metadata.name.utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
394         return false;
395     }
396
397     return true;
398 }
399
400 bool UniqueIDBDatabaseBackingStoreSQLite::deleteObjectStore(const IDBTransactionIdentifier& identifier, int64_t objectStoreID)
401 {
402     ASSERT(!isMainThread());
403     ASSERT(m_sqliteDB);
404     ASSERT(m_sqliteDB->isOpen());
405
406     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
407     if (!transaction || !transaction->inProgress()) {
408         LOG_ERROR("Attempt to change database version with an established, in-progress transaction");
409         return false;
410     }
411     if (transaction->mode() != IndexedDB::TransactionMode::VersionChange) {
412         LOG_ERROR("Attempt to change database version during a non version-change transaction");
413         return false;
414     }
415
416     {
417         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM ObjectStoreInfo WHERE id = ?;"));
418         if (sql.prepare() != SQLResultOk
419             || sql.bindInt64(1, objectStoreID) != SQLResultOk
420             || sql.step() != SQLResultDone) {
421             LOG_ERROR("Could not delete object store id %lli from ObjectStoreInfo table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
422             return false;
423         }
424     }
425     {
426         // FIXME: Execute SQL here to drop all records and indexes related to this object store.
427     }
428
429     return true;
430 }
431
432 bool UniqueIDBDatabaseBackingStoreSQLite::clearObjectStore(const IDBTransactionIdentifier& identifier, int64_t objectStoreID)
433 {
434     ASSERT(!isMainThread());
435     ASSERT(m_sqliteDB);
436     ASSERT(m_sqliteDB->isOpen());
437
438     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
439     if (!transaction || !transaction->inProgress()) {
440         LOG_ERROR("Attempt to change database version with an establish, in-progress transaction");
441         return false;
442     }
443     if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) {
444         LOG_ERROR("Attempt to change database version during a read-only transaction");
445         return false;
446     }
447
448     {
449         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM Records WHERE objectStoreID = ?;"));
450         if (sql.prepare() != SQLResultOk
451             || sql.bindInt64(1, objectStoreID) != SQLResultOk
452             || sql.step() != SQLResultDone) {
453             LOG_ERROR("Could not delete records from object store id %lli (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
454             return false;
455         }
456     }
457
458     // FIXME <rdar://problem/15779642>: Once indexes are implemented, drop index records.
459     return true;
460 }
461
462 PassRefPtr<IDBKey> UniqueIDBDatabaseBackingStoreSQLite::generateKey(const IDBTransactionIdentifier&, int64_t objectStoreID)
463 {
464     // FIXME (<rdar://problem/15877909>): Implement
465     return nullptr;
466 }
467
468 bool UniqueIDBDatabaseBackingStoreSQLite::keyExistsInObjectStore(const IDBTransactionIdentifier&, int64_t objectStoreID, const IDBKey&, bool& keyExists)
469 {
470     // FIXME: When Get support is implemented, we need to implement this also (<rdar://problem/15779644>)
471     return false;
472 }
473
474 bool UniqueIDBDatabaseBackingStoreSQLite::putRecord(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, const IDBKey& key, const uint8_t* valueBuffer, size_t valueSize)
475 {
476     ASSERT(!isMainThread());
477     ASSERT(m_sqliteDB);
478     ASSERT(m_sqliteDB->isOpen());
479
480     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
481     if (!transaction || !transaction->inProgress()) {
482         LOG_ERROR("Attempt to put a record into database without an established, in-progress transaction");
483         return false;
484     }
485     if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) {
486         LOG_ERROR("Attempt to put a record into database during read-only transaction");
487         return false;
488     }
489
490     RefPtr<SharedBuffer> keyBuffer = serializeIDBKey(key);
491     if (!keyBuffer) {
492         LOG_ERROR("Unable to serialize IDBKey to be stored in the database");
493         return false;
494     }
495     {
496         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO Records VALUES (?, ?, ?);"));
497         if (sql.prepare() != SQLResultOk
498             || sql.bindInt64(1, objectStoreID) != SQLResultOk
499             || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLResultOk
500             || sql.bindBlob(3, valueBuffer, valueSize) != SQLResultOk
501             || sql.step() != SQLResultDone) {
502             LOG_ERROR("Could not put record for object store %lli in Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
503             return false;
504         }
505     }
506
507     return true;
508 }
509
510 bool UniqueIDBDatabaseBackingStoreSQLite::updateKeyGenerator(const IDBTransactionIdentifier&, int64_t objectStoreId, const IDBKey&, bool checkCurrent)
511 {
512     // FIXME (<rdar://problem/15877909>): Implement
513     return false;
514 }
515
516 bool UniqueIDBDatabaseBackingStoreSQLite::getKeyRecordFromObjectStore(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, const WebCore::IDBKey& key, RefPtr<WebCore::SharedBuffer>& result)
517 {
518     ASSERT(!isMainThread());
519     ASSERT(m_sqliteDB);
520     ASSERT(m_sqliteDB->isOpen());
521
522     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
523     if (!transaction || !transaction->inProgress()) {
524         LOG_ERROR("Attempt to put a record into database without an established, in-progress transaction");
525         return false;
526     }
527
528     RefPtr<SharedBuffer> keyBuffer = serializeIDBKey(key);
529     if (!keyBuffer) {
530         LOG_ERROR("Unable to serialize IDBKey to be stored in the database");
531         return false;
532     }
533
534     {
535         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT value FROM Records WHERE objectStoreID = ? AND key = ?;"));
536         if (sql.prepare() != SQLResultOk
537             || sql.bindInt64(1, objectStoreID) != SQLResultOk
538             || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLResultOk) {
539             LOG_ERROR("Could not get record from object store %lli from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
540             return false;
541         }
542
543         int sqlResult = sql.step();
544         if (sqlResult == SQLResultOk || sqlResult == SQLResultDone) {
545             // There was no record for the key in the database.
546             return true;
547         }
548         if (sqlResult != SQLResultRow) {
549             // There was an error fetching the record from the database.
550             LOG_ERROR("Could not get record from object store %lli from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
551             return false;
552         }
553
554         Vector<char> buffer;
555         sql.getColumnBlobAsVector(0, buffer);
556         result = SharedBuffer::create(static_cast<const char*>(buffer.data()), buffer.size());
557     }
558
559     return true;
560 }
561
562 bool UniqueIDBDatabaseBackingStoreSQLite::getKeyRangeRecordFromObjectStore(const IDBTransactionIdentifier& identifier, int64_t objectStoreID, const WebCore::IDBKeyRange& keyRange, RefPtr<WebCore::SharedBuffer>& result, RefPtr<WebCore::IDBKey>& resultKey)
563 {
564     ASSERT(!isMainThread());
565     ASSERT(m_sqliteDB);
566     ASSERT(m_sqliteDB->isOpen());
567
568     SQLiteIDBTransaction* transaction = m_transactions.get(identifier);
569     if (!transaction || !transaction->inProgress()) {
570         LOG_ERROR("Attempt to put a record into database without an established, in-progress transaction");
571         return false;
572     }
573
574     RefPtr<SharedBuffer> lowerBuffer = serializeIDBKey(*keyRange.lower());
575     if (!lowerBuffer) {
576         LOG_ERROR("Unable to serialize IDBKey to be stored in the database");
577         return false;
578     }
579
580     RefPtr<SharedBuffer> upperBuffer = serializeIDBKey(*keyRange.upper());
581     if (!upperBuffer) {
582         LOG_ERROR("Unable to serialize IDBKey to be stored in the database");
583         return false;
584     }
585
586     {
587         SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT value FROM Records WHERE objectStoreID = ? AND key >= ? AND key <= ? ORDER BY key;"));
588         if (sql.prepare() != SQLResultOk
589             || sql.bindInt64(1, objectStoreID) != SQLResultOk
590             || sql.bindBlob(2, lowerBuffer->data(), lowerBuffer->size()) != SQLResultOk
591             || sql.bindBlob(3, upperBuffer->data(), upperBuffer->size()) != SQLResultOk) {
592             LOG_ERROR("Could not get key range record from object store %lli from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
593             return false;
594         }
595
596         int sqlResult = sql.step();
597
598         if (sqlResult == SQLResultOk || sqlResult == SQLResultDone) {
599             // There was no record for the key in the database.
600             return true;
601         }
602         if (sqlResult != SQLResultRow) {
603             // There was an error fetching the record from the database.
604             LOG_ERROR("Could not get record from object store %lli from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg());
605             return false;
606         }
607
608         Vector<char> buffer;
609         sql.getColumnBlobAsVector(0, buffer);
610         result = SharedBuffer::create(static_cast<const char*>(buffer.data()), buffer.size());
611     }
612
613     return true;
614 }
615
616 int UniqueIDBDatabaseBackingStoreSQLite::collate(int aLength, const void* a, int bLength, const void* b)
617 {
618     // FIXME: Implement
619     return 0;
620 }
621
622 } // namespace WebKit
623
624 #endif // ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS)