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 "Logging.h" 34#include "SQLiteIDBCursor.h" 35#include "SQLiteIDBTransaction.h" 36#include <WebCore/FileSystem.h> 37#include <WebCore/IDBBindingUtilities.h> 38#include <WebCore/IDBDatabaseMetadata.h> 39#include <WebCore/IDBGetResult.h> 40#include <WebCore/IDBKeyData.h> 41#include <WebCore/IDBKeyRange.h> 42#include <WebCore/SQLiteDatabase.h> 43#include <WebCore/SQLiteStatement.h> 44#include <WebCore/SharedBuffer.h> 45#include <wtf/RunLoop.h> 46 47using namespace JSC; 48using namespace WebCore; 49 50namespace WebKit { 51 52// Current version of the metadata schema being used in the metadata database. 53static const int currentMetadataVersion = 1; 54 55static int64_t generateDatabaseId() 56{ 57 static int64_t databaseID = 0; 58 59 ASSERT(!RunLoop::isMain()); 60 return ++databaseID; 61} 62 63UniqueIDBDatabaseBackingStoreSQLite::UniqueIDBDatabaseBackingStoreSQLite(const UniqueIDBDatabaseIdentifier& identifier, const String& databaseDirectory) 64 : m_identifier(identifier) 65 , m_absoluteDatabaseDirectory(databaseDirectory) 66{ 67 // The backing store is meant to be created and used entirely on a background thread. 68 ASSERT(!RunLoop::isMain()); 69} 70 71UniqueIDBDatabaseBackingStoreSQLite::~UniqueIDBDatabaseBackingStoreSQLite() 72{ 73 ASSERT(!RunLoop::isMain()); 74 75 m_transactions.clear(); 76 m_sqliteDB = nullptr; 77 78 if (m_vm) { 79 JSLockHolder locker(m_vm.get()); 80 m_globalObject.clear(); 81 m_vm = nullptr; 82 } 83} 84 85std::unique_ptr<IDBDatabaseMetadata> UniqueIDBDatabaseBackingStoreSQLite::createAndPopulateInitialMetadata() 86{ 87 ASSERT(!RunLoop::isMain()); 88 ASSERT(m_sqliteDB); 89 ASSERT(m_sqliteDB->isOpen()); 90 91 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);")) { 92 LOG_ERROR("Could not create IDBDatabaseInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 93 m_sqliteDB = nullptr; 94 return nullptr; 95 } 96 97 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);")) { 98 LOG_ERROR("Could not create ObjectStoreInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 99 m_sqliteDB = nullptr; 100 return nullptr; 101 } 102 103 if (!m_sqliteDB->executeCommand("CREATE TABLE IndexInfo (id INTEGER NOT NULL ON CONFLICT FAIL, name TEXT NOT NULL 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);")) { 104 LOG_ERROR("Could not create IndexInfo table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 105 m_sqliteDB = nullptr; 106 return nullptr; 107 } 108 109 if (!m_sqliteDB->executeCommand("CREATE TABLE Records (objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, key TEXT COLLATE IDBKEY NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, value NOT NULL ON CONFLICT FAIL);")) { 110 LOG_ERROR("Could not create Records table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 111 m_sqliteDB = nullptr; 112 return nullptr; 113 } 114 115 if (!m_sqliteDB->executeCommand("CREATE TABLE IndexRecords (indexID INTEGER NOT NULL ON CONFLICT FAIL, objectStoreID INTEGER NOT NULL ON CONFLICT FAIL, key TEXT COLLATE IDBKEY NOT NULL ON CONFLICT FAIL, value NOT NULL ON CONFLICT FAIL);")) { 116 LOG_ERROR("Could not create IndexRecords table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 117 m_sqliteDB = nullptr; 118 return nullptr; 119 } 120 121 if (!m_sqliteDB->executeCommand("CREATE TABLE KeyGenerators (objectStoreID INTEGER NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE, currentKey INTEGER NOT NULL ON CONFLICT FAIL);")) { 122 LOG_ERROR("Could not create KeyGenerators table in database (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 123 m_sqliteDB = nullptr; 124 return nullptr; 125 } 126 127 { 128 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('MetadataVersion', ?);")); 129 if (sql.prepare() != SQLResultOk 130 || sql.bindInt(1, currentMetadataVersion) != SQLResultOk 131 || sql.step() != SQLResultDone) { 132 LOG_ERROR("Could not insert database metadata version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 133 m_sqliteDB = nullptr; 134 return nullptr; 135 } 136 } 137 { 138 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('DatabaseName', ?);")); 139 if (sql.prepare() != SQLResultOk 140 || sql.bindText(1, m_identifier.databaseName()) != SQLResultOk 141 || sql.step() != SQLResultDone) { 142 LOG_ERROR("Could not insert database name into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 143 m_sqliteDB = nullptr; 144 return nullptr; 145 } 146 } 147 { 148 // Database versions are defined to be a uin64_t in the spec but sqlite3 doesn't support native binding of unsigned integers. 149 // Therefore we'll store the version as a String. 150 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('DatabaseVersion', ?);")); 151 if (sql.prepare() != SQLResultOk 152 || sql.bindText(1, String::number(IDBDatabaseMetadata::NoIntVersion)) != SQLResultOk 153 || sql.step() != SQLResultDone) { 154 LOG_ERROR("Could not insert default version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 155 m_sqliteDB = nullptr; 156 return nullptr; 157 } 158 } 159 160 if (!m_sqliteDB->executeCommand(ASCIILiteral("INSERT INTO IDBDatabaseInfo VALUES ('MaxObjectStoreID', 1);"))) { 161 LOG_ERROR("Could not insert default version into IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 162 m_sqliteDB = nullptr; 163 return nullptr; 164 } 165 166 // This initial metadata matches the default values we just put into the metadata database. 167 auto metadata = std::make_unique<IDBDatabaseMetadata>(); 168 metadata->name = m_identifier.databaseName(); 169 metadata->version = IDBDatabaseMetadata::NoIntVersion; 170 metadata->maxObjectStoreId = 1; 171 172 return metadata; 173} 174 175std::unique_ptr<IDBDatabaseMetadata> UniqueIDBDatabaseBackingStoreSQLite::extractExistingMetadata() 176{ 177 ASSERT(!RunLoop::isMain()); 178 ASSERT(m_sqliteDB); 179 180 if (!m_sqliteDB->tableExists(ASCIILiteral("IDBDatabaseInfo"))) 181 return nullptr; 182 183 auto metadata = std::make_unique<IDBDatabaseMetadata>(); 184 { 185 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT value FROM IDBDatabaseInfo WHERE key = 'MetadataVersion';")); 186 if (sql.isColumnNull(0)) 187 return nullptr; 188 metadata->version = sql.getColumnInt(0); 189 } 190 { 191 SQLiteStatement sql(*m_sqliteDB, "SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseName';"); 192 if (sql.isColumnNull(0)) 193 return nullptr; 194 metadata->name = sql.getColumnText(0); 195 if (metadata->name != m_identifier.databaseName()) { 196 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()); 197 return nullptr; 198 } 199 } 200 { 201 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT value FROM IDBDatabaseInfo WHERE key = 'DatabaseVersion';")); 202 if (sql.isColumnNull(0)) 203 return nullptr; 204 String stringVersion = sql.getColumnText(0); 205 bool ok; 206 metadata->version = stringVersion.toUInt64Strict(&ok); 207 if (!ok) { 208 LOG_ERROR("Database version on disk ('%s') does not cleanly convert to an unsigned 64-bit integer version", stringVersion.utf8().data()); 209 return nullptr; 210 } 211 } 212 213 { 214 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT id, name, keyPath, autoInc, maxIndexID FROM ObjectStoreInfo;")); 215 if (sql.prepare() != SQLResultOk) 216 return nullptr; 217 218 int result = sql.step(); 219 while (result == SQLResultRow) { 220 IDBObjectStoreMetadata osMetadata; 221 osMetadata.id = sql.getColumnInt64(0); 222 osMetadata.name = sql.getColumnText(1); 223 224 Vector<char> keyPathBuffer; 225 sql.getColumnBlobAsVector(2, keyPathBuffer); 226 227 if (!deserializeIDBKeyPath(reinterpret_cast<const uint8_t*>(keyPathBuffer.data()), keyPathBuffer.size(), osMetadata.keyPath)) { 228 LOG_ERROR("Unable to extract key path metadata from database"); 229 return nullptr; 230 } 231 232 osMetadata.autoIncrement = sql.getColumnInt(3); 233 osMetadata.maxIndexId = sql.getColumnInt64(4); 234 235 metadata->objectStores.set(osMetadata.id, osMetadata); 236 result = sql.step(); 237 } 238 239 if (result != SQLResultDone) { 240 LOG_ERROR("Error fetching object store metadata from database on disk"); 241 return nullptr; 242 } 243 } 244 245 { 246 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT id, name, objectStoreID, keyPath, isUnique, multiEntry FROM IndexInfo;")); 247 if (sql.prepare() != SQLResultOk) 248 return nullptr; 249 250 int result = sql.step(); 251 while (result == SQLResultRow) { 252 IDBIndexMetadata indexMetadata; 253 254 indexMetadata.id = sql.getColumnInt64(0); 255 indexMetadata.name = sql.getColumnText(1); 256 int64_t objectStoreID = sql.getColumnInt64(2); 257 258 Vector<char> keyPathBuffer; 259 sql.getColumnBlobAsVector(3, keyPathBuffer); 260 261 if (!deserializeIDBKeyPath(reinterpret_cast<const uint8_t*>(keyPathBuffer.data()), keyPathBuffer.size(), indexMetadata.keyPath)) { 262 LOG_ERROR("Unable to extract key path metadata from database"); 263 return nullptr; 264 } 265 266 indexMetadata.unique = sql.getColumnInt(4); 267 indexMetadata.multiEntry = sql.getColumnInt(5); 268 269 auto objectStoreMetadataIt = metadata->objectStores.find(objectStoreID); 270 if (objectStoreMetadataIt == metadata->objectStores.end()) { 271 LOG_ERROR("Found index referring to a non-existant object store"); 272 return nullptr; 273 } 274 275 objectStoreMetadataIt->value.indexes.set(indexMetadata.id, indexMetadata); 276 277 result = sql.step(); 278 } 279 280 if (result != SQLResultDone) { 281 LOG_ERROR("Error fetching index metadata from database on disk"); 282 return nullptr; 283 } 284 } 285 286 return metadata; 287} 288 289std::unique_ptr<SQLiteDatabase> UniqueIDBDatabaseBackingStoreSQLite::openSQLiteDatabaseAtPath(const String& path) 290{ 291 ASSERT(!RunLoop::isMain()); 292 293 auto sqliteDatabase = std::make_unique<SQLiteDatabase>(); 294 if (!sqliteDatabase->open(path)) { 295 LOG_ERROR("Failed to open SQLite database at path '%s'", path.utf8().data()); 296 return nullptr; 297 } 298 299 // Since a WorkQueue isn't bound to a specific thread, we have to disable threading checks 300 // even though we never access the database from different threads simultaneously. 301 sqliteDatabase->disableThreadingChecks(); 302 303 return sqliteDatabase; 304} 305 306std::unique_ptr<IDBDatabaseMetadata> UniqueIDBDatabaseBackingStoreSQLite::getOrEstablishMetadata() 307{ 308 ASSERT(!RunLoop::isMain()); 309 310 String dbFilename = UniqueIDBDatabase::calculateAbsoluteDatabaseFilename(m_absoluteDatabaseDirectory); 311 312 m_sqliteDB = openSQLiteDatabaseAtPath(dbFilename); 313 if (!m_sqliteDB) 314 return nullptr; 315 316 m_sqliteDB->setCollationFunction("IDBKEY", [this](int aLength, const void* a, int bLength, const void* b) { 317 return idbKeyCollate(aLength, a, bLength, b); 318 }); 319 320 std::unique_ptr<IDBDatabaseMetadata> metadata = extractExistingMetadata(); 321 if (!metadata) 322 metadata = createAndPopulateInitialMetadata(); 323 324 if (!metadata) 325 LOG_ERROR("Unable to establish IDB database at path '%s'", dbFilename.utf8().data()); 326 327 // The database id is a runtime concept and doesn't need to be stored in the metadata database. 328 metadata->id = generateDatabaseId(); 329 330 return metadata; 331} 332 333bool UniqueIDBDatabaseBackingStoreSQLite::establishTransaction(const IDBIdentifier& transactionIdentifier, const Vector<int64_t>&, IndexedDB::TransactionMode mode) 334{ 335 ASSERT(!RunLoop::isMain()); 336 337 if (!m_transactions.add(transactionIdentifier, SQLiteIDBTransaction::create(*this, transactionIdentifier, mode)).isNewEntry) { 338 LOG_ERROR("Attempt to establish transaction identifier that already exists"); 339 return false; 340 } 341 342 return true; 343} 344 345bool UniqueIDBDatabaseBackingStoreSQLite::beginTransaction(const IDBIdentifier& transactionIdentifier) 346{ 347 ASSERT(!RunLoop::isMain()); 348 349 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 350 if (!transaction) { 351 LOG_ERROR("Attempt to begin a transaction that hasn't been established"); 352 return false; 353 } 354 355 return transaction->begin(*m_sqliteDB); 356} 357 358bool UniqueIDBDatabaseBackingStoreSQLite::commitTransaction(const IDBIdentifier& transactionIdentifier) 359{ 360 ASSERT(!RunLoop::isMain()); 361 362 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 363 if (!transaction) { 364 LOG_ERROR("Attempt to commit a transaction that hasn't been established"); 365 return false; 366 } 367 368 return transaction->commit(); 369} 370 371bool UniqueIDBDatabaseBackingStoreSQLite::resetTransaction(const IDBIdentifier& transactionIdentifier) 372{ 373 ASSERT(!RunLoop::isMain()); 374 375 std::unique_ptr<SQLiteIDBTransaction> transaction = m_transactions.take(transactionIdentifier); 376 if (!transaction) { 377 LOG_ERROR("Attempt to reset a transaction that hasn't been established"); 378 return false; 379 } 380 381 return transaction->reset(); 382} 383 384bool UniqueIDBDatabaseBackingStoreSQLite::rollbackTransaction(const IDBIdentifier& transactionIdentifier) 385{ 386 ASSERT(!RunLoop::isMain()); 387 388 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 389 if (!transaction) { 390 LOG_ERROR("Attempt to rollback a transaction that hasn't been established"); 391 return false; 392 } 393 394 if (!transaction->inProgress()) { 395 LOG_ERROR("Attempt to rollback a transaction that hasn't begun"); 396 return false; 397 } 398 399 return transaction->rollback(); 400} 401 402bool UniqueIDBDatabaseBackingStoreSQLite::changeDatabaseVersion(const IDBIdentifier& transactionIdentifier, uint64_t newVersion) 403{ 404 ASSERT(!RunLoop::isMain()); 405 ASSERT(m_sqliteDB); 406 ASSERT(m_sqliteDB->isOpen()); 407 408 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 409 if (!transaction || !transaction->inProgress()) { 410 LOG_ERROR("Attempt to change database version with an established, in-progress transaction"); 411 return false; 412 } 413 if (transaction->mode() != IndexedDB::TransactionMode::VersionChange) { 414 LOG_ERROR("Attempt to change database version during a non version-change transaction"); 415 return false; 416 } 417 418 { 419 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("UPDATE IDBDatabaseInfo SET value = ? where key = 'DatabaseVersion';")); 420 if (sql.prepare() != SQLResultOk 421 || sql.bindText(1, String::number(newVersion)) != SQLResultOk 422 || sql.step() != SQLResultDone) { 423 LOG_ERROR("Could not update database version in IDBDatabaseInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 424 return false; 425 } 426 } 427 428 return true; 429} 430 431bool UniqueIDBDatabaseBackingStoreSQLite::createObjectStore(const IDBIdentifier& transactionIdentifier, const IDBObjectStoreMetadata& metadata) 432{ 433 ASSERT(!RunLoop::isMain()); 434 ASSERT(m_sqliteDB); 435 ASSERT(m_sqliteDB->isOpen()); 436 437 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 438 if (!transaction || !transaction->inProgress()) { 439 LOG_ERROR("Attempt to change database version with an established, in-progress transaction"); 440 return false; 441 } 442 if (transaction->mode() != IndexedDB::TransactionMode::VersionChange) { 443 LOG_ERROR("Attempt to change database version during a non version-change transaction"); 444 return false; 445 } 446 447 RefPtr<SharedBuffer> keyPathBlob = serializeIDBKeyPath(metadata.keyPath); 448 if (!keyPathBlob) { 449 LOG_ERROR("Unable to serialize IDBKeyPath to save in database"); 450 return false; 451 } 452 453 { 454 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO ObjectStoreInfo VALUES (?, ?, ?, ?, ?);")); 455 if (sql.prepare() != SQLResultOk 456 || sql.bindInt64(1, metadata.id) != SQLResultOk 457 || sql.bindText(2, metadata.name) != SQLResultOk 458 || sql.bindBlob(3, keyPathBlob->data(), keyPathBlob->size()) != SQLResultOk 459 || sql.bindInt(4, metadata.autoIncrement) != SQLResultOk 460 || sql.bindInt64(5, metadata.maxIndexId) != SQLResultOk 461 || sql.step() != SQLResultDone) { 462 LOG_ERROR("Could not add object store '%s' to ObjectStoreInfo table (%i) - %s", metadata.name.utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 463 return false; 464 } 465 } 466 467 { 468 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO KeyGenerators VALUES (?, 0);")); 469 if (sql.prepare() != SQLResultOk 470 || sql.bindInt64(1, metadata.id) != SQLResultOk 471 || sql.step() != SQLResultDone) { 472 LOG_ERROR("Could not seed initial key generator value for ObjectStoreInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 473 return false; 474 } 475 } 476 477 return true; 478} 479 480bool UniqueIDBDatabaseBackingStoreSQLite::deleteObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID) 481{ 482 ASSERT(!RunLoop::isMain()); 483 ASSERT(m_sqliteDB); 484 ASSERT(m_sqliteDB->isOpen()); 485 486 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 487 if (!transaction || !transaction->inProgress()) { 488 LOG_ERROR("Attempt to change database version with an established, in-progress transaction"); 489 return false; 490 } 491 if (transaction->mode() != IndexedDB::TransactionMode::VersionChange) { 492 LOG_ERROR("Attempt to change database version during a non version-change transaction"); 493 return false; 494 } 495 496 // Delete the ObjectStore record 497 { 498 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM ObjectStoreInfo WHERE id = ?;")); 499 if (sql.prepare() != SQLResultOk 500 || sql.bindInt64(1, objectStoreID) != SQLResultOk 501 || sql.step() != SQLResultDone) { 502 LOG_ERROR("Could not delete object store id %lli from ObjectStoreInfo table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 503 return false; 504 } 505 } 506 507 // Delete the ObjectStore's key generator record if there is one. 508 { 509 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM KeyGenerators WHERE objectStoreID = ?;")); 510 if (sql.prepare() != SQLResultOk 511 || sql.bindInt64(1, objectStoreID) != SQLResultOk 512 || sql.step() != SQLResultDone) { 513 LOG_ERROR("Could not delete object store from KeyGenerators table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 514 return false; 515 } 516 } 517 518 // Delete all associated records 519 { 520 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM Records WHERE objectStoreID = ?;")); 521 if (sql.prepare() != SQLResultOk 522 || sql.bindInt64(1, objectStoreID) != SQLResultOk 523 || sql.step() != SQLResultDone) { 524 LOG_ERROR("Could not delete records for object store %lli (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 525 return false; 526 } 527 } 528 529 // Delete all associated Indexes 530 { 531 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM IndexInfo WHERE objectStoreID = ?;")); 532 if (sql.prepare() != SQLResultOk 533 || sql.bindInt64(1, objectStoreID) != SQLResultOk 534 || sql.step() != SQLResultDone) { 535 LOG_ERROR("Could not delete index from IndexInfo table (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 536 return false; 537 } 538 } 539 540 // Delete all associated Index records 541 { 542 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM IndexRecords WHERE objectStoreID = ?;")); 543 if (sql.prepare() != SQLResultOk 544 || sql.bindInt64(1, objectStoreID) != SQLResultOk 545 || sql.step() != SQLResultDone) { 546 LOG_ERROR("Could not delete index records(%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 547 return false; 548 } 549 } 550 551 return true; 552} 553 554bool UniqueIDBDatabaseBackingStoreSQLite::clearObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID) 555{ 556 ASSERT(!RunLoop::isMain()); 557 ASSERT(m_sqliteDB); 558 ASSERT(m_sqliteDB->isOpen()); 559 560 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 561 if (!transaction || !transaction->inProgress()) { 562 LOG_ERROR("Attempt to change database version with an establish, in-progress transaction"); 563 return false; 564 } 565 if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) { 566 LOG_ERROR("Attempt to change database version during a read-only transaction"); 567 return false; 568 } 569 570 { 571 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM Records WHERE objectStoreID = ?;")); 572 if (sql.prepare() != SQLResultOk 573 || sql.bindInt64(1, objectStoreID) != SQLResultOk 574 || sql.step() != SQLResultDone) { 575 LOG_ERROR("Could not delete records from object store id %lli (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 576 return false; 577 } 578 } 579 580 { 581 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM IndexRecords WHERE objectStoreID = ?;")); 582 if (sql.prepare() != SQLResultOk 583 || sql.bindInt64(1, objectStoreID) != SQLResultOk 584 || sql.step() != SQLResultDone) { 585 LOG_ERROR("Could not delete records from index record store id %lli (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 586 return false; 587 } 588 } 589 590 return true; 591} 592 593bool UniqueIDBDatabaseBackingStoreSQLite::createIndex(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBIndexMetadata& metadata) 594{ 595 ASSERT(!RunLoop::isMain()); 596 ASSERT(m_sqliteDB); 597 ASSERT(m_sqliteDB->isOpen()); 598 599 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 600 if (!transaction || !transaction->inProgress()) { 601 LOG_ERROR("Attempt to create index without an established, in-progress transaction"); 602 return false; 603 } 604 if (transaction->mode() != IndexedDB::TransactionMode::VersionChange) { 605 LOG_ERROR("Attempt to create index during a non-version-change transaction"); 606 return false; 607 } 608 609 RefPtr<SharedBuffer> keyPathBlob = serializeIDBKeyPath(metadata.keyPath); 610 if (!keyPathBlob) { 611 LOG_ERROR("Unable to serialize IDBKeyPath to save in database"); 612 return false; 613 } 614 615 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IndexInfo VALUES (?, ?, ?, ?, ?, ?);")); 616 if (sql.prepare() != SQLResultOk 617 || sql.bindInt64(1, metadata.id) != SQLResultOk 618 || sql.bindText(2, metadata.name) != SQLResultOk 619 || sql.bindInt64(3, objectStoreID) != SQLResultOk 620 || sql.bindBlob(4, keyPathBlob->data(), keyPathBlob->size()) != SQLResultOk 621 || sql.bindInt(5, metadata.unique) != SQLResultOk 622 || sql.bindInt(6, metadata.multiEntry) != SQLResultOk 623 || sql.step() != SQLResultDone) { 624 LOG_ERROR("Could not add index '%s' to IndexInfo table (%i) - %s", metadata.name.utf8().data(), m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 625 return false; 626 } 627 628 // Write index records for any records that already exist in this object store. 629 SQLiteIDBCursor* cursor = transaction->openCursor(objectStoreID, IDBIndexMetadata::InvalidId, IndexedDB::CursorDirection::Next, IndexedDB::CursorType::KeyAndValue, IDBDatabaseBackend::NormalTask, IDBKeyRangeData()); 630 631 if (!cursor) { 632 LOG_ERROR("Cannot open cursor to populate indexes in database"); 633 return false; 634 } 635 636 m_cursors.set(cursor->identifier(), cursor); 637 638 std::unique_ptr<JSLockHolder> locker; 639 while (!cursor->currentKey().isNull) { 640 const IDBKeyData& key = cursor->currentKey(); 641 const Vector<uint8_t>& valueBuffer = cursor->currentValueBuffer(); 642 643 if (!m_globalObject) { 644 ASSERT(!m_vm); 645 m_vm = VM::create(); 646 locker = std::make_unique<JSLockHolder>(m_vm.get()); 647 m_globalObject.set(*m_vm, JSGlobalObject::create(*m_vm, JSGlobalObject::createStructure(*m_vm, jsNull()))); 648 } 649 650 if (!locker) 651 locker = std::make_unique<JSLockHolder>(m_vm.get()); 652 653 Deprecated::ScriptValue value = deserializeIDBValueBuffer(m_globalObject->globalExec(), valueBuffer, true); 654 Vector<IDBKeyData> indexKeys; 655 generateIndexKeysForValue(m_globalObject->globalExec(), metadata, value, indexKeys); 656 657 for (auto& indexKey : indexKeys) { 658 if (!uncheckedPutIndexRecord(objectStoreID, metadata.id, key, indexKey)) { 659 LOG_ERROR("Unable to put index record for newly created index"); 660 return false; 661 } 662 } 663 664 if (!cursor->advance(1)) { 665 LOG_ERROR("Error advancing cursor while indexing existing records for new index."); 666 return false; 667 } 668 } 669 670 transaction->closeCursor(*cursor); 671 672 return true; 673} 674 675bool UniqueIDBDatabaseBackingStoreSQLite::deleteIndex(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID) 676{ 677 ASSERT(!RunLoop::isMain()); 678 ASSERT(m_sqliteDB); 679 ASSERT(m_sqliteDB->isOpen()); 680 681 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 682 if (!transaction || !transaction->inProgress()) { 683 LOG_ERROR("Attempt to delete index without an established, in-progress transaction"); 684 return false; 685 } 686 if (transaction->mode() != IndexedDB::TransactionMode::VersionChange) { 687 LOG_ERROR("Attempt to delete index during a non-version-change transaction"); 688 return false; 689 } 690 691 { 692 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM IndexInfo WHERE id = ? AND objectStoreID = ?;")); 693 if (sql.prepare() != SQLResultOk 694 || sql.bindInt64(1, indexID) != SQLResultOk 695 || sql.bindInt64(2, objectStoreID) != SQLResultOk 696 || sql.step() != SQLResultDone) { 697 LOG_ERROR("Could not delete index id %lli from IndexInfo table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 698 return false; 699 } 700 } 701 702 { 703 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM IndexRecords WHERE indexID = ? AND objectStoreID = ?;")); 704 if (sql.prepare() != SQLResultOk 705 || sql.bindInt64(1, indexID) != SQLResultOk 706 || sql.bindInt64(2, objectStoreID) != SQLResultOk 707 || sql.step() != SQLResultDone) { 708 LOG_ERROR("Could not delete index records for index id %lli from IndexRecords table (%i) - %s", indexID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 709 return false; 710 } 711 } 712 713 return true; 714} 715 716bool UniqueIDBDatabaseBackingStoreSQLite::generateKeyNumber(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t& generatedKey) 717{ 718 ASSERT(!RunLoop::isMain()); 719 ASSERT(m_sqliteDB); 720 ASSERT(m_sqliteDB->isOpen()); 721 722 // The IndexedDatabase spec defines the max key generator value as 2^53; 723 static const int64_t maxGeneratorValue = 9007199254740992LL; 724 725 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 726 if (!transaction || !transaction->inProgress()) { 727 LOG_ERROR("Attempt to generate key in database without an established, in-progress transaction"); 728 return false; 729 } 730 if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) { 731 LOG_ERROR("Attempt to generate key in database during read-only transaction"); 732 return false; 733 } 734 735 int64_t currentValue; 736 { 737 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT currentKey FROM KeyGenerators WHERE objectStoreID = ?;")); 738 if (sql.prepare() != SQLResultOk 739 || sql.bindInt64(1, objectStoreID) != SQLResultOk) { 740 LOG_ERROR("Could not delete index id %lli from IndexInfo table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 741 return false; 742 } 743 int result = sql.step(); 744 if (result != SQLResultRow) { 745 LOG_ERROR("Could not retreive key generator value for object store, but it should be there."); 746 return false; 747 } 748 749 currentValue = sql.getColumnInt64(0); 750 } 751 752 if (currentValue < 0 || currentValue > maxGeneratorValue) 753 return false; 754 755 generatedKey = currentValue + 1; 756 return true; 757} 758 759bool UniqueIDBDatabaseBackingStoreSQLite::updateKeyGeneratorNumber(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t keyNumber, bool) 760{ 761 ASSERT(!RunLoop::isMain()); 762 ASSERT(m_sqliteDB); 763 ASSERT(m_sqliteDB->isOpen()); 764 765 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 766 if (!transaction || !transaction->inProgress()) { 767 LOG_ERROR("Attempt to update key generator in database without an established, in-progress transaction"); 768 return false; 769 } 770 if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) { 771 LOG_ERROR("Attempt to update key generator in database during read-only transaction"); 772 return false; 773 } 774 775 { 776 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO KeyGenerators VALUES (?, ?);")); 777 if (sql.prepare() != SQLResultOk 778 || sql.bindInt64(1, objectStoreID) != SQLResultOk 779 || sql.bindInt64(2, keyNumber) != SQLResultOk 780 || sql.step() != SQLResultDone) { 781 LOG_ERROR("Could not update key generator value (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 782 return false; 783 } 784 } 785 786 return true; 787} 788 789bool UniqueIDBDatabaseBackingStoreSQLite::keyExistsInObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyData& keyData, bool& keyExists) 790{ 791 ASSERT(!RunLoop::isMain()); 792 ASSERT(m_sqliteDB); 793 ASSERT(m_sqliteDB->isOpen()); 794 795 keyExists = false; 796 797 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 798 if (!transaction || !transaction->inProgress()) { 799 LOG_ERROR("Attempt to see if key exists in objectstore without established, in-progress transaction"); 800 return false; 801 } 802 803 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData); 804 if (!keyBuffer) { 805 LOG_ERROR("Unable to serialize IDBKey to check for existence"); 806 return false; 807 } 808 809 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT key FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT) LIMIT 1;")); 810 if (sql.prepare() != SQLResultOk 811 || sql.bindInt64(1, objectStoreID) != SQLResultOk 812 || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLResultOk) { 813 LOG_ERROR("Could not get record from object store %lli from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 814 return false; 815 } 816 817 int sqlResult = sql.step(); 818 if (sqlResult == SQLResultOk || sqlResult == SQLResultDone) { 819 keyExists = false; 820 return true; 821 } 822 823 if (sqlResult != SQLResultRow) { 824 // There was an error fetching the record from the database. 825 LOG_ERROR("Could not check if key exists in object store (%i) - %s", m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 826 return false; 827 } 828 829 keyExists = true; 830 return true; 831} 832 833bool UniqueIDBDatabaseBackingStoreSQLite::putRecord(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyData& keyData, const uint8_t* valueBuffer, size_t valueSize) 834{ 835 ASSERT(!RunLoop::isMain()); 836 ASSERT(m_sqliteDB); 837 ASSERT(m_sqliteDB->isOpen()); 838 839 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 840 if (!transaction || !transaction->inProgress()) { 841 LOG_ERROR("Attempt to put a record into database without an established, in-progress transaction"); 842 return false; 843 } 844 if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) { 845 LOG_ERROR("Attempt to put a record into database during read-only transaction"); 846 return false; 847 } 848 849 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(keyData); 850 if (!keyBuffer) { 851 LOG_ERROR("Unable to serialize IDBKey to be stored in the database"); 852 return false; 853 } 854 { 855 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO Records VALUES (?, CAST(? AS TEXT), ?);")); 856 if (sql.prepare() != SQLResultOk 857 || sql.bindInt64(1, objectStoreID) != SQLResultOk 858 || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLResultOk 859 || sql.bindBlob(3, valueBuffer, valueSize) != SQLResultOk 860 || sql.step() != SQLResultDone) { 861 LOG_ERROR("Could not put record for object store %lli in Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 862 return false; 863 } 864 } 865 866 return true; 867} 868 869bool UniqueIDBDatabaseBackingStoreSQLite::putIndexRecord(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyData& keyValue, const IDBKeyData& indexKey) 870{ 871 ASSERT(!RunLoop::isMain()); 872 ASSERT(m_sqliteDB); 873 ASSERT(m_sqliteDB->isOpen()); 874 875 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 876 if (!transaction || !transaction->inProgress()) { 877 LOG_ERROR("Attempt to put index record into database without an established, in-progress transaction"); 878 return false; 879 } 880 if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) { 881 LOG_ERROR("Attempt to put index record into database during read-only transaction"); 882 return false; 883 } 884 885 return uncheckedPutIndexRecord(objectStoreID, indexID, keyValue, indexKey); 886} 887 888bool UniqueIDBDatabaseBackingStoreSQLite::uncheckedPutIndexRecord(int64_t objectStoreID, int64_t indexID, const WebCore::IDBKeyData& keyValue, const WebCore::IDBKeyData& indexKey) 889{ 890 RefPtr<SharedBuffer> indexKeyBuffer = serializeIDBKeyData(indexKey); 891 if (!indexKeyBuffer) { 892 LOG_ERROR("Unable to serialize index key to be stored in the database"); 893 return false; 894 } 895 896 RefPtr<SharedBuffer> valueBuffer = serializeIDBKeyData(keyValue); 897 if (!valueBuffer) { 898 LOG_ERROR("Unable to serialize the value to be stored in the database"); 899 return false; 900 } 901 { 902 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("INSERT INTO IndexRecords VALUES (?, ?, CAST(? AS TEXT), CAST(? AS TEXT));")); 903 if (sql.prepare() != SQLResultOk 904 || sql.bindInt64(1, indexID) != SQLResultOk 905 || sql.bindInt64(2, objectStoreID) != SQLResultOk 906 || sql.bindBlob(3, indexKeyBuffer->data(), indexKeyBuffer->size()) != SQLResultOk 907 || sql.bindBlob(4, valueBuffer->data(), valueBuffer->size()) != SQLResultOk 908 || sql.step() != SQLResultDone) { 909 LOG_ERROR("Could not put index record for index %lli in object store %lli in Records table (%i) - %s", indexID, objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 910 return false; 911 } 912 } 913 914 return true; 915} 916 917bool UniqueIDBDatabaseBackingStoreSQLite::getIndexRecord(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData& keyRangeData, IndexedDB::CursorType cursorType, IDBGetResult& result) 918{ 919 ASSERT(!RunLoop::isMain()); 920 ASSERT(m_sqliteDB); 921 ASSERT(m_sqliteDB->isOpen()); 922 923 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 924 if (!transaction || !transaction->inProgress()) { 925 LOG_ERROR("Attempt to get count from database without an established, in-progress transaction"); 926 return false; 927 } 928 929 SQLiteIDBCursor* cursor = transaction->openCursor(objectStoreID, indexID, IndexedDB::CursorDirection::Next, cursorType, IDBDatabaseBackend::NormalTask, keyRangeData); 930 931 if (!cursor) { 932 LOG_ERROR("Cannot open cursor to perform index get in database"); 933 return false; 934 } 935 936 // Even though we're only using this cursor locally, add it to our cursor set. 937 m_cursors.set(cursor->identifier(), cursor); 938 939 if (cursorType == IndexedDB::CursorType::KeyOnly) 940 result = IDBGetResult(cursor->currentPrimaryKey()); 941 else { 942 result = IDBGetResult(SharedBuffer::create(cursor->currentValueBuffer().data(), cursor->currentValueBuffer().size())); 943 result.keyData = cursor->currentPrimaryKey(); 944 } 945 946 // Closing the cursor will destroy the cursor object and remove it from our cursor set. 947 transaction->closeCursor(*cursor); 948 949 return true; 950} 951 952bool UniqueIDBDatabaseBackingStoreSQLite::deleteRecord(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const WebCore::IDBKeyData& keyData) 953{ 954 ASSERT(!RunLoop::isMain()); 955 ASSERT(m_sqliteDB); 956 ASSERT(m_sqliteDB->isOpen()); 957 958 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 959 if (!transaction || !transaction->inProgress()) { 960 LOG_ERROR("Attempt to get count from database without an established, in-progress transaction"); 961 return false; 962 } 963 964 if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) { 965 LOG_ERROR("Attempt to delete range from a read-only transaction"); 966 return false; 967 } 968 969 return deleteRecord(*transaction, objectStoreID, keyData); 970} 971 972bool UniqueIDBDatabaseBackingStoreSQLite::deleteRange(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyRangeData& keyRangeData) 973{ 974 ASSERT(!RunLoop::isMain()); 975 ASSERT(m_sqliteDB); 976 ASSERT(m_sqliteDB->isOpen()); 977 978 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 979 if (!transaction || !transaction->inProgress()) { 980 LOG_ERROR("Attempt to get count from database without an established, in-progress transaction"); 981 return false; 982 } 983 984 if (transaction->mode() == IndexedDB::TransactionMode::ReadOnly) { 985 LOG_ERROR("Attempt to delete range from a read-only transaction"); 986 return false; 987 } 988 989 // If the range to delete is exactly one key we can delete it right now. 990 if (keyRangeData.isExactlyOneKey()) { 991 if (!deleteRecord(*transaction, objectStoreID, keyRangeData.lowerKey)) { 992 LOG_ERROR("Failed to delete record for key '%s'", keyRangeData.lowerKey.loggingString().utf8().data()); 993 return false; 994 } 995 return true; 996 } 997 998 // Otherwise the range might span multiple keys so we collect them with a cursor. 999 SQLiteIDBCursor* cursor = transaction->openCursor(objectStoreID, IDBIndexMetadata::InvalidId, IndexedDB::CursorDirection::Next, IndexedDB::CursorType::KeyAndValue, IDBDatabaseBackend::NormalTask, keyRangeData); 1000 1001 if (!cursor) { 1002 LOG_ERROR("Cannot open cursor to perform index get in database"); 1003 return false; 1004 } 1005 1006 m_cursors.set(cursor->identifier(), cursor); 1007 1008 Vector<IDBKeyData> keys; 1009 do 1010 keys.append(cursor->currentKey()); 1011 while (cursor->advance(1)); 1012 1013 bool cursorDidError = cursor->didError(); 1014 1015 // closeCursor() will remove the cursor from m_cursors and delete the cursor object 1016 transaction->closeCursor(*cursor); 1017 1018 if (cursorDidError) { 1019 LOG_ERROR("Unable to iterate over object store to deleteRange in database"); 1020 return false; 1021 } 1022 1023 for (auto& key : keys) { 1024 if (!deleteRecord(*transaction, objectStoreID, key)) { 1025 LOG_ERROR("Failed to delete record for key '%s'", key.loggingString().utf8().data()); 1026 return false; 1027 } 1028 } 1029 1030 return true; 1031} 1032 1033bool UniqueIDBDatabaseBackingStoreSQLite::deleteRecord(SQLiteIDBTransaction& transaction, int64_t objectStoreID, const WebCore::IDBKeyData& key) 1034{ 1035 ASSERT(!RunLoop::isMain()); 1036 ASSERT(m_sqliteDB); 1037 ASSERT(m_sqliteDB->isOpen()); 1038 1039 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(key); 1040 if (!keyBuffer) { 1041 LOG_ERROR("Unable to serialize IDBKeyData to be removed from the database"); 1042 return false; 1043 } 1044 1045 // Delete record from object store 1046 { 1047 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT);")); 1048 1049 if (sql.prepare() != SQLResultOk 1050 || sql.bindInt64(1, objectStoreID) != SQLResultOk 1051 || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLResultOk 1052 || sql.step() != SQLResultDone) { 1053 LOG_ERROR("Could not delete record from object store %lli (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 1054 return false; 1055 } 1056 } 1057 1058 // Delete record from indexes store 1059 { 1060 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("DELETE FROM IndexRecords WHERE objectStoreID = ? AND value = CAST(? AS TEXT);")); 1061 1062 if (sql.prepare() != SQLResultOk 1063 || sql.bindInt64(1, objectStoreID) != SQLResultOk 1064 || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLResultOk 1065 || sql.step() != SQLResultDone) { 1066 LOG_ERROR("Could not delete record from indexes for object store %lli (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 1067 return false; 1068 } 1069 } 1070 1071 return true; 1072} 1073 1074bool UniqueIDBDatabaseBackingStoreSQLite::getKeyRecordFromObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKey& key, RefPtr<SharedBuffer>& result) 1075{ 1076 ASSERT(!RunLoop::isMain()); 1077 ASSERT(m_sqliteDB); 1078 ASSERT(m_sqliteDB->isOpen()); 1079 1080 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 1081 if (!transaction || !transaction->inProgress()) { 1082 LOG_ERROR("Attempt to put a record into database without an established, in-progress transaction"); 1083 return false; 1084 } 1085 1086 RefPtr<SharedBuffer> keyBuffer = serializeIDBKeyData(IDBKeyData(&key)); 1087 if (!keyBuffer) { 1088 LOG_ERROR("Unable to serialize IDBKey to be stored in the database"); 1089 return false; 1090 } 1091 1092 { 1093 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT value FROM Records WHERE objectStoreID = ? AND key = CAST(? AS TEXT);")); 1094 if (sql.prepare() != SQLResultOk 1095 || sql.bindInt64(1, objectStoreID) != SQLResultOk 1096 || sql.bindBlob(2, keyBuffer->data(), keyBuffer->size()) != SQLResultOk) { 1097 LOG_ERROR("Could not get record from object store %lli from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 1098 return false; 1099 } 1100 1101 int sqlResult = sql.step(); 1102 if (sqlResult == SQLResultOk || sqlResult == SQLResultDone) { 1103 // There was no record for the key in the database. 1104 return true; 1105 } 1106 if (sqlResult != SQLResultRow) { 1107 // There was an error fetching the record from the database. 1108 LOG_ERROR("Could not get record from object store %lli from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 1109 return false; 1110 } 1111 1112 Vector<char> buffer; 1113 sql.getColumnBlobAsVector(0, buffer); 1114 result = SharedBuffer::create(static_cast<const char*>(buffer.data()), buffer.size()); 1115 } 1116 1117 return true; 1118} 1119 1120bool UniqueIDBDatabaseBackingStoreSQLite::getKeyRangeRecordFromObjectStore(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, const IDBKeyRange& keyRange, RefPtr<SharedBuffer>& result, RefPtr<IDBKey>& resultKey) 1121{ 1122 ASSERT(!RunLoop::isMain()); 1123 ASSERT(m_sqliteDB); 1124 ASSERT(m_sqliteDB->isOpen()); 1125 1126 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 1127 if (!transaction || !transaction->inProgress()) { 1128 LOG_ERROR("Attempt to put a record into database without an established, in-progress transaction"); 1129 return false; 1130 } 1131 1132 RefPtr<SharedBuffer> lowerBuffer = serializeIDBKeyData(IDBKeyData(keyRange.lower().get())); 1133 if (!lowerBuffer) { 1134 LOG_ERROR("Unable to serialize IDBKey to be stored in the database"); 1135 return false; 1136 } 1137 1138 RefPtr<SharedBuffer> upperBuffer = serializeIDBKeyData(IDBKeyData(keyRange.upper().get())); 1139 if (!upperBuffer) { 1140 LOG_ERROR("Unable to serialize IDBKey to be stored in the database"); 1141 return false; 1142 } 1143 1144 { 1145 SQLiteStatement sql(*m_sqliteDB, ASCIILiteral("SELECT value FROM Records WHERE objectStoreID = ? AND key >= CAST(? AS TEXT) AND key <= CAST(? AS TEXT) ORDER BY key;")); 1146 if (sql.prepare() != SQLResultOk 1147 || sql.bindInt64(1, objectStoreID) != SQLResultOk 1148 || sql.bindBlob(2, lowerBuffer->data(), lowerBuffer->size()) != SQLResultOk 1149 || sql.bindBlob(3, upperBuffer->data(), upperBuffer->size()) != SQLResultOk) { 1150 LOG_ERROR("Could not get key range record from object store %lli from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 1151 return false; 1152 } 1153 1154 int sqlResult = sql.step(); 1155 1156 if (sqlResult == SQLResultOk || sqlResult == SQLResultDone) { 1157 // There was no record for the key in the database. 1158 return true; 1159 } 1160 if (sqlResult != SQLResultRow) { 1161 // There was an error fetching the record from the database. 1162 LOG_ERROR("Could not get record from object store %lli from Records table (%i) - %s", objectStoreID, m_sqliteDB->lastError(), m_sqliteDB->lastErrorMsg()); 1163 return false; 1164 } 1165 1166 Vector<char> buffer; 1167 sql.getColumnBlobAsVector(0, buffer); 1168 result = SharedBuffer::create(static_cast<const char*>(buffer.data()), buffer.size()); 1169 } 1170 1171 return true; 1172} 1173 1174bool UniqueIDBDatabaseBackingStoreSQLite::count(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, const IDBKeyRangeData& keyRangeData, int64_t& count) 1175{ 1176 ASSERT(!RunLoop::isMain()); 1177 ASSERT(m_sqliteDB); 1178 ASSERT(m_sqliteDB->isOpen()); 1179 1180 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 1181 if (!transaction || !transaction->inProgress()) { 1182 LOG_ERROR("Attempt to get count from database without an established, in-progress transaction"); 1183 return false; 1184 } 1185 1186 SQLiteIDBCursor* cursor = transaction->openCursor(objectStoreID, indexID, IndexedDB::CursorDirection::Next, IndexedDB::CursorType::KeyOnly, IDBDatabaseBackend::NormalTask, keyRangeData); 1187 1188 if (!cursor) { 1189 LOG_ERROR("Cannot open cursor to get count in database"); 1190 return false; 1191 } 1192 1193 m_cursors.set(cursor->identifier(), cursor); 1194 1195 count = 0; 1196 while (cursor->advance(1)) 1197 ++count; 1198 1199 transaction->closeCursor(*cursor); 1200 1201 return true; 1202} 1203 1204bool UniqueIDBDatabaseBackingStoreSQLite::openCursor(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID, int64_t indexID, IndexedDB::CursorDirection cursorDirection, IndexedDB::CursorType cursorType, IDBDatabaseBackend::TaskType taskType, const IDBKeyRangeData& keyRange, int64_t& cursorID, IDBKeyData& key, IDBKeyData& primaryKey, Vector<uint8_t>& valueBuffer) 1205{ 1206 ASSERT(!RunLoop::isMain()); 1207 ASSERT(m_sqliteDB); 1208 ASSERT(m_sqliteDB->isOpen()); 1209 1210 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 1211 if (!transaction || !transaction->inProgress()) { 1212 LOG_ERROR("Attempt to open a cursor in database without an established, in-progress transaction"); 1213 return false; 1214 } 1215 1216 SQLiteIDBCursor* cursor = transaction->openCursor(objectStoreID, indexID, cursorDirection, cursorType, taskType, keyRange); 1217 if (!cursor) 1218 return false; 1219 1220 m_cursors.set(cursor->identifier(), cursor); 1221 cursorID = cursor->identifier().id(); 1222 key = cursor->currentKey(); 1223 primaryKey = cursor->currentPrimaryKey(); 1224 valueBuffer = cursor->currentValueBuffer(); 1225 1226 return true; 1227} 1228 1229bool UniqueIDBDatabaseBackingStoreSQLite::advanceCursor(const IDBIdentifier& cursorIdentifier, uint64_t count, IDBKeyData& key, IDBKeyData& primaryKey, Vector<uint8_t>& valueBuffer) 1230{ 1231 ASSERT(!RunLoop::isMain()); 1232 ASSERT(m_sqliteDB); 1233 ASSERT(m_sqliteDB->isOpen()); 1234 1235 SQLiteIDBCursor* cursor = m_cursors.get(cursorIdentifier); 1236 if (!cursor) { 1237 LOG_ERROR("Attempt to advance a cursor that doesn't exist"); 1238 return false; 1239 } 1240 if (!cursor->transaction() || !cursor->transaction()->inProgress()) { 1241 LOG_ERROR("Attempt to advance a cursor without an established, in-progress transaction"); 1242 return false; 1243 } 1244 1245 if (!cursor->advance(count)) { 1246 LOG_ERROR("Attempt to advance cursor %lli steps failed", count); 1247 return false; 1248 } 1249 1250 key = cursor->currentKey(); 1251 primaryKey = cursor->currentPrimaryKey(); 1252 valueBuffer = cursor->currentValueBuffer(); 1253 1254 return true; 1255} 1256 1257bool UniqueIDBDatabaseBackingStoreSQLite::iterateCursor(const IDBIdentifier& cursorIdentifier, const IDBKeyData& targetKey, IDBKeyData& key, IDBKeyData& primaryKey, Vector<uint8_t>& valueBuffer) 1258{ 1259 ASSERT(!RunLoop::isMain()); 1260 ASSERT(m_sqliteDB); 1261 ASSERT(m_sqliteDB->isOpen()); 1262 1263 SQLiteIDBCursor* cursor = m_cursors.get(cursorIdentifier); 1264 if (!cursor) { 1265 LOG_ERROR("Attempt to iterate a cursor that doesn't exist"); 1266 return false; 1267 } 1268 if (!cursor->transaction() || !cursor->transaction()->inProgress()) { 1269 LOG_ERROR("Attempt to iterate a cursor without an established, in-progress transaction"); 1270 return false; 1271 } 1272 1273 if (!cursor->iterate(targetKey)) { 1274 LOG_ERROR("Attempt to iterate cursor failed"); 1275 return false; 1276 } 1277 1278 key = cursor->currentKey(); 1279 primaryKey = cursor->currentPrimaryKey(); 1280 valueBuffer = cursor->currentValueBuffer(); 1281 1282 return true; 1283} 1284 1285void UniqueIDBDatabaseBackingStoreSQLite::notifyCursorsOfChanges(const IDBIdentifier& transactionIdentifier, int64_t objectStoreID) 1286{ 1287 ASSERT(!RunLoop::isMain()); 1288 ASSERT(m_sqliteDB); 1289 ASSERT(m_sqliteDB->isOpen()); 1290 1291 SQLiteIDBTransaction* transaction = m_transactions.get(transactionIdentifier); 1292 if (!transaction || !transaction->inProgress()) { 1293 LOG_ERROR("Attempt to notify cursors of changes in database without an established, in-progress transaction"); 1294 return; 1295 } 1296 1297 transaction->notifyCursorsOfChanges(objectStoreID); 1298} 1299 1300int UniqueIDBDatabaseBackingStoreSQLite::idbKeyCollate(int aLength, const void* aBuffer, int bLength, const void* bBuffer) 1301{ 1302 IDBKeyData a, b; 1303 if (!deserializeIDBKeyData(static_cast<const uint8_t*>(aBuffer), aLength, a)) { 1304 LOG_ERROR("Unable to deserialize key A in collation function."); 1305 1306 // There's no way to indicate an error to SQLite - we have to return a sorting decision. 1307 // We arbitrarily choose "A > B" 1308 return 1; 1309 } 1310 if (!deserializeIDBKeyData(static_cast<const uint8_t*>(bBuffer), bLength, b)) { 1311 LOG_ERROR("Unable to deserialize key B in collation function."); 1312 1313 // There's no way to indicate an error to SQLite - we have to return a sorting decision. 1314 // We arbitrarily choose "A > B" 1315 return 1; 1316 } 1317 1318 return a.compare(b); 1319} 1320 1321void UniqueIDBDatabaseBackingStoreSQLite::unregisterCursor(SQLiteIDBCursor* cursor) 1322{ 1323 ASSERT(m_cursors.contains(cursor->identifier())); 1324 m_cursors.remove(cursor->identifier()); 1325} 1326 1327} // namespace WebKit 1328 1329#endif // ENABLE(INDEXED_DATABASE) && ENABLE(DATABASE_PROCESS) 1330