web_database.cc 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. // Copyright (c) 2012 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "components/webdata/common/web_database.h"
  5. #include <algorithm>
  6. #include "base/logging.h"
  7. #include "sql/transaction.h"
  8. // Current version number. Note: when changing the current version number,
  9. // corresponding changes must happen in the unit tests, and new migration test
  10. // added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
  11. // static
  12. const int WebDatabase::kCurrentVersionNumber = 104;
  13. const int WebDatabase::kDeprecatedVersionNumber = 82;
  14. const base::FilePath::CharType WebDatabase::kInMemoryPath[] =
  15. FILE_PATH_LITERAL(":memory");
  16. namespace {
  17. const int kCompatibleVersionNumber = 99;
  18. // Change the version number and possibly the compatibility version of
  19. // |meta_table_|.
  20. void ChangeVersion(sql::MetaTable* meta_table,
  21. int version_num,
  22. bool update_compatible_version_num) {
  23. meta_table->SetVersionNumber(version_num);
  24. if (update_compatible_version_num) {
  25. meta_table->SetCompatibleVersionNumber(
  26. std::min(version_num, kCompatibleVersionNumber));
  27. }
  28. }
  29. // Outputs the failed version number as a warning and always returns
  30. // |sql::INIT_FAILURE|.
  31. sql::InitStatus FailedMigrationTo(int version_num) {
  32. LOG(WARNING) << "Unable to update web database to version " << version_num
  33. << ".";
  34. NOTREACHED();
  35. return sql::INIT_FAILURE;
  36. }
  37. } // namespace
  38. WebDatabase::WebDatabase()
  39. : db_({// Run the database in exclusive mode. Nobody else should be
  40. // accessing the database while we're running, and this will give
  41. // somewhat improved perf.
  42. .exclusive_locking = true,
  43. // We don't store that much data in the tables so use a small page
  44. // size. This provides a large benefit for empty tables (which is
  45. // very likely with the tables we create).
  46. .page_size = 2048,
  47. // We shouldn't have much data and what access we currently have is
  48. // quite infrequent. So we go with a small cache size.
  49. .cache_size = 32}) {}
  50. WebDatabase::~WebDatabase() = default;
  51. void WebDatabase::AddTable(WebDatabaseTable* table) {
  52. tables_[table->GetTypeKey()] = table;
  53. }
  54. WebDatabaseTable* WebDatabase::GetTable(WebDatabaseTable::TypeKey key) {
  55. return tables_[key];
  56. }
  57. void WebDatabase::BeginTransaction() {
  58. db_.BeginTransaction();
  59. }
  60. void WebDatabase::CommitTransaction() {
  61. db_.CommitTransaction();
  62. }
  63. std::string WebDatabase::GetDiagnosticInfo(int extended_error,
  64. sql::Statement* statement) {
  65. return db_.GetDiagnosticInfo(extended_error, statement);
  66. }
  67. sql::Database* WebDatabase::GetSQLConnection() {
  68. return &db_;
  69. }
  70. sql::InitStatus WebDatabase::Init(const base::FilePath& db_name) {
  71. db_.set_histogram_tag("Web");
  72. if ((db_name.value() == kInMemoryPath) ? !db_.OpenInMemory()
  73. : !db_.Open(db_name)) {
  74. return sql::INIT_FAILURE;
  75. }
  76. // Clobber really old databases.
  77. static_assert(kDeprecatedVersionNumber < kCurrentVersionNumber,
  78. "Deprecation version must be less than current");
  79. sql::MetaTable::RazeIfIncompatible(
  80. &db_, /*lowest_supported_version=*/kDeprecatedVersionNumber + 1,
  81. kCurrentVersionNumber);
  82. // Scope initialization in a transaction so we can't be partially
  83. // initialized.
  84. sql::Transaction transaction(&db_);
  85. if (!transaction.Begin())
  86. return sql::INIT_FAILURE;
  87. // Version check.
  88. if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber))
  89. return sql::INIT_FAILURE;
  90. if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
  91. LOG(WARNING) << "Web database is too new.";
  92. return sql::INIT_TOO_NEW;
  93. }
  94. // Initialize the tables.
  95. for (const auto& table : tables_) {
  96. table.second->Init(&db_, &meta_table_);
  97. }
  98. // If the file on disk is an older database version, bring it up to date.
  99. // If the migration fails we return an error to caller and do not commit
  100. // the migration.
  101. sql::InitStatus migration_status = MigrateOldVersionsAsNeeded();
  102. if (migration_status != sql::INIT_OK)
  103. return migration_status;
  104. // Create the desired SQL tables if they do not already exist.
  105. // It's important that this happen *after* the migration code runs.
  106. // Otherwise, the migration code would have to explicitly check for empty
  107. // tables created in the new format, and skip the migration in that case.
  108. for (const auto& table : tables_) {
  109. if (!table.second->CreateTablesIfNecessary()) {
  110. LOG(WARNING) << "Unable to initialize the web database.";
  111. return sql::INIT_FAILURE;
  112. }
  113. }
  114. return transaction.Commit() ? sql::INIT_OK : sql::INIT_FAILURE;
  115. }
  116. sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded() {
  117. // Some malware used to lower the version number, causing migration to
  118. // fail. Ensure the version number is at least as high as the compatible
  119. // version number.
  120. int current_version = std::max(meta_table_.GetVersionNumber(),
  121. meta_table_.GetCompatibleVersionNumber());
  122. if (current_version > meta_table_.GetVersionNumber())
  123. ChangeVersion(&meta_table_, current_version, false);
  124. DCHECK_GT(current_version, kDeprecatedVersionNumber);
  125. for (int next_version = current_version + 1;
  126. next_version <= kCurrentVersionNumber; ++next_version) {
  127. // Do any database-wide migrations.
  128. bool update_compatible_version = false;
  129. if (!MigrateToVersion(next_version, &update_compatible_version))
  130. return FailedMigrationTo(next_version);
  131. ChangeVersion(&meta_table_, next_version, update_compatible_version);
  132. // Give each table a chance to migrate to this version.
  133. for (const auto& table : tables_) {
  134. // Any of the tables may set this to true, but by default it is false.
  135. update_compatible_version = false;
  136. if (!table.second->MigrateToVersion(next_version,
  137. &update_compatible_version)) {
  138. return FailedMigrationTo(next_version);
  139. }
  140. ChangeVersion(&meta_table_, next_version, update_compatible_version);
  141. }
  142. }
  143. return sql::INIT_OK;
  144. }
  145. bool WebDatabase::MigrateToVersion(int version,
  146. bool* update_compatible_version) {
  147. // Migrate if necessary.
  148. switch (version) {
  149. case 58:
  150. *update_compatible_version = true;
  151. return MigrateToVersion58DropWebAppsAndIntents();
  152. case 79:
  153. *update_compatible_version = true;
  154. return MigrateToVersion79DropLoginsTable();
  155. }
  156. return true;
  157. }
  158. bool WebDatabase::MigrateToVersion58DropWebAppsAndIntents() {
  159. sql::Transaction transaction(&db_);
  160. return transaction.Begin() && db_.Execute("DROP TABLE IF EXISTS web_apps") &&
  161. db_.Execute("DROP TABLE IF EXISTS web_app_icons") &&
  162. db_.Execute("DROP TABLE IF EXISTS web_intents") &&
  163. db_.Execute("DROP TABLE IF EXISTS web_intents_defaults") &&
  164. transaction.Commit();
  165. }
  166. bool WebDatabase::MigrateToVersion79DropLoginsTable() {
  167. sql::Transaction transaction(&db_);
  168. return transaction.Begin() &&
  169. db_.Execute("DROP TABLE IF EXISTS ie7_logins") &&
  170. db_.Execute("DROP TABLE IF EXISTS logins") && transaction.Commit();
  171. }