123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- // Copyright (c) 2012 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "components/webdata/common/web_database.h"
- #include <algorithm>
- #include "base/logging.h"
- #include "sql/transaction.h"
- // Current version number. Note: when changing the current version number,
- // corresponding changes must happen in the unit tests, and new migration test
- // added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
- // static
- const int WebDatabase::kCurrentVersionNumber = 104;
- const int WebDatabase::kDeprecatedVersionNumber = 82;
- const base::FilePath::CharType WebDatabase::kInMemoryPath[] =
- FILE_PATH_LITERAL(":memory");
- namespace {
- const int kCompatibleVersionNumber = 99;
- // Change the version number and possibly the compatibility version of
- // |meta_table_|.
- void ChangeVersion(sql::MetaTable* meta_table,
- int version_num,
- bool update_compatible_version_num) {
- meta_table->SetVersionNumber(version_num);
- if (update_compatible_version_num) {
- meta_table->SetCompatibleVersionNumber(
- std::min(version_num, kCompatibleVersionNumber));
- }
- }
- // Outputs the failed version number as a warning and always returns
- // |sql::INIT_FAILURE|.
- sql::InitStatus FailedMigrationTo(int version_num) {
- LOG(WARNING) << "Unable to update web database to version " << version_num
- << ".";
- NOTREACHED();
- return sql::INIT_FAILURE;
- }
- } // namespace
- WebDatabase::WebDatabase()
- : db_({// Run the database in exclusive mode. Nobody else should be
- // accessing the database while we're running, and this will give
- // somewhat improved perf.
- .exclusive_locking = true,
- // We don't store that much data in the tables so use a small page
- // size. This provides a large benefit for empty tables (which is
- // very likely with the tables we create).
- .page_size = 2048,
- // We shouldn't have much data and what access we currently have is
- // quite infrequent. So we go with a small cache size.
- .cache_size = 32}) {}
- WebDatabase::~WebDatabase() = default;
- void WebDatabase::AddTable(WebDatabaseTable* table) {
- tables_[table->GetTypeKey()] = table;
- }
- WebDatabaseTable* WebDatabase::GetTable(WebDatabaseTable::TypeKey key) {
- return tables_[key];
- }
- void WebDatabase::BeginTransaction() {
- db_.BeginTransaction();
- }
- void WebDatabase::CommitTransaction() {
- db_.CommitTransaction();
- }
- std::string WebDatabase::GetDiagnosticInfo(int extended_error,
- sql::Statement* statement) {
- return db_.GetDiagnosticInfo(extended_error, statement);
- }
- sql::Database* WebDatabase::GetSQLConnection() {
- return &db_;
- }
- sql::InitStatus WebDatabase::Init(const base::FilePath& db_name) {
- db_.set_histogram_tag("Web");
- if ((db_name.value() == kInMemoryPath) ? !db_.OpenInMemory()
- : !db_.Open(db_name)) {
- return sql::INIT_FAILURE;
- }
- // Clobber really old databases.
- static_assert(kDeprecatedVersionNumber < kCurrentVersionNumber,
- "Deprecation version must be less than current");
- sql::MetaTable::RazeIfIncompatible(
- &db_, /*lowest_supported_version=*/kDeprecatedVersionNumber + 1,
- kCurrentVersionNumber);
- // Scope initialization in a transaction so we can't be partially
- // initialized.
- sql::Transaction transaction(&db_);
- if (!transaction.Begin())
- return sql::INIT_FAILURE;
- // Version check.
- if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber))
- return sql::INIT_FAILURE;
- if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
- LOG(WARNING) << "Web database is too new.";
- return sql::INIT_TOO_NEW;
- }
- // Initialize the tables.
- for (const auto& table : tables_) {
- table.second->Init(&db_, &meta_table_);
- }
- // If the file on disk is an older database version, bring it up to date.
- // If the migration fails we return an error to caller and do not commit
- // the migration.
- sql::InitStatus migration_status = MigrateOldVersionsAsNeeded();
- if (migration_status != sql::INIT_OK)
- return migration_status;
- // Create the desired SQL tables if they do not already exist.
- // It's important that this happen *after* the migration code runs.
- // Otherwise, the migration code would have to explicitly check for empty
- // tables created in the new format, and skip the migration in that case.
- for (const auto& table : tables_) {
- if (!table.second->CreateTablesIfNecessary()) {
- LOG(WARNING) << "Unable to initialize the web database.";
- return sql::INIT_FAILURE;
- }
- }
- return transaction.Commit() ? sql::INIT_OK : sql::INIT_FAILURE;
- }
- sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded() {
- // Some malware used to lower the version number, causing migration to
- // fail. Ensure the version number is at least as high as the compatible
- // version number.
- int current_version = std::max(meta_table_.GetVersionNumber(),
- meta_table_.GetCompatibleVersionNumber());
- if (current_version > meta_table_.GetVersionNumber())
- ChangeVersion(&meta_table_, current_version, false);
- DCHECK_GT(current_version, kDeprecatedVersionNumber);
- for (int next_version = current_version + 1;
- next_version <= kCurrentVersionNumber; ++next_version) {
- // Do any database-wide migrations.
- bool update_compatible_version = false;
- if (!MigrateToVersion(next_version, &update_compatible_version))
- return FailedMigrationTo(next_version);
- ChangeVersion(&meta_table_, next_version, update_compatible_version);
- // Give each table a chance to migrate to this version.
- for (const auto& table : tables_) {
- // Any of the tables may set this to true, but by default it is false.
- update_compatible_version = false;
- if (!table.second->MigrateToVersion(next_version,
- &update_compatible_version)) {
- return FailedMigrationTo(next_version);
- }
- ChangeVersion(&meta_table_, next_version, update_compatible_version);
- }
- }
- return sql::INIT_OK;
- }
- bool WebDatabase::MigrateToVersion(int version,
- bool* update_compatible_version) {
- // Migrate if necessary.
- switch (version) {
- case 58:
- *update_compatible_version = true;
- return MigrateToVersion58DropWebAppsAndIntents();
- case 79:
- *update_compatible_version = true;
- return MigrateToVersion79DropLoginsTable();
- }
- return true;
- }
- bool WebDatabase::MigrateToVersion58DropWebAppsAndIntents() {
- sql::Transaction transaction(&db_);
- return transaction.Begin() && db_.Execute("DROP TABLE IF EXISTS web_apps") &&
- db_.Execute("DROP TABLE IF EXISTS web_app_icons") &&
- db_.Execute("DROP TABLE IF EXISTS web_intents") &&
- db_.Execute("DROP TABLE IF EXISTS web_intents_defaults") &&
- transaction.Commit();
- }
- bool WebDatabase::MigrateToVersion79DropLoginsTable() {
- sql::Transaction transaction(&db_);
- return transaction.Begin() &&
- db_.Execute("DROP TABLE IF EXISTS ie7_logins") &&
- db_.Execute("DROP TABLE IF EXISTS logins") && transaction.Commit();
- }
|