Chromium Code Reviews| Index: chrome/browser/webdata/web_database.cc |
| diff --git a/chrome/browser/webdata/web_database.cc b/chrome/browser/webdata/web_database.cc |
| index 9d116292e8daf6c7812e7f213c8ec49196150cb3..a469f38c3cd400e6af4c397cc00543a02f3aab3d 100644 |
| --- a/chrome/browser/webdata/web_database.cc |
| +++ b/chrome/browser/webdata/web_database.cc |
| @@ -20,6 +20,7 @@ |
| #include "chrome/browser/autofill/autofill_profile.h" |
| #include "chrome/browser/autofill/autofill_type.h" |
| #include "chrome/browser/autofill/credit_card.h" |
| +#include "chrome/browser/autofill/personal_data_manager.h" |
| #include "chrome/browser/diagnostics/sqlite_diagnostics.h" |
| #include "chrome/browser/history/history_database.h" |
| #include "chrome/browser/password_manager/encryptor.h" |
| @@ -158,6 +159,14 @@ enum AutoFillPhoneType { |
| // of the number. |
| // number |
| // |
| +// autofill_profiles_trash |
| +// This table contains guids of "trashed" autofill |
| +// profiles. When a profile is removed its guid is added |
| +// to this table so that Sync can perform deferred removal. |
| +// |
| +// guid The guid string that identifies the profile to which |
| +// the phone or fax number belongs. |
|
Ilya Sherman
2011/03/16 04:58:57
nit: phone/fax is unrelated ;)
dhollowa
2011/03/16 16:13:35
Done.
|
| +// |
| // credit_cards This table contains credit card data added by the user |
| // with the AutoFill dialog. Most of the columns are |
| // standard entries in a credit card form. |
| @@ -192,8 +201,8 @@ typedef std::vector<Tuple3<int64, string16, string16> > AutofillElementList; |
| // 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|. |
| -const int kCurrentVersionNumber = 35; |
| -const int kCompatibleVersionNumber = 35; |
| +const int kCurrentVersionNumber = 36; |
| +const int kCompatibleVersionNumber = 36; |
| // ID of the url column in keywords. |
| const int kUrlIdPosition = 16; |
| @@ -592,6 +601,13 @@ bool RemoveAutofillProfilePieces(const std::string& guid, sql::Connection* db) { |
| return s3.Run(); |
| } |
| +// TODO(dhollowa): Find a common place for this. It is duplicated in |
| +// personal_data_manager.cc. |
| +template<typename T> |
| +T* address_of(T& v) { |
| + return &v; |
| +} |
| + |
| } // namespace |
| WebDatabase::WebDatabase() { |
| @@ -651,8 +667,8 @@ sql::InitStatus WebDatabase::Init(const FilePath& db_name) { |
| !InitWebAppsTable() || !InitAutofillTable() || |
| !InitAutofillDatesTable() || !InitAutofillProfilesTable() || |
| !InitAutofillProfileNamesTable() || !InitAutofillProfileEmailsTable() || |
| - !InitAutofillProfilePhonesTable() || !InitCreditCardsTable() || |
| - !InitTokenServiceTable()) { |
| + !InitAutofillProfilePhonesTable() || !InitAutofillProfileTrashTable() || |
| + !InitCreditCardsTable() || !InitTokenServiceTable()) { |
| LOG(WARNING) << "Unable to initialize the web database."; |
| return sql::INIT_FAILURE; |
| } |
| @@ -997,6 +1013,17 @@ bool WebDatabase::InitAutofillProfilePhonesTable() { |
| return true; |
| } |
| +bool WebDatabase::InitAutofillProfileTrashTable() { |
| + if (!db_.DoesTableExist("autofill_profiles_trash")) { |
| + if (!db_.Execute("CREATE TABLE autofill_profiles_trash ( " |
| + "guid VARCHAR)")) { |
| + NOTREACHED(); |
| + return false; |
| + } |
| + } |
| + return true; |
| +} |
| + |
| bool WebDatabase::InitCreditCardsTable() { |
| if (!db_.DoesTableExist("credit_cards")) { |
| if (!db_.Execute("CREATE TABLE credit_cards ( " |
| @@ -1847,6 +1874,9 @@ bool WebDatabase::RemoveFormElement(const string16& name, |
| } |
| bool WebDatabase::AddAutofillProfile(const AutofillProfile& profile) { |
| + if (IsAutofillGUIDInTrash(profile.guid())) |
| + return true; |
| + |
| sql::Statement s(db_.GetUniqueStatement( |
| "INSERT INTO autofill_profiles" |
| "(guid, company_name, address_line_1, address_line_2, city, state," |
| @@ -1986,6 +2016,9 @@ bool WebDatabase::GetAutofillProfiles( |
| bool WebDatabase::UpdateAutofillProfile(const AutofillProfile& profile) { |
| DCHECK(guid::IsValidGUID(profile.guid())); |
| + if (IsAutofillGUIDInTrash(profile.guid())) |
| + return true; |
| + |
| AutofillProfile* tmp_profile = NULL; |
| if (!GetAutofillProfile(profile.guid(), &tmp_profile)) |
| return false; |
| @@ -2022,6 +2055,10 @@ bool WebDatabase::UpdateAutofillProfile(const AutofillProfile& profile) { |
| bool WebDatabase::RemoveAutofillProfile(const std::string& guid) { |
| DCHECK(guid::IsValidGUID(guid)); |
| + |
| + if (IsAutofillGUIDInTrash(guid)) |
| + return true; |
|
Ilya Sherman
2011/03/16 04:58:57
Shouldn't we remove the profile from the trash her
dhollowa
2011/03/16 16:13:35
The trash is emptied by the WDS. This should be s
|
| + |
| sql::Statement s(db_.GetUniqueStatement( |
| "DELETE FROM autofill_profiles WHERE guid = ?")); |
| if (!s) { |
| @@ -2036,6 +2073,50 @@ bool WebDatabase::RemoveAutofillProfile(const std::string& guid) { |
| return RemoveAutofillProfilePieces(guid, &db_); |
| } |
| +bool WebDatabase::ClearAutofillProfiles() { |
| + sql::Statement s1(db_.GetUniqueStatement( |
| + "DELETE FROM autofill_profiles")); |
| + if (!s1) { |
| + NOTREACHED() << "Statement prepare failed"; |
| + return false; |
| + } |
| + |
| + if (!s1.Run()) |
| + return false; |
| + |
| + sql::Statement s2(db_.GetUniqueStatement( |
| + "DELETE FROM autofill_profile_names")); |
| + if (!s2) { |
| + NOTREACHED() << "Statement prepare failed"; |
| + return false; |
| + } |
| + |
| + if (!s2.Run()) |
| + return false; |
| + |
| + sql::Statement s3(db_.GetUniqueStatement( |
| + "DELETE FROM autofill_profile_emails")); |
| + if (!s3) { |
| + NOTREACHED() << "Statement prepare failed"; |
| + return false; |
| + } |
| + |
| + if (!s3.Run()) |
| + return false; |
| + |
| + sql::Statement s4(db_.GetUniqueStatement( |
| + "DELETE FROM autofill_profile_phones")); |
| + if (!s4) { |
| + NOTREACHED() << "Statement prepare failed"; |
| + return false; |
| + } |
| + |
| + if (!s4.Run()) |
| + return false; |
| + |
| + return true; |
| +} |
| + |
| bool WebDatabase::AddCreditCard(const CreditCard& credit_card) { |
| sql::Statement s(db_.GetUniqueStatement( |
| "INSERT INTO credit_cards" |
| @@ -2195,6 +2276,36 @@ bool WebDatabase::RemoveAutofillProfilesAndCreditCardsModifiedBetween( |
| return true; |
| } |
| +bool WebDatabase::GetAutofillProfilesInTrash(std::vector<std::string>* guids) { |
| + guids->clear(); |
| + |
| + sql::Statement s(db_.GetUniqueStatement( |
| + "SELECT guid " |
| + "FROM autofill_profiles_trash")); |
| + if (!s) { |
| + NOTREACHED() << "Statement prepare failed"; |
| + return false; |
| + } |
| + |
| + while (s.Step()) { |
| + std::string guid = s.ColumnString(0); |
| + guids->push_back(guid); |
| + } |
| + |
| + return s.Succeeded(); |
| +} |
| + |
| +bool WebDatabase::EmptyAutofillProfilesTrash() { |
| + sql::Statement s(db_.GetUniqueStatement( |
| + "DELETE FROM autofill_profiles_trash")); |
| + if (!s) { |
| + NOTREACHED() << "Statement prepare failed"; |
| + return false; |
| + } |
| + |
| + return s.Run(); |
| +} |
| + |
| bool WebDatabase::AddToCountOfFormElement(int64 pair_id, |
| int delta, |
| bool* was_removed) { |
| @@ -2231,6 +2342,38 @@ bool WebDatabase::RemoveFormElementForID(int64 pair_id) { |
| return false; |
| } |
| +bool WebDatabase::AddAutofillGUIDToTrash(const std::string& guid) { |
| + sql::Statement s(db_.GetUniqueStatement( |
| + "INSERT INTO autofill_profiles_trash" |
| + " (guid) " |
| + "VALUES (?)")); |
| + if (!s) { |
| + NOTREACHED(); |
| + return sql::INIT_FAILURE; |
| + } |
| + |
| + s.BindString(0, guid); |
| + if (!s.Run()) { |
| + NOTREACHED(); |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| +bool WebDatabase::IsAutofillGUIDInTrash(const std::string& guid) { |
| + sql::Statement s(db_.GetUniqueStatement( |
| + "SELECT guid " |
| + "FROM autofill_profiles_trash " |
| + "WHERE guid = ?")); |
| + if (!s) { |
| + NOTREACHED() << "Statement prepare failed"; |
| + return false; |
| + } |
| + |
| + s.BindString(0, guid); |
| + return s.Step(); |
| +} |
| + |
| sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded(){ |
| // Migrate if necessary. |
| int current_version = meta_table_.GetVersionNumber(); |
| @@ -3092,6 +3235,101 @@ sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded(){ |
| // FALL THROUGH |
| + case 35: |
| + // Merge and cull older profiles where possible. |
| + { |
| + sql::Statement s(db_.GetUniqueStatement( |
| + "SELECT guid, date_modified " |
| + "FROM autofill_profiles")); |
| + if (!s) { |
| + NOTREACHED() << "Statement prepare failed"; |
| + return sql::INIT_FAILURE; |
| + } |
| + |
| + // Accumulate the good profiles. |
| + std::vector<AutofillProfile> accumulated_profiles; |
| + std::vector<AutofillProfile*> accumulated_profiles_p; |
| + std::map<std::string, int64> modification_map; |
| + while (s.Step()) { |
| + std::string guid = s.ColumnString(0); |
| + int64 date_modified = s.ColumnInt64(1); |
| + modification_map.insert( |
| + std::pair<std::string, int64>(guid, date_modified)); |
| + AutofillProfile* profile = NULL; |
| + if (!GetAutofillProfile(guid, &profile)) { |
| + NOTREACHED() << "Bad read of profile."; |
| + return sql::INIT_FAILURE; |
| + } |
| + scoped_ptr<AutofillProfile> p(profile); |
| + |
| + if (PersonalDataManager::IsSuitableMergeProfile(*p)) { |
| + std::vector<AutofillProfile> merged_profiles; |
| + bool merged = PersonalDataManager::MergeProfile( |
| + *p, accumulated_profiles_p, &merged_profiles); |
| + |
| + std::swap(accumulated_profiles, merged_profiles); |
| + |
| + accumulated_profiles_p.clear(); |
| + accumulated_profiles_p.resize(accumulated_profiles.size()); |
| + std::transform(accumulated_profiles.begin(), |
| + accumulated_profiles.end(), |
| + accumulated_profiles_p.begin(), |
| + address_of<AutofillProfile>); |
| + |
| + // If the profile got merged trash the original. |
| + if (merged) |
| + AddAutofillGUIDToTrash(p->guid()); |
| + } else { |
| + // An invalid profile, so trash it. |
| + AddAutofillGUIDToTrash(p->guid()); |
| + } |
| + } |
| + |
| + // Drop the current profiles. |
| + if (!ClearAutofillProfiles()) { |
| + LOG(WARNING) << "Unable to update web database to version 36."; |
| + NOTREACHED(); |
| + return sql::INIT_FAILURE; |
| + } |
| + |
| + // Add the newly merged profiles back in. |
| + for (std::vector<AutofillProfile>::const_iterator |
| + iter = accumulated_profiles.begin(); |
| + iter != accumulated_profiles.end(); |
| + ++iter) { |
| + if (!AddAutofillProfile(*iter)) { |
| + LOG(WARNING) << "Unable to update web database to version 36."; |
| + NOTREACHED(); |
| + return sql::INIT_FAILURE; |
| + } |
| + |
| + // Fix up the original modification date. |
| + std::map<std::string, int64>::const_iterator date_item = |
| + modification_map.find(iter->guid()); |
| + if (date_item == modification_map.end()) { |
| + LOG(WARNING) << "Unable to update web database to version 36."; |
| + NOTREACHED(); |
| + return sql::INIT_FAILURE; |
| + } |
| + sql::Statement s_date(db_.GetUniqueStatement( |
| + "UPDATE autofill_profiles SET date_modified=? " |
| + "WHERE guid=?")); |
| + s_date.BindInt64(0, date_item->second); |
| + s_date.BindString(1, iter->guid()); |
| + if (!s_date.Run()) { |
| + LOG(WARNING) << "Unable to update web database to version 36."; |
| + NOTREACHED(); |
| + return sql::INIT_FAILURE; |
| + } |
| + } |
| + } |
| + |
| + meta_table_.SetVersionNumber(36); |
| + meta_table_.SetCompatibleVersionNumber( |
| + std::min(36, kCompatibleVersionNumber)); |
| + |
| + // FALL THROUGH |
| + |
| // Add successive versions here. Each should set the version number and |
| // compatible version number as appropriate, then fall through to the next |
| // case. |