Home | History | Annotate | Download | only in webdata
      1 // Copyright (c) 2011 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 
      5 #include "chrome/browser/webdata/web_database.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "app/sql/statement.h"
     10 #include "app/sql/transaction.h"
     11 #include "chrome/browser/diagnostics/sqlite_diagnostics.h"
     12 #include "content/common/notification_service.h"
     13 
     14 namespace {
     15 
     16 // Current version number.  Note: when changing the current version number,
     17 // corresponding changes must happen in the unit tests, and new migration test
     18 // added.  See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
     19 const int kCurrentVersionNumber = 37;
     20 const int kCompatibleVersionNumber = 37;
     21 
     22 // Change the version number and possibly the compatibility version of
     23 // |meta_table_|.
     24 void ChangeVersion(sql::MetaTable* meta_table,
     25                    int version_num,
     26                    bool update_compatible_version_num) {
     27   meta_table->SetVersionNumber(version_num);
     28   if (update_compatible_version_num) {
     29     meta_table->SetCompatibleVersionNumber(
     30           std::min(version_num, kCompatibleVersionNumber));
     31   }
     32 }
     33 
     34 // Outputs the failed version number as a warning and always returns
     35 // |sql::INIT_FAILURE|.
     36 sql::InitStatus FailedMigrationTo(int version_num) {
     37   LOG(WARNING) << "Unable to update web database to version "
     38                << version_num << ".";
     39   NOTREACHED();
     40   return sql::INIT_FAILURE;
     41 }
     42 
     43 }  // namespace
     44 
     45 WebDatabase::WebDatabase() {}
     46 
     47 WebDatabase::~WebDatabase() {}
     48 
     49 void WebDatabase::BeginTransaction() {
     50   db_.BeginTransaction();
     51 }
     52 
     53 void WebDatabase::CommitTransaction() {
     54   db_.CommitTransaction();
     55 }
     56 
     57 AutofillTable* WebDatabase::GetAutofillTable() {
     58   return autofill_table_.get();
     59 }
     60 
     61 KeywordTable* WebDatabase::GetKeywordTable() {
     62   return keyword_table_.get();
     63 }
     64 
     65 LoginsTable* WebDatabase::GetLoginsTable() {
     66   return logins_table_.get();
     67 }
     68 
     69 TokenServiceTable* WebDatabase::GetTokenServiceTable() {
     70   return token_service_table_.get();
     71 }
     72 
     73 WebAppsTable* WebDatabase::GetWebAppsTable() {
     74   return web_apps_table_.get();
     75 }
     76 
     77 sql::Connection* WebDatabase::GetSQLConnection() {
     78   return &db_;
     79 }
     80 
     81 sql::InitStatus WebDatabase::Init(const FilePath& db_name) {
     82   // When running in unit tests, there is already a NotificationService object.
     83   // Since only one can exist at a time per thread, check first.
     84   if (!NotificationService::current())
     85     notification_service_.reset(new NotificationService);
     86 
     87   // Set the exceptional sqlite error handler.
     88   db_.set_error_delegate(GetErrorHandlerForWebDb());
     89 
     90   // We don't store that much data in the tables so use a small page size.
     91   // This provides a large benefit for empty tables (which is very likely with
     92   // the tables we create).
     93   db_.set_page_size(2048);
     94 
     95   // We shouldn't have much data and what access we currently have is quite
     96   // infrequent. So we go with a small cache size.
     97   db_.set_cache_size(32);
     98 
     99   // Run the database in exclusive mode. Nobody else should be accessing the
    100   // database while we're running, and this will give somewhat improved perf.
    101   db_.set_exclusive_locking();
    102 
    103   if (!db_.Open(db_name))
    104     return sql::INIT_FAILURE;
    105 
    106   // Initialize various tables
    107   sql::Transaction transaction(&db_);
    108   if (!transaction.Begin())
    109     return sql::INIT_FAILURE;
    110 
    111   // Version check.
    112   if (!meta_table_.Init(&db_, kCurrentVersionNumber, kCompatibleVersionNumber))
    113     return sql::INIT_FAILURE;
    114   if (meta_table_.GetCompatibleVersionNumber() > kCurrentVersionNumber) {
    115     LOG(WARNING) << "Web database is too new.";
    116     return sql::INIT_TOO_NEW;
    117   }
    118 
    119   // Create the tables.
    120   autofill_table_.reset(new AutofillTable(&db_, &meta_table_));
    121   keyword_table_.reset(new KeywordTable(&db_, &meta_table_));
    122   logins_table_.reset(new LoginsTable(&db_, &meta_table_));
    123   token_service_table_.reset(new TokenServiceTable(&db_, &meta_table_));
    124   web_apps_table_.reset(new WebAppsTable(&db_, &meta_table_));
    125 
    126   // Initialize the tables.
    127   if (!keyword_table_->Init() || !autofill_table_->Init() ||
    128       !logins_table_->Init() || !web_apps_table_->Init() ||
    129       !token_service_table_->Init()) {
    130     LOG(WARNING) << "Unable to initialize the web database.";
    131     return sql::INIT_FAILURE;
    132   }
    133 
    134   // If the file on disk is an older database version, bring it up to date.
    135   // If the migration fails we return an error to caller and do not commit
    136   // the migration.
    137   sql::InitStatus migration_status = MigrateOldVersionsAsNeeded();
    138   if (migration_status != sql::INIT_OK)
    139     return migration_status;
    140 
    141   return transaction.Commit() ? sql::INIT_OK : sql::INIT_FAILURE;
    142 }
    143 
    144 sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded() {
    145   // Migrate if necessary.
    146   int current_version = meta_table_.GetVersionNumber();
    147   switch (current_version) {
    148     // Versions 1 - 19 are unhandled.  Version numbers greater than
    149     // kCurrentVersionNumber should have already been weeded out by the caller.
    150     default:
    151       // When the version is too old, we return failure error code.  The schema
    152       // is too out of date to migrate.
    153       // There should not be a released product that makes a database too old to
    154       // migrate. If we do encounter such a legacy database, we will need a
    155       // better solution to handle it (i.e., pop up a dialog to tell the user,
    156       // erase all their prefs and start over, etc.).
    157       LOG(WARNING) << "Web database version " << current_version <<
    158           " is too old to handle.";
    159       NOTREACHED();
    160       return sql::INIT_FAILURE;
    161 
    162     case 20:
    163       if (!keyword_table_->MigrateToVersion21AutoGenerateKeywordColumn())
    164         return FailedMigrationTo(21);
    165 
    166       ChangeVersion(&meta_table_, 21, true);
    167       // FALL THROUGH
    168 
    169     case 21:
    170       if (!autofill_table_->ClearAutofillEmptyValueElements())
    171         return FailedMigrationTo(22);
    172 
    173       ChangeVersion(&meta_table_, 22, false);
    174       // FALL THROUGH
    175 
    176     case 22:
    177       if (!autofill_table_->MigrateToVersion23AddCardNumberEncryptedColumn())
    178         return FailedMigrationTo(23);
    179 
    180       ChangeVersion(&meta_table_, 23, false);
    181       // FALL THROUGH
    182 
    183     case 23:
    184       if (!autofill_table_->MigrateToVersion24CleanupOversizedStringFields())
    185         return FailedMigrationTo(24);
    186 
    187       ChangeVersion(&meta_table_, 24, false);
    188       // FALL THROUGH
    189 
    190     case 24:
    191       if (!keyword_table_->MigrateToVersion25AddLogoIDColumn())
    192         return FailedMigrationTo(25);
    193 
    194       ChangeVersion(&meta_table_, 25, true);
    195       // FALL THROUGH
    196 
    197     case 25:
    198       if (!keyword_table_->MigrateToVersion26AddCreatedByPolicyColumn())
    199         return FailedMigrationTo(26);
    200 
    201       ChangeVersion(&meta_table_, 26, true);
    202       // FALL THROUGH
    203 
    204     case 26:
    205       if (!autofill_table_->MigrateToVersion27UpdateLegacyCreditCards())
    206         return FailedMigrationTo(27);
    207 
    208       ChangeVersion(&meta_table_, 27, true);
    209       // FALL THROUGH
    210 
    211     case 27:
    212       if (!keyword_table_->MigrateToVersion28SupportsInstantColumn())
    213         return FailedMigrationTo(28);
    214 
    215       ChangeVersion(&meta_table_, 28, true);
    216       // FALL THROUGH
    217 
    218     case 28:
    219       if (!keyword_table_->MigrateToVersion29InstantUrlToSupportsInstant())
    220         return FailedMigrationTo(29);
    221 
    222       ChangeVersion(&meta_table_, 29, true);
    223       // FALL THROUGH
    224 
    225     case 29:
    226       if (!autofill_table_->MigrateToVersion30AddDateModifed())
    227         return FailedMigrationTo(30);
    228 
    229       ChangeVersion(&meta_table_, 30, true);
    230       // FALL THROUGH
    231 
    232     case 30:
    233       if (!autofill_table_->MigrateToVersion31AddGUIDToCreditCardsAndProfiles())
    234         return FailedMigrationTo(31);
    235 
    236       ChangeVersion(&meta_table_, 31, true);
    237       // FALL THROUGH
    238 
    239     case 31:
    240       if (!autofill_table_->MigrateToVersion32UpdateProfilesAndCreditCards())
    241         return FailedMigrationTo(32);
    242 
    243       ChangeVersion(&meta_table_, 32, true);
    244       // FALL THROUGH
    245 
    246     case 32:
    247       if (!autofill_table_->MigrateToVersion33ProfilesBasedOnFirstName())
    248         return FailedMigrationTo(33);
    249 
    250       ChangeVersion(&meta_table_, 33, true);
    251       // FALL THROUGH
    252 
    253     case 33:
    254       if (!autofill_table_->MigrateToVersion34ProfilesBasedOnCountryCode())
    255         return FailedMigrationTo(34);
    256 
    257       ChangeVersion(&meta_table_, 34, true);
    258       // FALL THROUGH
    259 
    260     case 34:
    261       if (!autofill_table_->MigrateToVersion35GreatBritainCountryCodes())
    262         return FailedMigrationTo(35);
    263 
    264       ChangeVersion(&meta_table_, 35, true);
    265       // FALL THROUGH
    266 
    267     // Combine migrations 35 and 36.  This is due to enhancements to the merge
    268     // step when migrating profiles.  The original migration from 35 to 36 did
    269     // not merge profiles with identical addresses, but the migration from 36 to
    270     // 37 does.  The step from 35 to 36 should only happen on the Chrome 12 dev
    271     // channel.  Chrome 12 beta and release users will jump from 35 to 37
    272     // directly getting the full benefits of the multi-valued merge as well as
    273     // the culling of bad data.
    274     case 35:
    275     case 36:
    276       if (!autofill_table_->MigrateToVersion37MergeAndCullOlderProfiles())
    277         return FailedMigrationTo(37);
    278 
    279       ChangeVersion(&meta_table_, 37, true);
    280       // FALL THROUGH
    281 
    282     // Add successive versions here.  Each should set the version number and
    283     // compatible version number as appropriate, then fall through to the next
    284     // case.
    285 
    286     case kCurrentVersionNumber:
    287       // No migration needed.
    288       return sql::INIT_OK;
    289   }
    290 }
    291