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. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "config.h" 27 #include "modules/webdatabase/Database.h" 28 29 #include "core/dom/CrossThreadTask.h" 30 #include "core/dom/ExceptionCode.h" 31 #include "core/html/VoidCallback.h" 32 #include "modules/webdatabase/ChangeVersionData.h" 33 #include "modules/webdatabase/ChangeVersionWrapper.h" 34 #include "modules/webdatabase/DatabaseAuthorizer.h" 35 #include "modules/webdatabase/DatabaseContext.h" 36 #include "modules/webdatabase/DatabaseManager.h" 37 #include "modules/webdatabase/DatabaseTask.h" 38 #include "modules/webdatabase/DatabaseThread.h" 39 #include "modules/webdatabase/DatabaseTracker.h" 40 #include "modules/webdatabase/SQLError.h" 41 #include "modules/webdatabase/SQLTransaction.h" 42 #include "modules/webdatabase/SQLTransactionBackend.h" 43 #include "modules/webdatabase/SQLTransactionCallback.h" 44 #include "modules/webdatabase/SQLTransactionClient.h" 45 #include "modules/webdatabase/SQLTransactionCoordinator.h" 46 #include "modules/webdatabase/SQLTransactionErrorCallback.h" 47 #include "modules/webdatabase/sqlite/SQLiteStatement.h" 48 #include "modules/webdatabase/sqlite/SQLiteTransaction.h" 49 #include "platform/Logging.h" 50 #include "platform/weborigin/DatabaseIdentifier.h" 51 #include "public/platform/Platform.h" 52 #include "public/platform/WebDatabaseObserver.h" 53 54 // Registering "opened" databases with the DatabaseTracker 55 // ======================================================= 56 // The DatabaseTracker maintains a list of databases that have been 57 // "opened" so that the client can call interrupt or delete on every database 58 // associated with a DatabaseContext. 59 // 60 // We will only call DatabaseTracker::addOpenDatabase() to add the database 61 // to the tracker as opened when we've succeeded in opening the database, 62 // and will set m_opened to true. Similarly, we only call 63 // DatabaseTracker::removeOpenDatabase() to remove the database from the 64 // tracker when we set m_opened to false in closeDatabase(). This sets up 65 // a simple symmetry between open and close operations, and a direct 66 // correlation to adding and removing databases from the tracker's list, 67 // thus ensuring that we have a correct list for the interrupt and 68 // delete operations to work on. 69 // 70 // The only databases instances not tracked by the tracker's open database 71 // list are the ones that have not been added yet, or the ones that we 72 // attempted an open on but failed to. Such instances only exist in the 73 // DatabaseServer's factory methods for creating database backends. 74 // 75 // The factory methods will either call openAndVerifyVersion() or 76 // performOpenAndVerify(). These methods will add the newly instantiated 77 // database backend if they succeed in opening the requested database. 78 // In the case of failure to open the database, the factory methods will 79 // simply discard the newly instantiated database backend when they return. 80 // The ref counting mechanims will automatically destruct the un-added 81 // (and un-returned) databases instances. 82 83 namespace blink { 84 85 static const char versionKey[] = "WebKitDatabaseVersionKey"; 86 static const char infoTableName[] = "__WebKitDatabaseInfoTable__"; 87 88 static String formatErrorMessage(const char* message, int sqliteErrorCode, const char* sqliteErrorMessage) 89 { 90 return String::format("%s (%d %s)", message, sqliteErrorCode, sqliteErrorMessage); 91 } 92 93 static bool retrieveTextResultFromDatabase(SQLiteDatabase& db, const String& query, String& resultString) 94 { 95 SQLiteStatement statement(db, query); 96 int result = statement.prepare(); 97 98 if (result != SQLResultOk) { 99 WTF_LOG_ERROR("Error (%i) preparing statement to read text result from database (%s)", result, query.ascii().data()); 100 return false; 101 } 102 103 result = statement.step(); 104 if (result == SQLResultRow) { 105 resultString = statement.getColumnText(0); 106 return true; 107 } 108 if (result == SQLResultDone) { 109 resultString = String(); 110 return true; 111 } 112 113 WTF_LOG_ERROR("Error (%i) reading text result from database (%s)", result, query.ascii().data()); 114 return false; 115 } 116 117 static bool setTextValueInDatabase(SQLiteDatabase& db, const String& query, const String& value) 118 { 119 SQLiteStatement statement(db, query); 120 int result = statement.prepare(); 121 122 if (result != SQLResultOk) { 123 WTF_LOG_ERROR("Failed to prepare statement to set value in database (%s)", query.ascii().data()); 124 return false; 125 } 126 127 statement.bindText(1, value); 128 129 result = statement.step(); 130 if (result != SQLResultDone) { 131 WTF_LOG_ERROR("Failed to step statement to set value in database (%s)", query.ascii().data()); 132 return false; 133 } 134 135 return true; 136 } 137 138 // FIXME: move all guid-related functions to a DatabaseVersionTracker class. 139 static RecursiveMutex& guidMutex() 140 { 141 AtomicallyInitializedStatic(RecursiveMutex&, mutex = *new RecursiveMutex); 142 return mutex; 143 } 144 145 typedef HashMap<DatabaseGuid, String> GuidVersionMap; 146 static GuidVersionMap& guidToVersionMap() 147 { 148 // Ensure the the mutex is locked. 149 ASSERT(guidMutex().locked()); 150 DEFINE_STATIC_LOCAL(GuidVersionMap, map, ()); 151 return map; 152 } 153 154 // NOTE: Caller must lock guidMutex(). 155 static inline void updateGuidVersionMap(DatabaseGuid guid, String newVersion) 156 { 157 // Ensure the the mutex is locked. 158 ASSERT(guidMutex().locked()); 159 160 // Note: It is not safe to put an empty string into the guidToVersionMap() 161 // map. That's because the map is cross-thread, but empty strings are 162 // per-thread. The copy() function makes a version of the string you can 163 // use on the current thread, but we need a string we can keep in a 164 // cross-thread data structure. 165 // FIXME: This is a quite-awkward restriction to have to program with. 166 167 // Map null string to empty string (see comment above). 168 guidToVersionMap().set(guid, newVersion.isEmpty() ? String() : newVersion.isolatedCopy()); 169 } 170 171 typedef HashMap<DatabaseGuid, HashSet<Database*>*> GuidDatabaseMap; 172 static GuidDatabaseMap& guidToDatabaseMap() 173 { 174 // Ensure the the mutex is locked. 175 ASSERT(guidMutex().locked()); 176 DEFINE_STATIC_LOCAL(GuidDatabaseMap, map, ()); 177 return map; 178 } 179 180 static DatabaseGuid guidForOriginAndName(const String& origin, const String& name) 181 { 182 // Ensure the the mutex is locked. 183 ASSERT(guidMutex().locked()); 184 185 String stringID = origin + "/" + name; 186 187 typedef HashMap<String, int> IDGuidMap; 188 DEFINE_STATIC_LOCAL(IDGuidMap, stringIdentifierToGUIDMap, ()); 189 DatabaseGuid guid = stringIdentifierToGUIDMap.get(stringID); 190 if (!guid) { 191 static int currentNewGUID = 1; 192 guid = currentNewGUID++; 193 stringIdentifierToGUIDMap.set(stringID, guid); 194 } 195 196 return guid; 197 } 198 199 Database::Database(DatabaseContext* databaseContext, const String& name, const String& expectedVersion, const String& displayName, unsigned long estimatedSize) 200 : m_databaseContext(databaseContext) 201 , m_name(name.isolatedCopy()) 202 , m_expectedVersion(expectedVersion.isolatedCopy()) 203 , m_displayName(displayName.isolatedCopy()) 204 , m_estimatedSize(estimatedSize) 205 , m_guid(0) 206 , m_opened(false) 207 , m_new(false) 208 , m_transactionInProgress(false) 209 , m_isTransactionQueueEnabled(true) 210 { 211 m_contextThreadSecurityOrigin = m_databaseContext->securityOrigin()->isolatedCopy(); 212 213 m_databaseAuthorizer = DatabaseAuthorizer::create(infoTableName); 214 215 if (m_name.isNull()) 216 m_name = ""; 217 218 { 219 SafePointAwareMutexLocker locker(guidMutex()); 220 m_guid = guidForOriginAndName(securityOrigin()->toString(), name); 221 HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid); 222 if (!hashSet) { 223 hashSet = new HashSet<Database*>; 224 guidToDatabaseMap().set(m_guid, hashSet); 225 } 226 227 hashSet->add(this); 228 } 229 230 m_filename = DatabaseManager::manager().fullPathForDatabase(securityOrigin(), m_name); 231 232 m_databaseThreadSecurityOrigin = m_contextThreadSecurityOrigin->isolatedCopy(); 233 ASSERT(m_databaseContext->databaseThread()); 234 ASSERT(m_databaseContext->isContextThread()); 235 } 236 237 Database::~Database() 238 { 239 // SQLite is "multi-thread safe", but each database handle can only be used 240 // on a single thread at a time. 241 // 242 // For Database, we open the SQLite database on the DatabaseThread, and 243 // hence we should also close it on that same thread. This means that the 244 // SQLite database need to be closed by another mechanism (see 245 // DatabaseContext::stopDatabases()). By the time we get here, the SQLite 246 // database should have already been closed. 247 248 ASSERT(!m_opened); 249 } 250 251 void Database::trace(Visitor* visitor) 252 { 253 visitor->trace(m_databaseContext); 254 visitor->trace(m_sqliteDatabase); 255 visitor->trace(m_databaseAuthorizer); 256 visitor->trace(m_transactionQueue); 257 } 258 259 bool Database::openAndVerifyVersion(bool setVersionInNewDatabase, DatabaseError& error, String& errorMessage) 260 { 261 TaskSynchronizer synchronizer; 262 if (!databaseContext()->databaseThreadAvailable()) 263 return false; 264 265 DatabaseTracker::tracker().prepareToOpenDatabase(this); 266 bool success = false; 267 OwnPtr<DatabaseOpenTask> task = DatabaseOpenTask::create(this, setVersionInNewDatabase, &synchronizer, error, errorMessage, success); 268 databaseContext()->databaseThread()->scheduleTask(task.release()); 269 synchronizer.waitForTaskCompletion(); 270 271 return success; 272 } 273 274 void Database::close() 275 { 276 ASSERT(databaseContext()->databaseThread()); 277 ASSERT(databaseContext()->databaseThread()->isDatabaseThread()); 278 279 { 280 MutexLocker locker(m_transactionInProgressMutex); 281 282 // Clean up transactions that have not been scheduled yet: 283 // Transaction phase 1 cleanup. See comment on "What happens if a 284 // transaction is interrupted?" at the top of SQLTransactionBackend.cpp. 285 RefPtrWillBeRawPtr<SQLTransactionBackend> transaction = nullptr; 286 while (!m_transactionQueue.isEmpty()) { 287 transaction = m_transactionQueue.takeFirst(); 288 transaction->notifyDatabaseThreadIsShuttingDown(); 289 } 290 291 m_isTransactionQueueEnabled = false; 292 m_transactionInProgress = false; 293 } 294 295 closeDatabase(); 296 databaseContext()->databaseThread()->recordDatabaseClosed(this); 297 } 298 299 PassRefPtrWillBeRawPtr<SQLTransactionBackend> Database::runTransaction(PassRefPtrWillBeRawPtr<SQLTransaction> transaction, 300 bool readOnly, const ChangeVersionData* data) 301 { 302 MutexLocker locker(m_transactionInProgressMutex); 303 if (!m_isTransactionQueueEnabled) 304 return nullptr; 305 306 RefPtrWillBeRawPtr<SQLTransactionWrapper> wrapper = nullptr; 307 if (data) 308 wrapper = ChangeVersionWrapper::create(data->oldVersion(), data->newVersion()); 309 310 RefPtrWillBeRawPtr<SQLTransactionBackend> transactionBackend = SQLTransactionBackend::create(this, transaction, wrapper.release(), readOnly); 311 m_transactionQueue.append(transactionBackend); 312 if (!m_transactionInProgress) 313 scheduleTransaction(); 314 315 return transactionBackend; 316 } 317 318 void Database::inProgressTransactionCompleted() 319 { 320 MutexLocker locker(m_transactionInProgressMutex); 321 m_transactionInProgress = false; 322 scheduleTransaction(); 323 } 324 325 void Database::scheduleTransaction() 326 { 327 ASSERT(!m_transactionInProgressMutex.tryLock()); // Locked by caller. 328 RefPtrWillBeRawPtr<SQLTransactionBackend> transaction = nullptr; 329 330 if (m_isTransactionQueueEnabled && !m_transactionQueue.isEmpty()) 331 transaction = m_transactionQueue.takeFirst(); 332 333 if (transaction && databaseContext()->databaseThreadAvailable()) { 334 OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction); 335 WTF_LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for transaction %p\n", task.get(), task->transaction()); 336 m_transactionInProgress = true; 337 databaseContext()->databaseThread()->scheduleTask(task.release()); 338 } else { 339 m_transactionInProgress = false; 340 } 341 } 342 343 void Database::scheduleTransactionStep(SQLTransactionBackend* transaction) 344 { 345 if (!databaseContext()->databaseThreadAvailable()) 346 return; 347 348 OwnPtr<DatabaseTransactionTask> task = DatabaseTransactionTask::create(transaction); 349 WTF_LOG(StorageAPI, "Scheduling DatabaseTransactionTask %p for the transaction step\n", task.get()); 350 databaseContext()->databaseThread()->scheduleTask(task.release()); 351 } 352 353 SQLTransactionClient* Database::transactionClient() const 354 { 355 return databaseContext()->databaseThread()->transactionClient(); 356 } 357 358 SQLTransactionCoordinator* Database::transactionCoordinator() const 359 { 360 return databaseContext()->databaseThread()->transactionCoordinator(); 361 } 362 363 // static 364 const char* Database::databaseInfoTableName() 365 { 366 return infoTableName; 367 } 368 369 void Database::closeDatabase() 370 { 371 if (!m_opened) 372 return; 373 374 m_sqliteDatabase.close(); 375 m_opened = false; 376 // See comment at the top this file regarding calling removeOpenDatabase(). 377 DatabaseTracker::tracker().removeOpenDatabase(this); 378 { 379 SafePointAwareMutexLocker locker(guidMutex()); 380 381 HashSet<Database*>* hashSet = guidToDatabaseMap().get(m_guid); 382 ASSERT(hashSet); 383 ASSERT(hashSet->contains(this)); 384 hashSet->remove(this); 385 if (hashSet->isEmpty()) { 386 guidToDatabaseMap().remove(m_guid); 387 delete hashSet; 388 guidToVersionMap().remove(m_guid); 389 } 390 } 391 } 392 393 String Database::version() const 394 { 395 // Note: In multi-process browsers the cached value may be accurate, but we 396 // cannot read the actual version from the database without potentially 397 // inducing a deadlock. 398 // FIXME: Add an async version getter to the DatabaseAPI. 399 return getCachedVersion(); 400 } 401 402 class DoneCreatingDatabaseOnExitCaller { 403 public: 404 DoneCreatingDatabaseOnExitCaller(Database* database) 405 : m_database(database) 406 , m_openSucceeded(false) 407 { 408 } 409 ~DoneCreatingDatabaseOnExitCaller() 410 { 411 if (!m_openSucceeded) 412 DatabaseTracker::tracker().failedToOpenDatabase(m_database); 413 } 414 415 void setOpenSucceeded() { m_openSucceeded = true; } 416 417 private: 418 Database* m_database; 419 bool m_openSucceeded; 420 }; 421 422 bool Database::performOpenAndVerify(bool shouldSetVersionInNewDatabase, DatabaseError& error, String& errorMessage) 423 { 424 DoneCreatingDatabaseOnExitCaller onExitCaller(this); 425 ASSERT(errorMessage.isEmpty()); 426 ASSERT(error == DatabaseError::None); // Better not have any errors already. 427 // Presumed failure. We'll clear it if we succeed below. 428 error = DatabaseError::InvalidDatabaseState; 429 430 const int maxSqliteBusyWaitTime = 30000; 431 432 if (!m_sqliteDatabase.open(m_filename, true)) { 433 reportOpenDatabaseResult(1, InvalidStateError, m_sqliteDatabase.lastError()); 434 errorMessage = formatErrorMessage("unable to open database", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg()); 435 return false; 436 } 437 if (!m_sqliteDatabase.turnOnIncrementalAutoVacuum()) 438 WTF_LOG_ERROR("Unable to turn on incremental auto-vacuum (%d %s)", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg()); 439 440 m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime); 441 442 String currentVersion; 443 { 444 SafePointAwareMutexLocker locker(guidMutex()); 445 446 GuidVersionMap::iterator entry = guidToVersionMap().find(m_guid); 447 if (entry != guidToVersionMap().end()) { 448 // Map null string to empty string (see updateGuidVersionMap()). 449 currentVersion = entry->value.isNull() ? emptyString() : entry->value.isolatedCopy(); 450 WTF_LOG(StorageAPI, "Current cached version for guid %i is %s", m_guid, currentVersion.ascii().data()); 451 452 // Note: In multi-process browsers the cached value may be 453 // inaccurate, but we cannot read the actual version from the 454 // database without potentially inducing a form of deadlock, a 455 // busytimeout error when trying to access the database. So we'll 456 // use the cached value if we're unable to read the value from the 457 // database file without waiting. 458 // FIXME: Add an async openDatabase method to the DatabaseAPI. 459 const int noSqliteBusyWaitTime = 0; 460 m_sqliteDatabase.setBusyTimeout(noSqliteBusyWaitTime); 461 String versionFromDatabase; 462 if (getVersionFromDatabase(versionFromDatabase, false)) { 463 currentVersion = versionFromDatabase; 464 updateGuidVersionMap(m_guid, currentVersion); 465 } 466 m_sqliteDatabase.setBusyTimeout(maxSqliteBusyWaitTime); 467 } else { 468 WTF_LOG(StorageAPI, "No cached version for guid %i", m_guid); 469 470 SQLiteTransaction transaction(m_sqliteDatabase); 471 transaction.begin(); 472 if (!transaction.inProgress()) { 473 reportOpenDatabaseResult(2, InvalidStateError, m_sqliteDatabase.lastError()); 474 errorMessage = formatErrorMessage("unable to open database, failed to start transaction", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg()); 475 m_sqliteDatabase.close(); 476 return false; 477 } 478 479 String tableName(infoTableName); 480 if (!m_sqliteDatabase.tableExists(tableName)) { 481 m_new = true; 482 483 if (!m_sqliteDatabase.executeCommand("CREATE TABLE " + tableName + " (key TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,value TEXT NOT NULL ON CONFLICT FAIL);")) { 484 reportOpenDatabaseResult(3, InvalidStateError, m_sqliteDatabase.lastError()); 485 errorMessage = formatErrorMessage("unable to open database, failed to create 'info' table", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg()); 486 transaction.rollback(); 487 m_sqliteDatabase.close(); 488 return false; 489 } 490 } else if (!getVersionFromDatabase(currentVersion, false)) { 491 reportOpenDatabaseResult(4, InvalidStateError, m_sqliteDatabase.lastError()); 492 errorMessage = formatErrorMessage("unable to open database, failed to read current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg()); 493 transaction.rollback(); 494 m_sqliteDatabase.close(); 495 return false; 496 } 497 498 if (currentVersion.length()) { 499 WTF_LOG(StorageAPI, "Retrieved current version %s from database %s", currentVersion.ascii().data(), databaseDebugName().ascii().data()); 500 } else if (!m_new || shouldSetVersionInNewDatabase) { 501 WTF_LOG(StorageAPI, "Setting version %s in database %s that was just created", m_expectedVersion.ascii().data(), databaseDebugName().ascii().data()); 502 if (!setVersionInDatabase(m_expectedVersion, false)) { 503 reportOpenDatabaseResult(5, InvalidStateError, m_sqliteDatabase.lastError()); 504 errorMessage = formatErrorMessage("unable to open database, failed to write current version", m_sqliteDatabase.lastError(), m_sqliteDatabase.lastErrorMsg()); 505 transaction.rollback(); 506 m_sqliteDatabase.close(); 507 return false; 508 } 509 currentVersion = m_expectedVersion; 510 } 511 updateGuidVersionMap(m_guid, currentVersion); 512 transaction.commit(); 513 } 514 } 515 516 if (currentVersion.isNull()) { 517 WTF_LOG(StorageAPI, "Database %s does not have its version set", databaseDebugName().ascii().data()); 518 currentVersion = ""; 519 } 520 521 // If the expected version isn't the empty string, ensure that the current 522 // database version we have matches that version. Otherwise, set an 523 // exception. 524 // If the expected version is the empty string, then we always return with 525 // whatever version of the database we have. 526 if ((!m_new || shouldSetVersionInNewDatabase) && m_expectedVersion.length() && m_expectedVersion != currentVersion) { 527 reportOpenDatabaseResult(6, InvalidStateError, 0); 528 errorMessage = "unable to open database, version mismatch, '" + m_expectedVersion + "' does not match the currentVersion of '" + currentVersion + "'"; 529 m_sqliteDatabase.close(); 530 return false; 531 } 532 533 ASSERT(m_databaseAuthorizer); 534 m_sqliteDatabase.setAuthorizer(m_databaseAuthorizer.get()); 535 536 // See comment at the top this file regarding calling addOpenDatabase(). 537 DatabaseTracker::tracker().addOpenDatabase(this); 538 m_opened = true; 539 540 // Declare success: 541 error = DatabaseError::None; // Clear the presumed error from above. 542 onExitCaller.setOpenSucceeded(); 543 544 if (m_new && !shouldSetVersionInNewDatabase) { 545 // The caller provided a creationCallback which will set the expected 546 // version. 547 m_expectedVersion = ""; 548 } 549 550 reportOpenDatabaseResult(0, -1, 0); // OK 551 552 if (databaseContext()->databaseThread()) 553 databaseContext()->databaseThread()->recordDatabaseOpen(this); 554 return true; 555 } 556 557 String Database::stringIdentifier() const 558 { 559 // Return a deep copy for ref counting thread safety 560 return m_name.isolatedCopy(); 561 } 562 563 String Database::displayName() const 564 { 565 // Return a deep copy for ref counting thread safety 566 return m_displayName.isolatedCopy(); 567 } 568 569 unsigned long Database::estimatedSize() const 570 { 571 return m_estimatedSize; 572 } 573 574 String Database::fileName() const 575 { 576 // Return a deep copy for ref counting thread safety 577 return m_filename.isolatedCopy(); 578 } 579 580 bool Database::getVersionFromDatabase(String& version, bool shouldCacheVersion) 581 { 582 String query(String("SELECT value FROM ") + infoTableName + " WHERE key = '" + versionKey + "';"); 583 584 m_databaseAuthorizer->disable(); 585 586 bool result = retrieveTextResultFromDatabase(m_sqliteDatabase, query, version); 587 if (result) { 588 if (shouldCacheVersion) 589 setCachedVersion(version); 590 } else { 591 WTF_LOG_ERROR("Failed to retrieve version from database %s", databaseDebugName().ascii().data()); 592 } 593 594 m_databaseAuthorizer->enable(); 595 596 return result; 597 } 598 599 bool Database::setVersionInDatabase(const String& version, bool shouldCacheVersion) 600 { 601 // The INSERT will replace an existing entry for the database with the new 602 // version number, due to the UNIQUE ON CONFLICT REPLACE clause in the 603 // CREATE statement (see Database::performOpenAndVerify()). 604 String query(String("INSERT INTO ") + infoTableName + " (key, value) VALUES ('" + versionKey + "', ?);"); 605 606 m_databaseAuthorizer->disable(); 607 608 bool result = setTextValueInDatabase(m_sqliteDatabase, query, version); 609 if (result) { 610 if (shouldCacheVersion) 611 setCachedVersion(version); 612 } else { 613 WTF_LOG_ERROR("Failed to set version %s in database (%s)", version.ascii().data(), query.ascii().data()); 614 } 615 616 m_databaseAuthorizer->enable(); 617 618 return result; 619 } 620 621 void Database::setExpectedVersion(const String& version) 622 { 623 m_expectedVersion = version.isolatedCopy(); 624 } 625 626 String Database::getCachedVersion() const 627 { 628 SafePointAwareMutexLocker locker(guidMutex()); 629 return guidToVersionMap().get(m_guid).isolatedCopy(); 630 } 631 632 void Database::setCachedVersion(const String& actualVersion) 633 { 634 // Update the in memory database version map. 635 SafePointAwareMutexLocker locker(guidMutex()); 636 updateGuidVersionMap(m_guid, actualVersion); 637 } 638 639 bool Database::getActualVersionForTransaction(String& actualVersion) 640 { 641 ASSERT(m_sqliteDatabase.transactionInProgress()); 642 // Note: In multi-process browsers the cached value may be inaccurate. So we 643 // retrieve the value from the database and update the cached value here. 644 return getVersionFromDatabase(actualVersion, true); 645 } 646 647 void Database::disableAuthorizer() 648 { 649 ASSERT(m_databaseAuthorizer); 650 m_databaseAuthorizer->disable(); 651 } 652 653 void Database::enableAuthorizer() 654 { 655 ASSERT(m_databaseAuthorizer); 656 m_databaseAuthorizer->enable(); 657 } 658 659 void Database::setAuthorizerPermissions(int permissions) 660 { 661 ASSERT(m_databaseAuthorizer); 662 m_databaseAuthorizer->setPermissions(permissions); 663 } 664 665 bool Database::lastActionChangedDatabase() 666 { 667 ASSERT(m_databaseAuthorizer); 668 return m_databaseAuthorizer->lastActionChangedDatabase(); 669 } 670 671 bool Database::lastActionWasInsert() 672 { 673 ASSERT(m_databaseAuthorizer); 674 return m_databaseAuthorizer->lastActionWasInsert(); 675 } 676 677 void Database::resetDeletes() 678 { 679 ASSERT(m_databaseAuthorizer); 680 m_databaseAuthorizer->resetDeletes(); 681 } 682 683 bool Database::hadDeletes() 684 { 685 ASSERT(m_databaseAuthorizer); 686 return m_databaseAuthorizer->hadDeletes(); 687 } 688 689 void Database::resetAuthorizer() 690 { 691 if (m_databaseAuthorizer) 692 m_databaseAuthorizer->reset(); 693 } 694 695 unsigned long long Database::maximumSize() const 696 { 697 return DatabaseTracker::tracker().getMaxSizeForDatabase(this); 698 } 699 700 void Database::incrementalVacuumIfNeeded() 701 { 702 int64_t freeSpaceSize = m_sqliteDatabase.freeSpaceSize(); 703 int64_t totalSize = m_sqliteDatabase.totalSize(); 704 if (totalSize <= 10 * freeSpaceSize) { 705 int result = m_sqliteDatabase.runIncrementalVacuumCommand(); 706 reportVacuumDatabaseResult(result); 707 if (result != SQLResultOk) 708 logErrorMessage(formatErrorMessage("error vacuuming database", result, m_sqliteDatabase.lastErrorMsg())); 709 } 710 } 711 712 // These are used to generate histograms of errors seen with websql. 713 // See about:histograms in chromium. 714 void Database::reportOpenDatabaseResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode) 715 { 716 if (Platform::current()->databaseObserver()) { 717 Platform::current()->databaseObserver()->reportOpenDatabaseResult( 718 createDatabaseIdentifierFromSecurityOrigin(securityOrigin()), 719 stringIdentifier(), false, 720 errorSite, webSqlErrorCode, sqliteErrorCode); 721 } 722 } 723 724 void Database::reportChangeVersionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode) 725 { 726 if (Platform::current()->databaseObserver()) { 727 Platform::current()->databaseObserver()->reportChangeVersionResult( 728 createDatabaseIdentifierFromSecurityOrigin(securityOrigin()), 729 stringIdentifier(), false, 730 errorSite, webSqlErrorCode, sqliteErrorCode); 731 } 732 } 733 734 void Database::reportStartTransactionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode) 735 { 736 if (Platform::current()->databaseObserver()) { 737 Platform::current()->databaseObserver()->reportStartTransactionResult( 738 createDatabaseIdentifierFromSecurityOrigin(securityOrigin()), 739 stringIdentifier(), false, 740 errorSite, webSqlErrorCode, sqliteErrorCode); 741 } 742 } 743 744 void Database::reportCommitTransactionResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode) 745 { 746 if (Platform::current()->databaseObserver()) { 747 Platform::current()->databaseObserver()->reportCommitTransactionResult( 748 createDatabaseIdentifierFromSecurityOrigin(securityOrigin()), 749 stringIdentifier(), false, 750 errorSite, webSqlErrorCode, sqliteErrorCode); 751 } 752 } 753 754 void Database::reportExecuteStatementResult(int errorSite, int webSqlErrorCode, int sqliteErrorCode) 755 { 756 if (Platform::current()->databaseObserver()) { 757 Platform::current()->databaseObserver()->reportExecuteStatementResult( 758 createDatabaseIdentifierFromSecurityOrigin(securityOrigin()), 759 stringIdentifier(), false, 760 errorSite, webSqlErrorCode, sqliteErrorCode); 761 } 762 } 763 764 void Database::reportVacuumDatabaseResult(int sqliteErrorCode) 765 { 766 if (Platform::current()->databaseObserver()) { 767 Platform::current()->databaseObserver()->reportVacuumDatabaseResult( 768 createDatabaseIdentifierFromSecurityOrigin(securityOrigin()), 769 stringIdentifier(), false, sqliteErrorCode); 770 } 771 } 772 773 void Database::logErrorMessage(const String& message) 774 { 775 executionContext()->addConsoleMessage(ConsoleMessage::create(StorageMessageSource, ErrorMessageLevel, message)); 776 } 777 778 ExecutionContext* Database::executionContext() const 779 { 780 return databaseContext()->executionContext(); 781 } 782 783 void Database::closeImmediately() 784 { 785 ASSERT(executionContext()->isContextThread()); 786 if (databaseContext()->databaseThreadAvailable() && opened()) { 787 logErrorMessage("forcibly closing database"); 788 databaseContext()->databaseThread()->scheduleTask(DatabaseCloseTask::create(this, 0)); 789 } 790 } 791 792 void Database::changeVersion( 793 const String& oldVersion, 794 const String& newVersion, 795 SQLTransactionCallback* callback, 796 SQLTransactionErrorCallback* errorCallback, 797 VoidCallback* successCallback) 798 { 799 ChangeVersionData data(oldVersion, newVersion); 800 runTransaction(callback, errorCallback, successCallback, false, &data); 801 } 802 803 void Database::transaction( 804 SQLTransactionCallback* callback, 805 SQLTransactionErrorCallback* errorCallback, 806 VoidCallback* successCallback) 807 { 808 runTransaction(callback, errorCallback, successCallback, false); 809 } 810 811 void Database::readTransaction( 812 SQLTransactionCallback* callback, 813 SQLTransactionErrorCallback* errorCallback, 814 VoidCallback* successCallback) 815 { 816 runTransaction(callback, errorCallback, successCallback, true); 817 } 818 819 static void callTransactionErrorCallback(ExecutionContext*, SQLTransactionErrorCallback* callback, PassOwnPtr<SQLErrorData> errorData) 820 { 821 RefPtrWillBeRawPtr<SQLError> error = SQLError::create(*errorData); 822 callback->handleEvent(error.get()); 823 } 824 825 void Database::runTransaction( 826 SQLTransactionCallback* callback, 827 SQLTransactionErrorCallback* errorCallback, 828 VoidCallback* successCallback, 829 bool readOnly, 830 const ChangeVersionData* changeVersionData) 831 { 832 // FIXME: Rather than passing errorCallback to SQLTransaction and then 833 // sometimes firing it ourselves, this code should probably be pushed down 834 // into Database so that we only create the SQLTransaction if we're 835 // actually going to run it. 836 #if ENABLE(ASSERT) 837 SQLTransactionErrorCallback* originalErrorCallback = errorCallback; 838 #endif 839 RefPtrWillBeRawPtr<SQLTransaction> transaction = SQLTransaction::create(this, callback, successCallback, errorCallback, readOnly); 840 RefPtrWillBeRawPtr<SQLTransactionBackend> transactionBackend = runTransaction(transaction, readOnly, changeVersionData); 841 if (!transactionBackend) { 842 SQLTransactionErrorCallback* callback = transaction->releaseErrorCallback(); 843 ASSERT(callback == originalErrorCallback); 844 if (callback) { 845 OwnPtr<SQLErrorData> error = SQLErrorData::create(SQLError::UNKNOWN_ERR, "database has been closed"); 846 executionContext()->postTask(createCrossThreadTask(&callTransactionErrorCallback, callback, error.release())); 847 } 848 } 849 } 850 851 // This object is constructed in a database thread, and destructed in the 852 // context thread. 853 class DeliverPendingCallbackTask FINAL : public ExecutionContextTask { 854 public: 855 static PassOwnPtr<DeliverPendingCallbackTask> create(PassRefPtrWillBeRawPtr<SQLTransaction> transaction) 856 { 857 return adoptPtr(new DeliverPendingCallbackTask(transaction)); 858 } 859 860 virtual void performTask(ExecutionContext*) OVERRIDE 861 { 862 m_transaction->performPendingCallback(); 863 } 864 865 private: 866 DeliverPendingCallbackTask(PassRefPtrWillBeRawPtr<SQLTransaction> transaction) 867 : m_transaction(transaction) 868 { 869 } 870 871 RefPtrWillBeCrossThreadPersistent<SQLTransaction> m_transaction; 872 }; 873 874 void Database::scheduleTransactionCallback(SQLTransaction* transaction) 875 { 876 executionContext()->postTask(DeliverPendingCallbackTask::create(transaction)); 877 } 878 879 Vector<String> Database::performGetTableNames() 880 { 881 disableAuthorizer(); 882 883 SQLiteStatement statement(sqliteDatabase(), "SELECT name FROM sqlite_master WHERE type='table';"); 884 if (statement.prepare() != SQLResultOk) { 885 WTF_LOG_ERROR("Unable to retrieve list of tables for database %s", databaseDebugName().ascii().data()); 886 enableAuthorizer(); 887 return Vector<String>(); 888 } 889 890 Vector<String> tableNames; 891 int result; 892 while ((result = statement.step()) == SQLResultRow) { 893 String name = statement.getColumnText(0); 894 if (name != databaseInfoTableName()) 895 tableNames.append(name); 896 } 897 898 enableAuthorizer(); 899 900 if (result != SQLResultDone) { 901 WTF_LOG_ERROR("Error getting tables for database %s", databaseDebugName().ascii().data()); 902 return Vector<String>(); 903 } 904 905 return tableNames; 906 } 907 908 Vector<String> Database::tableNames() 909 { 910 // FIXME: Not using isolatedCopy on these strings looks ok since threads 911 // take strict turns in dealing with them. However, if the code changes, 912 // this may not be true anymore. 913 Vector<String> result; 914 TaskSynchronizer synchronizer; 915 if (!databaseContext()->databaseThreadAvailable()) 916 return result; 917 918 OwnPtr<DatabaseTableNamesTask> task = DatabaseTableNamesTask::create(this, &synchronizer, result); 919 databaseContext()->databaseThread()->scheduleTask(task.release()); 920 synchronizer.waitForTaskCompletion(); 921 922 return result; 923 } 924 925 SecurityOrigin* Database::securityOrigin() const 926 { 927 if (executionContext()->isContextThread()) 928 return m_contextThreadSecurityOrigin.get(); 929 if (databaseContext()->databaseThread()->isDatabaseThread()) 930 return m_databaseThreadSecurityOrigin.get(); 931 return 0; 932 } 933 934 } // namespace blink 935