| OLD | NEW |
| (Empty) |
| 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 | |
| 5 #include "chrome/browser/webdata/autofill_table.h" | |
| 6 | |
| 7 #include <algorithm> | |
| 8 #include <limits> | |
| 9 #include <map> | |
| 10 #include <set> | |
| 11 #include <string> | |
| 12 #include <vector> | |
| 13 | |
| 14 #include "base/guid.h" | |
| 15 #include "base/i18n/case_conversion.h" | |
| 16 #include "base/logging.h" | |
| 17 #include "base/strings/string_number_conversions.h" | |
| 18 #include "base/time.h" | |
| 19 #include "base/tuple.h" | |
| 20 #include "chrome/browser/webdata/autofill_change.h" | |
| 21 #include "chrome/browser/webdata/autofill_entry.h" | |
| 22 #include "chrome/browser/webdata/web_database.h" | |
| 23 #include "components/autofill/browser/autofill_country.h" | |
| 24 #include "components/autofill/browser/autofill_profile.h" | |
| 25 #include "components/autofill/browser/autofill_type.h" | |
| 26 #include "components/autofill/browser/credit_card.h" | |
| 27 #include "components/autofill/browser/personal_data_manager.h" | |
| 28 #include "components/autofill/common/form_field_data.h" | |
| 29 #include "components/webdata/encryptor/encryptor.h" | |
| 30 #include "sql/statement.h" | |
| 31 #include "ui/base/l10n/l10n_util.h" | |
| 32 | |
| 33 using base::Time; | |
| 34 | |
| 35 namespace { | |
| 36 | |
| 37 typedef std::vector<Tuple3<int64, string16, string16> > AutofillElementList; | |
| 38 | |
| 39 // TODO(dhollowa): Find a common place for this. It is duplicated in | |
| 40 // personal_data_manager.cc. | |
| 41 template<typename T> | |
| 42 T* address_of(T& v) { | |
| 43 return &v; | |
| 44 } | |
| 45 | |
| 46 string16 LimitDataSize(const string16& data) { | |
| 47 if (data.size() > AutofillTable::kMaxDataLength) | |
| 48 return data.substr(0, AutofillTable::kMaxDataLength); | |
| 49 | |
| 50 return data; | |
| 51 } | |
| 52 | |
| 53 void BindAutofillProfileToStatement(const AutofillProfile& profile, | |
| 54 sql::Statement* s) { | |
| 55 DCHECK(base::IsValidGUID(profile.guid())); | |
| 56 s->BindString(0, profile.guid()); | |
| 57 | |
| 58 string16 text = profile.GetRawInfo(COMPANY_NAME); | |
| 59 s->BindString16(1, LimitDataSize(text)); | |
| 60 text = profile.GetRawInfo(ADDRESS_HOME_LINE1); | |
| 61 s->BindString16(2, LimitDataSize(text)); | |
| 62 text = profile.GetRawInfo(ADDRESS_HOME_LINE2); | |
| 63 s->BindString16(3, LimitDataSize(text)); | |
| 64 text = profile.GetRawInfo(ADDRESS_HOME_CITY); | |
| 65 s->BindString16(4, LimitDataSize(text)); | |
| 66 text = profile.GetRawInfo(ADDRESS_HOME_STATE); | |
| 67 s->BindString16(5, LimitDataSize(text)); | |
| 68 text = profile.GetRawInfo(ADDRESS_HOME_ZIP); | |
| 69 s->BindString16(6, LimitDataSize(text)); | |
| 70 text = profile.GetRawInfo(ADDRESS_HOME_COUNTRY); | |
| 71 s->BindString16(7, LimitDataSize(text)); | |
| 72 std::string country_code = profile.CountryCode(); | |
| 73 s->BindString(8, country_code); | |
| 74 s->BindInt64(9, Time::Now().ToTimeT()); | |
| 75 } | |
| 76 | |
| 77 AutofillProfile* AutofillProfileFromStatement(const sql::Statement& s) { | |
| 78 AutofillProfile* profile = new AutofillProfile; | |
| 79 profile->set_guid(s.ColumnString(0)); | |
| 80 DCHECK(base::IsValidGUID(profile->guid())); | |
| 81 | |
| 82 profile->SetRawInfo(COMPANY_NAME, s.ColumnString16(1)); | |
| 83 profile->SetRawInfo(ADDRESS_HOME_LINE1, s.ColumnString16(2)); | |
| 84 profile->SetRawInfo(ADDRESS_HOME_LINE2, s.ColumnString16(3)); | |
| 85 profile->SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(4)); | |
| 86 profile->SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(5)); | |
| 87 profile->SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(6)); | |
| 88 // Intentionally skip column 7, which stores the localized country name. | |
| 89 profile->SetCountryCode(s.ColumnString(8)); | |
| 90 // Intentionally skip column 9, which stores the profile's modification date. | |
| 91 | |
| 92 return profile; | |
| 93 } | |
| 94 | |
| 95 void BindCreditCardToStatement(const CreditCard& credit_card, | |
| 96 sql::Statement* s) { | |
| 97 DCHECK(base::IsValidGUID(credit_card.guid())); | |
| 98 s->BindString(0, credit_card.guid()); | |
| 99 | |
| 100 string16 text = credit_card.GetRawInfo(CREDIT_CARD_NAME); | |
| 101 s->BindString16(1, LimitDataSize(text)); | |
| 102 text = credit_card.GetRawInfo(CREDIT_CARD_EXP_MONTH); | |
| 103 s->BindString16(2, LimitDataSize(text)); | |
| 104 text = credit_card.GetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR); | |
| 105 s->BindString16(3, LimitDataSize(text)); | |
| 106 text = credit_card.GetRawInfo(CREDIT_CARD_NUMBER); | |
| 107 std::string encrypted_data; | |
| 108 Encryptor::EncryptString16(text, &encrypted_data); | |
| 109 s->BindBlob(4, encrypted_data.data(), | |
| 110 static_cast<int>(encrypted_data.length())); | |
| 111 s->BindInt64(5, Time::Now().ToTimeT()); | |
| 112 } | |
| 113 | |
| 114 CreditCard* CreditCardFromStatement(const sql::Statement& s) { | |
| 115 CreditCard* credit_card = new CreditCard; | |
| 116 | |
| 117 credit_card->set_guid(s.ColumnString(0)); | |
| 118 DCHECK(base::IsValidGUID(credit_card->guid())); | |
| 119 | |
| 120 credit_card->SetRawInfo(CREDIT_CARD_NAME, s.ColumnString16(1)); | |
| 121 credit_card->SetRawInfo(CREDIT_CARD_EXP_MONTH, s.ColumnString16(2)); | |
| 122 credit_card->SetRawInfo(CREDIT_CARD_EXP_4_DIGIT_YEAR, s.ColumnString16(3)); | |
| 123 int encrypted_number_len = s.ColumnByteLength(4); | |
| 124 string16 credit_card_number; | |
| 125 if (encrypted_number_len) { | |
| 126 std::string encrypted_number; | |
| 127 encrypted_number.resize(encrypted_number_len); | |
| 128 memcpy(&encrypted_number[0], s.ColumnBlob(4), encrypted_number_len); | |
| 129 Encryptor::DecryptString16(encrypted_number, &credit_card_number); | |
| 130 } | |
| 131 credit_card->SetRawInfo(CREDIT_CARD_NUMBER, credit_card_number); | |
| 132 // Intentionally skip column 5, which stores the modification date. | |
| 133 | |
| 134 return credit_card; | |
| 135 } | |
| 136 | |
| 137 bool AddAutofillProfileNamesToProfile(sql::Connection* db, | |
| 138 AutofillProfile* profile) { | |
| 139 sql::Statement s(db->GetUniqueStatement( | |
| 140 "SELECT guid, first_name, middle_name, last_name " | |
| 141 "FROM autofill_profile_names " | |
| 142 "WHERE guid=?")); | |
| 143 s.BindString(0, profile->guid()); | |
| 144 | |
| 145 if (!s.is_valid()) | |
| 146 return false; | |
| 147 | |
| 148 std::vector<string16> first_names; | |
| 149 std::vector<string16> middle_names; | |
| 150 std::vector<string16> last_names; | |
| 151 while (s.Step()) { | |
| 152 DCHECK_EQ(profile->guid(), s.ColumnString(0)); | |
| 153 first_names.push_back(s.ColumnString16(1)); | |
| 154 middle_names.push_back(s.ColumnString16(2)); | |
| 155 last_names.push_back(s.ColumnString16(3)); | |
| 156 } | |
| 157 if (!s.Succeeded()) | |
| 158 return false; | |
| 159 | |
| 160 profile->SetRawMultiInfo(NAME_FIRST, first_names); | |
| 161 profile->SetRawMultiInfo(NAME_MIDDLE, middle_names); | |
| 162 profile->SetRawMultiInfo(NAME_LAST, last_names); | |
| 163 return true; | |
| 164 } | |
| 165 | |
| 166 bool AddAutofillProfileEmailsToProfile(sql::Connection* db, | |
| 167 AutofillProfile* profile) { | |
| 168 sql::Statement s(db->GetUniqueStatement( | |
| 169 "SELECT guid, email " | |
| 170 "FROM autofill_profile_emails " | |
| 171 "WHERE guid=?")); | |
| 172 s.BindString(0, profile->guid()); | |
| 173 | |
| 174 if (!s.is_valid()) | |
| 175 return false; | |
| 176 | |
| 177 std::vector<string16> emails; | |
| 178 while (s.Step()) { | |
| 179 DCHECK_EQ(profile->guid(), s.ColumnString(0)); | |
| 180 emails.push_back(s.ColumnString16(1)); | |
| 181 } | |
| 182 if (!s.Succeeded()) | |
| 183 return false; | |
| 184 | |
| 185 profile->SetRawMultiInfo(EMAIL_ADDRESS, emails); | |
| 186 return true; | |
| 187 } | |
| 188 | |
| 189 bool AddAutofillProfilePhonesToProfile(sql::Connection* db, | |
| 190 AutofillProfile* profile) { | |
| 191 sql::Statement s(db->GetUniqueStatement( | |
| 192 "SELECT guid, type, number " | |
| 193 "FROM autofill_profile_phones " | |
| 194 "WHERE guid=? AND type=?")); | |
| 195 | |
| 196 // Value used to be either [(0, phone), (1, fax)] but fax has been removed. | |
| 197 s.BindString(0, profile->guid()); | |
| 198 s.BindInt(1, 0); | |
| 199 | |
| 200 if (!s.is_valid()) | |
| 201 return false; | |
| 202 | |
| 203 std::vector<string16> numbers; | |
| 204 while (s.Step()) { | |
| 205 DCHECK_EQ(profile->guid(), s.ColumnString(0)); | |
| 206 numbers.push_back(s.ColumnString16(2)); | |
| 207 } | |
| 208 if (!s.Succeeded()) | |
| 209 return false; | |
| 210 | |
| 211 profile->SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, numbers); | |
| 212 return true; | |
| 213 } | |
| 214 | |
| 215 bool AddAutofillProfileNames(const AutofillProfile& profile, | |
| 216 sql::Connection* db) { | |
| 217 std::vector<string16> first_names; | |
| 218 profile.GetRawMultiInfo(NAME_FIRST, &first_names); | |
| 219 std::vector<string16> middle_names; | |
| 220 profile.GetRawMultiInfo(NAME_MIDDLE, &middle_names); | |
| 221 std::vector<string16> last_names; | |
| 222 profile.GetRawMultiInfo(NAME_LAST, &last_names); | |
| 223 DCHECK_EQ(first_names.size(), middle_names.size()); | |
| 224 DCHECK_EQ(middle_names.size(), last_names.size()); | |
| 225 | |
| 226 for (size_t i = 0; i < first_names.size(); ++i) { | |
| 227 // Add the new name. | |
| 228 sql::Statement s(db->GetUniqueStatement( | |
| 229 "INSERT INTO autofill_profile_names" | |
| 230 " (guid, first_name, middle_name, last_name) " | |
| 231 "VALUES (?,?,?,?)")); | |
| 232 s.BindString(0, profile.guid()); | |
| 233 s.BindString16(1, first_names[i]); | |
| 234 s.BindString16(2, middle_names[i]); | |
| 235 s.BindString16(3, last_names[i]); | |
| 236 | |
| 237 if (!s.Run()) | |
| 238 return false; | |
| 239 } | |
| 240 return true; | |
| 241 } | |
| 242 | |
| 243 bool AddAutofillProfileEmails(const AutofillProfile& profile, | |
| 244 sql::Connection* db) { | |
| 245 std::vector<string16> emails; | |
| 246 profile.GetRawMultiInfo(EMAIL_ADDRESS, &emails); | |
| 247 | |
| 248 for (size_t i = 0; i < emails.size(); ++i) { | |
| 249 // Add the new email. | |
| 250 sql::Statement s(db->GetUniqueStatement( | |
| 251 "INSERT INTO autofill_profile_emails" | |
| 252 " (guid, email) " | |
| 253 "VALUES (?,?)")); | |
| 254 s.BindString(0, profile.guid()); | |
| 255 s.BindString16(1, emails[i]); | |
| 256 | |
| 257 if (!s.Run()) | |
| 258 return false; | |
| 259 } | |
| 260 | |
| 261 return true; | |
| 262 } | |
| 263 | |
| 264 bool AddAutofillProfilePhones(const AutofillProfile& profile, | |
| 265 sql::Connection* db) { | |
| 266 std::vector<string16> numbers; | |
| 267 profile.GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &numbers); | |
| 268 | |
| 269 for (size_t i = 0; i < numbers.size(); ++i) { | |
| 270 // Add the new number. | |
| 271 sql::Statement s(db->GetUniqueStatement( | |
| 272 "INSERT INTO autofill_profile_phones" | |
| 273 " (guid, type, number) " | |
| 274 "VALUES (?,?,?)")); | |
| 275 s.BindString(0, profile.guid()); | |
| 276 // Value used to be either [(0, phone), (1, fax)] but fax has been removed. | |
| 277 s.BindInt(1, 0); | |
| 278 s.BindString16(2, numbers[i]); | |
| 279 | |
| 280 if (!s.Run()) | |
| 281 return false; | |
| 282 } | |
| 283 | |
| 284 return true; | |
| 285 } | |
| 286 | |
| 287 bool AddAutofillProfilePieces(const AutofillProfile& profile, | |
| 288 sql::Connection* db) { | |
| 289 if (!AddAutofillProfileNames(profile, db)) | |
| 290 return false; | |
| 291 | |
| 292 if (!AddAutofillProfileEmails(profile, db)) | |
| 293 return false; | |
| 294 | |
| 295 if (!AddAutofillProfilePhones(profile, db)) | |
| 296 return false; | |
| 297 | |
| 298 return true; | |
| 299 } | |
| 300 | |
| 301 bool RemoveAutofillProfilePieces(const std::string& guid, sql::Connection* db) { | |
| 302 sql::Statement s1(db->GetUniqueStatement( | |
| 303 "DELETE FROM autofill_profile_names WHERE guid = ?")); | |
| 304 s1.BindString(0, guid); | |
| 305 | |
| 306 if (!s1.Run()) | |
| 307 return false; | |
| 308 | |
| 309 sql::Statement s2(db->GetUniqueStatement( | |
| 310 "DELETE FROM autofill_profile_emails WHERE guid = ?")); | |
| 311 s2.BindString(0, guid); | |
| 312 | |
| 313 if (!s2.Run()) | |
| 314 return false; | |
| 315 | |
| 316 sql::Statement s3(db->GetUniqueStatement( | |
| 317 "DELETE FROM autofill_profile_phones WHERE guid = ?")); | |
| 318 s3.BindString(0, guid); | |
| 319 | |
| 320 return s3.Run(); | |
| 321 } | |
| 322 | |
| 323 int table_key = 0; | |
| 324 | |
| 325 WebDatabaseTable::TypeKey GetKey() { | |
| 326 return reinterpret_cast<void*>(&table_key); | |
| 327 } | |
| 328 | |
| 329 } // namespace | |
| 330 | |
| 331 // The maximum length allowed for form data. | |
| 332 const size_t AutofillTable::kMaxDataLength = 1024; | |
| 333 | |
| 334 AutofillTable::AutofillTable() | |
| 335 : app_locale_(AutofillCountry::ApplicationLocale()) { | |
| 336 } | |
| 337 | |
| 338 AutofillTable::~AutofillTable() { | |
| 339 } | |
| 340 | |
| 341 AutofillTable* AutofillTable::FromWebDatabase(WebDatabase* db) { | |
| 342 return static_cast<AutofillTable*>(db->GetTable(GetKey())); | |
| 343 } | |
| 344 | |
| 345 WebDatabaseTable::TypeKey AutofillTable::GetTypeKey() const { | |
| 346 return GetKey(); | |
| 347 } | |
| 348 | |
| 349 bool AutofillTable::Init(sql::Connection* db, sql::MetaTable* meta_table) { | |
| 350 WebDatabaseTable::Init(db, meta_table); | |
| 351 return (InitMainTable() && InitCreditCardsTable() && InitDatesTable() && | |
| 352 InitProfilesTable() && InitProfileNamesTable() && | |
| 353 InitProfileEmailsTable() && InitProfilePhonesTable() && | |
| 354 InitProfileTrashTable()); | |
| 355 } | |
| 356 | |
| 357 bool AutofillTable::IsSyncable() { | |
| 358 return true; | |
| 359 } | |
| 360 | |
| 361 bool AutofillTable::MigrateToVersion(int version, | |
| 362 bool* update_compatible_version) { | |
| 363 // Migrate if necessary. | |
| 364 switch (version) { | |
| 365 case 22: | |
| 366 return ClearAutofillEmptyValueElements(); | |
| 367 case 23: | |
| 368 return MigrateToVersion23AddCardNumberEncryptedColumn(); | |
| 369 case 24: | |
| 370 return MigrateToVersion24CleanupOversizedStringFields(); | |
| 371 case 27: | |
| 372 *update_compatible_version = true; | |
| 373 return MigrateToVersion27UpdateLegacyCreditCards(); | |
| 374 case 30: | |
| 375 *update_compatible_version = true; | |
| 376 return MigrateToVersion30AddDateModifed(); | |
| 377 case 31: | |
| 378 *update_compatible_version = true; | |
| 379 return MigrateToVersion31AddGUIDToCreditCardsAndProfiles(); | |
| 380 case 32: | |
| 381 *update_compatible_version = true; | |
| 382 return MigrateToVersion32UpdateProfilesAndCreditCards(); | |
| 383 case 33: | |
| 384 *update_compatible_version = true; | |
| 385 return MigrateToVersion33ProfilesBasedOnFirstName(); | |
| 386 case 34: | |
| 387 *update_compatible_version = true; | |
| 388 return MigrateToVersion34ProfilesBasedOnCountryCode(); | |
| 389 case 35: | |
| 390 *update_compatible_version = true; | |
| 391 return MigrateToVersion35GreatBritainCountryCodes(); | |
| 392 // Combine migrations 36 and 37. This is due to enhancements to the merge | |
| 393 // step when migrating profiles. The original migration from 35 to 36 did | |
| 394 // not merge profiles with identical addresses, but the migration from 36 to | |
| 395 // 37 does. The step from 35 to 36 should only happen on the Chrome 12 dev | |
| 396 // channel. Chrome 12 beta and release users will jump from 35 to 37 | |
| 397 // directly getting the full benefits of the multi-valued merge as well as | |
| 398 // the culling of bad data. | |
| 399 case 37: | |
| 400 *update_compatible_version = true; | |
| 401 return MigrateToVersion37MergeAndCullOlderProfiles(); | |
| 402 } | |
| 403 return true; | |
| 404 } | |
| 405 | |
| 406 bool AutofillTable::AddFormFieldValues( | |
| 407 const std::vector<FormFieldData>& elements, | |
| 408 std::vector<AutofillChange>* changes) { | |
| 409 return AddFormFieldValuesTime(elements, changes, Time::Now()); | |
| 410 } | |
| 411 | |
| 412 bool AutofillTable::AddFormFieldValue(const FormFieldData& element, | |
| 413 std::vector<AutofillChange>* changes) { | |
| 414 return AddFormFieldValueTime(element, changes, Time::Now()); | |
| 415 } | |
| 416 | |
| 417 bool AutofillTable::GetFormValuesForElementName(const string16& name, | |
| 418 const string16& prefix, | |
| 419 std::vector<string16>* values, | |
| 420 int limit) { | |
| 421 DCHECK(values); | |
| 422 sql::Statement s; | |
| 423 | |
| 424 if (prefix.empty()) { | |
| 425 s.Assign(db_->GetUniqueStatement( | |
| 426 "SELECT value FROM autofill " | |
| 427 "WHERE name = ? " | |
| 428 "ORDER BY count DESC " | |
| 429 "LIMIT ?")); | |
| 430 s.BindString16(0, name); | |
| 431 s.BindInt(1, limit); | |
| 432 } else { | |
| 433 string16 prefix_lower = base::i18n::ToLower(prefix); | |
| 434 string16 next_prefix = prefix_lower; | |
| 435 next_prefix[next_prefix.length() - 1]++; | |
| 436 | |
| 437 s.Assign(db_->GetUniqueStatement( | |
| 438 "SELECT value FROM autofill " | |
| 439 "WHERE name = ? AND " | |
| 440 "value_lower >= ? AND " | |
| 441 "value_lower < ? " | |
| 442 "ORDER BY count DESC " | |
| 443 "LIMIT ?")); | |
| 444 s.BindString16(0, name); | |
| 445 s.BindString16(1, prefix_lower); | |
| 446 s.BindString16(2, next_prefix); | |
| 447 s.BindInt(3, limit); | |
| 448 } | |
| 449 | |
| 450 values->clear(); | |
| 451 while (s.Step()) | |
| 452 values->push_back(s.ColumnString16(0)); | |
| 453 return s.Succeeded(); | |
| 454 } | |
| 455 | |
| 456 bool AutofillTable::RemoveFormElementsAddedBetween( | |
| 457 const Time& delete_begin, | |
| 458 const Time& delete_end, | |
| 459 std::vector<AutofillChange>* changes) { | |
| 460 DCHECK(changes); | |
| 461 // Query for the pair_id, name, and value of all form elements that | |
| 462 // were used between the given times. | |
| 463 sql::Statement s(db_->GetUniqueStatement( | |
| 464 "SELECT DISTINCT a.pair_id, a.name, a.value " | |
| 465 "FROM autofill_dates ad JOIN autofill a ON ad.pair_id = a.pair_id " | |
| 466 "WHERE ad.date_created >= ? AND ad.date_created < ?")); | |
| 467 s.BindInt64(0, delete_begin.ToTimeT()); | |
| 468 s.BindInt64(1, | |
| 469 (delete_end.is_null() || delete_end == base::Time::Max()) ? | |
| 470 std::numeric_limits<int64>::max() : | |
| 471 delete_end.ToTimeT()); | |
| 472 | |
| 473 AutofillElementList elements; | |
| 474 while (s.Step()) { | |
| 475 elements.push_back(MakeTuple(s.ColumnInt64(0), | |
| 476 s.ColumnString16(1), | |
| 477 s.ColumnString16(2))); | |
| 478 } | |
| 479 if (!s.Succeeded()) | |
| 480 return false; | |
| 481 | |
| 482 for (AutofillElementList::iterator itr = elements.begin(); | |
| 483 itr != elements.end(); ++itr) { | |
| 484 int how_many = 0; | |
| 485 if (!RemoveFormElementForTimeRange(itr->a, delete_begin, delete_end, | |
| 486 &how_many)) { | |
| 487 return false; | |
| 488 } | |
| 489 // We store at most 2 time stamps. If we remove both of them we should | |
| 490 // delete the corresponding data. If we delete only one it could still be | |
| 491 // the last timestamp for the data, so check how many timestamps do remain. | |
| 492 bool should_remove = (CountTimestampsData(itr->a) == 0); | |
| 493 if (should_remove) { | |
| 494 if (!RemoveFormElementForID(itr->a)) | |
| 495 return false; | |
| 496 } else { | |
| 497 if (!AddToCountOfFormElement(itr->a, -how_many)) | |
| 498 return false; | |
| 499 } | |
| 500 AutofillChange::Type change_type = | |
| 501 should_remove ? AutofillChange::REMOVE : AutofillChange::UPDATE; | |
| 502 changes->push_back(AutofillChange(change_type, | |
| 503 AutofillKey(itr->b, itr->c))); | |
| 504 } | |
| 505 | |
| 506 return true; | |
| 507 } | |
| 508 | |
| 509 bool AutofillTable::RemoveExpiredFormElements( | |
| 510 std::vector<AutofillChange>* changes) { | |
| 511 DCHECK(changes); | |
| 512 | |
| 513 base::Time delete_end = AutofillEntry::ExpirationTime(); | |
| 514 // Query for the pair_id, name, and value of all form elements that | |
| 515 // were last used before the |delete_end|. | |
| 516 sql::Statement select_for_delete(db_->GetUniqueStatement( | |
| 517 "SELECT DISTINCT pair_id, name, value " | |
| 518 "FROM autofill WHERE pair_id NOT IN " | |
| 519 "(SELECT DISTINCT pair_id " | |
| 520 "FROM autofill_dates WHERE date_created >= ?)")); | |
| 521 select_for_delete.BindInt64(0, delete_end.ToTimeT()); | |
| 522 AutofillElementList entries_to_delete; | |
| 523 while (select_for_delete.Step()) { | |
| 524 entries_to_delete.push_back(MakeTuple(select_for_delete.ColumnInt64(0), | |
| 525 select_for_delete.ColumnString16(1), | |
| 526 select_for_delete.ColumnString16(2))); | |
| 527 } | |
| 528 | |
| 529 if (!select_for_delete.Succeeded()) | |
| 530 return false; | |
| 531 | |
| 532 sql::Statement delete_data_statement(db_->GetUniqueStatement( | |
| 533 "DELETE FROM autofill WHERE pair_id NOT IN (" | |
| 534 "SELECT pair_id FROM autofill_dates WHERE date_created >= ?)")); | |
| 535 delete_data_statement.BindInt64(0, delete_end.ToTimeT()); | |
| 536 if (!delete_data_statement.Run()) | |
| 537 return false; | |
| 538 | |
| 539 sql::Statement delete_times_statement(db_->GetUniqueStatement( | |
| 540 "DELETE FROM autofill_dates WHERE pair_id NOT IN (" | |
| 541 "SELECT pair_id FROM autofill_dates WHERE date_created >= ?)")); | |
| 542 delete_times_statement.BindInt64(0, delete_end.ToTimeT()); | |
| 543 if (!delete_times_statement.Run()) | |
| 544 return false; | |
| 545 | |
| 546 // Cull remaining entries' timestamps. | |
| 547 std::vector<AutofillEntry> entries; | |
| 548 if (!GetAllAutofillEntries(&entries)) | |
| 549 return false; | |
| 550 sql::Statement cull_date_entry(db_->GetUniqueStatement( | |
| 551 "DELETE FROM autofill_dates " | |
| 552 "WHERE pair_id == (SELECT pair_id FROM autofill " | |
| 553 "WHERE name = ? and value = ?)" | |
| 554 "AND date_created != ? AND date_created != ?")); | |
| 555 for (size_t i = 0; i < entries.size(); ++i) { | |
| 556 cull_date_entry.BindString16(0, entries[i].key().name()); | |
| 557 cull_date_entry.BindString16(1, entries[i].key().value()); | |
| 558 cull_date_entry.BindInt64(2, | |
| 559 entries[i].timestamps().empty() ? 0 : | |
| 560 entries[i].timestamps().front().ToTimeT()); | |
| 561 cull_date_entry.BindInt64(3, | |
| 562 entries[i].timestamps().empty() ? 0 : | |
| 563 entries[i].timestamps().back().ToTimeT()); | |
| 564 if (!cull_date_entry.Run()) | |
| 565 return false; | |
| 566 cull_date_entry.Reset(true); | |
| 567 } | |
| 568 | |
| 569 changes->clear(); | |
| 570 changes->reserve(entries_to_delete.size()); | |
| 571 | |
| 572 for (AutofillElementList::iterator it = entries_to_delete.begin(); | |
| 573 it != entries_to_delete.end(); ++it) { | |
| 574 changes->push_back(AutofillChange( | |
| 575 AutofillChange::REMOVE, AutofillKey(it->b, it->c))); | |
| 576 } | |
| 577 return true; | |
| 578 } | |
| 579 | |
| 580 bool AutofillTable::RemoveFormElementForTimeRange(int64 pair_id, | |
| 581 const Time& delete_begin, | |
| 582 const Time& delete_end, | |
| 583 int* how_many) { | |
| 584 sql::Statement s(db_->GetUniqueStatement( | |
| 585 "DELETE FROM autofill_dates WHERE pair_id = ? AND " | |
| 586 "date_created >= ? AND date_created < ?")); | |
| 587 s.BindInt64(0, pair_id); | |
| 588 s.BindInt64(1, delete_begin.is_null() ? 0 : delete_begin.ToTimeT()); | |
| 589 s.BindInt64(2, delete_end.is_null() ? std::numeric_limits<int64>::max() : | |
| 590 delete_end.ToTimeT()); | |
| 591 | |
| 592 bool result = s.Run(); | |
| 593 if (how_many) | |
| 594 *how_many = db_->GetLastChangeCount(); | |
| 595 | |
| 596 return result; | |
| 597 } | |
| 598 | |
| 599 int AutofillTable::CountTimestampsData(int64 pair_id) { | |
| 600 sql::Statement s(db_->GetUniqueStatement( | |
| 601 "SELECT COUNT(*) FROM autofill_dates WHERE pair_id = ?")); | |
| 602 s.BindInt64(0, pair_id); | |
| 603 if (!s.Step()) { | |
| 604 NOTREACHED(); | |
| 605 return 0; | |
| 606 } else { | |
| 607 return s.ColumnInt(0); | |
| 608 } | |
| 609 } | |
| 610 | |
| 611 bool AutofillTable::AddToCountOfFormElement(int64 pair_id, | |
| 612 int delta) { | |
| 613 int count = 0; | |
| 614 | |
| 615 if (!GetCountOfFormElement(pair_id, &count)) | |
| 616 return false; | |
| 617 | |
| 618 if (count + delta == 0) { | |
| 619 // Should remove the element earlier in the code. | |
| 620 NOTREACHED(); | |
| 621 return false; | |
| 622 } else { | |
| 623 if (!SetCountOfFormElement(pair_id, count + delta)) | |
| 624 return false; | |
| 625 } | |
| 626 return true; | |
| 627 } | |
| 628 | |
| 629 bool AutofillTable::GetIDAndCountOfFormElement( | |
| 630 const FormFieldData& element, | |
| 631 int64* pair_id, | |
| 632 int* count) { | |
| 633 DCHECK(pair_id); | |
| 634 DCHECK(count); | |
| 635 | |
| 636 sql::Statement s(db_->GetUniqueStatement( | |
| 637 "SELECT pair_id, count FROM autofill " | |
| 638 "WHERE name = ? AND value = ?")); | |
| 639 s.BindString16(0, element.name); | |
| 640 s.BindString16(1, element.value); | |
| 641 | |
| 642 if (!s.is_valid()) | |
| 643 return false; | |
| 644 | |
| 645 *pair_id = 0; | |
| 646 *count = 0; | |
| 647 | |
| 648 if (s.Step()) { | |
| 649 *pair_id = s.ColumnInt64(0); | |
| 650 *count = s.ColumnInt(1); | |
| 651 } | |
| 652 | |
| 653 return true; | |
| 654 } | |
| 655 | |
| 656 bool AutofillTable::GetCountOfFormElement(int64 pair_id, int* count) { | |
| 657 DCHECK(count); | |
| 658 sql::Statement s(db_->GetUniqueStatement( | |
| 659 "SELECT count FROM autofill WHERE pair_id = ?")); | |
| 660 s.BindInt64(0, pair_id); | |
| 661 | |
| 662 if (s.Step()) { | |
| 663 *count = s.ColumnInt(0); | |
| 664 return true; | |
| 665 } | |
| 666 return false; | |
| 667 } | |
| 668 | |
| 669 bool AutofillTable::SetCountOfFormElement(int64 pair_id, int count) { | |
| 670 sql::Statement s(db_->GetUniqueStatement( | |
| 671 "UPDATE autofill SET count = ? WHERE pair_id = ?")); | |
| 672 s.BindInt(0, count); | |
| 673 s.BindInt64(1, pair_id); | |
| 674 | |
| 675 return s.Run(); | |
| 676 } | |
| 677 | |
| 678 bool AutofillTable::InsertFormElement(const FormFieldData& element, | |
| 679 int64* pair_id) { | |
| 680 DCHECK(pair_id); | |
| 681 sql::Statement s(db_->GetUniqueStatement( | |
| 682 "INSERT INTO autofill (name, value, value_lower) VALUES (?,?,?)")); | |
| 683 s.BindString16(0, element.name); | |
| 684 s.BindString16(1, element.value); | |
| 685 s.BindString16(2, base::i18n::ToLower(element.value)); | |
| 686 | |
| 687 if (!s.Run()) | |
| 688 return false; | |
| 689 | |
| 690 *pair_id = db_->GetLastInsertRowId(); | |
| 691 return true; | |
| 692 } | |
| 693 | |
| 694 bool AutofillTable::InsertPairIDAndDate(int64 pair_id, | |
| 695 const Time& date_created) { | |
| 696 sql::Statement s(db_->GetUniqueStatement( | |
| 697 "INSERT INTO autofill_dates " | |
| 698 "(pair_id, date_created) VALUES (?, ?)")); | |
| 699 s.BindInt64(0, pair_id); | |
| 700 s.BindInt64(1, date_created.ToTimeT()); | |
| 701 | |
| 702 return s.Run(); | |
| 703 } | |
| 704 | |
| 705 bool AutofillTable::DeleteLastAccess(int64 pair_id) { | |
| 706 // Inner SELECT selects the newest |date_created| for a given |pair_id|. | |
| 707 // DELETE deletes only that entry. | |
| 708 sql::Statement s(db_->GetUniqueStatement( | |
| 709 "DELETE FROM autofill_dates WHERE pair_id = ? and date_created IN " | |
| 710 "(SELECT date_created FROM autofill_dates WHERE pair_id = ? " | |
| 711 "ORDER BY date_created DESC LIMIT 1)")); | |
| 712 s.BindInt64(0, pair_id); | |
| 713 s.BindInt64(1, pair_id); | |
| 714 | |
| 715 return s.Run(); | |
| 716 } | |
| 717 | |
| 718 bool AutofillTable::AddFormFieldValuesTime( | |
| 719 const std::vector<FormFieldData>& elements, | |
| 720 std::vector<AutofillChange>* changes, | |
| 721 Time time) { | |
| 722 // Only add one new entry for each unique element name. Use |seen_names| to | |
| 723 // track this. Add up to |kMaximumUniqueNames| unique entries per form. | |
| 724 const size_t kMaximumUniqueNames = 256; | |
| 725 std::set<string16> seen_names; | |
| 726 bool result = true; | |
| 727 for (std::vector<FormFieldData>::const_iterator itr = elements.begin(); | |
| 728 itr != elements.end(); ++itr) { | |
| 729 if (seen_names.size() >= kMaximumUniqueNames) | |
| 730 break; | |
| 731 if (seen_names.find(itr->name) != seen_names.end()) | |
| 732 continue; | |
| 733 result = result && AddFormFieldValueTime(*itr, changes, time); | |
| 734 seen_names.insert(itr->name); | |
| 735 } | |
| 736 return result; | |
| 737 } | |
| 738 | |
| 739 bool AutofillTable::ClearAutofillEmptyValueElements() { | |
| 740 sql::Statement s(db_->GetUniqueStatement( | |
| 741 "SELECT pair_id FROM autofill WHERE TRIM(value)= \"\"")); | |
| 742 if (!s.is_valid()) | |
| 743 return false; | |
| 744 | |
| 745 std::set<int64> ids; | |
| 746 while (s.Step()) | |
| 747 ids.insert(s.ColumnInt64(0)); | |
| 748 if (!s.Succeeded()) | |
| 749 return false; | |
| 750 | |
| 751 bool success = true; | |
| 752 for (std::set<int64>::const_iterator iter = ids.begin(); iter != ids.end(); | |
| 753 ++iter) { | |
| 754 if (!RemoveFormElementForID(*iter)) | |
| 755 success = false; | |
| 756 } | |
| 757 | |
| 758 return success; | |
| 759 } | |
| 760 | |
| 761 bool AutofillTable::GetAllAutofillEntries(std::vector<AutofillEntry>* entries) { | |
| 762 DCHECK(entries); | |
| 763 sql::Statement s(db_->GetUniqueStatement( | |
| 764 "SELECT name, value, date_created FROM autofill a JOIN " | |
| 765 "autofill_dates ad ON a.pair_id=ad.pair_id")); | |
| 766 | |
| 767 bool first_entry = true; | |
| 768 AutofillKey* current_key_ptr = NULL; | |
| 769 std::vector<Time>* timestamps_ptr = NULL; | |
| 770 string16 name, value; | |
| 771 Time time; | |
| 772 while (s.Step()) { | |
| 773 name = s.ColumnString16(0); | |
| 774 value = s.ColumnString16(1); | |
| 775 time = Time::FromTimeT(s.ColumnInt64(2)); | |
| 776 | |
| 777 if (first_entry) { | |
| 778 current_key_ptr = new AutofillKey(name, value); | |
| 779 | |
| 780 timestamps_ptr = new std::vector<Time>; | |
| 781 timestamps_ptr->push_back(time); | |
| 782 | |
| 783 first_entry = false; | |
| 784 } else { | |
| 785 // we've encountered the next entry | |
| 786 if (current_key_ptr->name().compare(name) != 0 || | |
| 787 current_key_ptr->value().compare(value) != 0) { | |
| 788 AutofillEntry entry(*current_key_ptr, *timestamps_ptr); | |
| 789 entries->push_back(entry); | |
| 790 | |
| 791 delete current_key_ptr; | |
| 792 delete timestamps_ptr; | |
| 793 | |
| 794 current_key_ptr = new AutofillKey(name, value); | |
| 795 timestamps_ptr = new std::vector<Time>; | |
| 796 } | |
| 797 timestamps_ptr->push_back(time); | |
| 798 } | |
| 799 } | |
| 800 | |
| 801 // If there is at least one result returned, first_entry will be false. | |
| 802 // For this case we need to do a final cleanup step. | |
| 803 if (!first_entry) { | |
| 804 AutofillEntry entry(*current_key_ptr, *timestamps_ptr); | |
| 805 entries->push_back(entry); | |
| 806 delete current_key_ptr; | |
| 807 delete timestamps_ptr; | |
| 808 } | |
| 809 | |
| 810 return s.Succeeded(); | |
| 811 } | |
| 812 | |
| 813 bool AutofillTable::GetAutofillTimestamps(const string16& name, | |
| 814 const string16& value, | |
| 815 std::vector<Time>* timestamps) { | |
| 816 DCHECK(timestamps); | |
| 817 sql::Statement s(db_->GetUniqueStatement( | |
| 818 "SELECT date_created FROM autofill a JOIN " | |
| 819 "autofill_dates ad ON a.pair_id=ad.pair_id " | |
| 820 "WHERE a.name = ? AND a.value = ?")); | |
| 821 s.BindString16(0, name); | |
| 822 s.BindString16(1, value); | |
| 823 | |
| 824 while (s.Step()) | |
| 825 timestamps->push_back(Time::FromTimeT(s.ColumnInt64(0))); | |
| 826 | |
| 827 return s.Succeeded(); | |
| 828 } | |
| 829 | |
| 830 bool AutofillTable::UpdateAutofillEntries( | |
| 831 const std::vector<AutofillEntry>& entries) { | |
| 832 if (!entries.size()) | |
| 833 return true; | |
| 834 | |
| 835 // Remove all existing entries. | |
| 836 for (size_t i = 0; i < entries.size(); i++) { | |
| 837 std::string sql = "SELECT pair_id FROM autofill " | |
| 838 "WHERE name = ? AND value = ?"; | |
| 839 sql::Statement s(db_->GetUniqueStatement(sql.c_str())); | |
| 840 s.BindString16(0, entries[i].key().name()); | |
| 841 s.BindString16(1, entries[i].key().value()); | |
| 842 | |
| 843 if (!s.is_valid()) | |
| 844 return false; | |
| 845 | |
| 846 if (s.Step()) { | |
| 847 if (!RemoveFormElementForID(s.ColumnInt64(0))) | |
| 848 return false; | |
| 849 } | |
| 850 } | |
| 851 | |
| 852 // Insert all the supplied autofill entries. | |
| 853 for (size_t i = 0; i < entries.size(); i++) { | |
| 854 if (!InsertAutofillEntry(entries[i])) | |
| 855 return false; | |
| 856 } | |
| 857 | |
| 858 return true; | |
| 859 } | |
| 860 | |
| 861 bool AutofillTable::InsertAutofillEntry(const AutofillEntry& entry) { | |
| 862 std::string sql = "INSERT INTO autofill (name, value, value_lower, count) " | |
| 863 "VALUES (?, ?, ?, ?)"; | |
| 864 sql::Statement s(db_->GetUniqueStatement(sql.c_str())); | |
| 865 s.BindString16(0, entry.key().name()); | |
| 866 s.BindString16(1, entry.key().value()); | |
| 867 s.BindString16(2, base::i18n::ToLower(entry.key().value())); | |
| 868 s.BindInt(3, entry.timestamps().size()); | |
| 869 | |
| 870 if (!s.Run()) | |
| 871 return false; | |
| 872 | |
| 873 int64 pair_id = db_->GetLastInsertRowId(); | |
| 874 for (size_t i = 0; i < entry.timestamps().size(); i++) { | |
| 875 if (!InsertPairIDAndDate(pair_id, entry.timestamps()[i])) | |
| 876 return false; | |
| 877 } | |
| 878 | |
| 879 return true; | |
| 880 } | |
| 881 | |
| 882 bool AutofillTable::AddFormFieldValueTime(const FormFieldData& element, | |
| 883 std::vector<AutofillChange>* changes, | |
| 884 Time time) { | |
| 885 int count = 0; | |
| 886 int64 pair_id; | |
| 887 | |
| 888 if (!GetIDAndCountOfFormElement(element, &pair_id, &count)) | |
| 889 return false; | |
| 890 | |
| 891 if (count == 0 && !InsertFormElement(element, &pair_id)) | |
| 892 return false; | |
| 893 | |
| 894 if (!SetCountOfFormElement(pair_id, count + 1)) | |
| 895 return false; | |
| 896 | |
| 897 // If we already have more than 2 times delete last one, before adding new | |
| 898 // one. | |
| 899 if (count >= 2 && !DeleteLastAccess(pair_id)) | |
| 900 return false; | |
| 901 | |
| 902 if (!InsertPairIDAndDate(pair_id, time)) | |
| 903 return false; | |
| 904 | |
| 905 AutofillChange::Type change_type = | |
| 906 count == 0 ? AutofillChange::ADD : AutofillChange::UPDATE; | |
| 907 changes->push_back( | |
| 908 AutofillChange(change_type, | |
| 909 AutofillKey(element.name, element.value))); | |
| 910 return true; | |
| 911 } | |
| 912 | |
| 913 | |
| 914 bool AutofillTable::RemoveFormElement(const string16& name, | |
| 915 const string16& value) { | |
| 916 // Find the id for that pair. | |
| 917 sql::Statement s(db_->GetUniqueStatement( | |
| 918 "SELECT pair_id FROM autofill WHERE name = ? AND value= ?")); | |
| 919 s.BindString16(0, name); | |
| 920 s.BindString16(1, value); | |
| 921 | |
| 922 if (s.Step()) | |
| 923 return RemoveFormElementForID(s.ColumnInt64(0)); | |
| 924 return false; | |
| 925 } | |
| 926 | |
| 927 bool AutofillTable::AddAutofillProfile(const AutofillProfile& profile) { | |
| 928 if (IsAutofillGUIDInTrash(profile.guid())) | |
| 929 return true; | |
| 930 | |
| 931 sql::Statement s(db_->GetUniqueStatement( | |
| 932 "INSERT INTO autofill_profiles" | |
| 933 "(guid, company_name, address_line_1, address_line_2, city, state," | |
| 934 " zipcode, country, country_code, date_modified)" | |
| 935 "VALUES (?,?,?,?,?,?,?,?,?,?)")); | |
| 936 BindAutofillProfileToStatement(profile, &s); | |
| 937 | |
| 938 if (!s.Run()) | |
| 939 return false; | |
| 940 | |
| 941 return AddAutofillProfilePieces(profile, db_); | |
| 942 } | |
| 943 | |
| 944 bool AutofillTable::GetAutofillProfile(const std::string& guid, | |
| 945 AutofillProfile** profile) { | |
| 946 DCHECK(base::IsValidGUID(guid)); | |
| 947 DCHECK(profile); | |
| 948 sql::Statement s(db_->GetUniqueStatement( | |
| 949 "SELECT guid, company_name, address_line_1, address_line_2, city, state," | |
| 950 " zipcode, country, country_code, date_modified " | |
| 951 "FROM autofill_profiles " | |
| 952 "WHERE guid=?")); | |
| 953 s.BindString(0, guid); | |
| 954 | |
| 955 if (!s.Step()) | |
| 956 return false; | |
| 957 | |
| 958 scoped_ptr<AutofillProfile> p(AutofillProfileFromStatement(s)); | |
| 959 | |
| 960 // Get associated name info. | |
| 961 AddAutofillProfileNamesToProfile(db_, p.get()); | |
| 962 | |
| 963 // Get associated email info. | |
| 964 AddAutofillProfileEmailsToProfile(db_, p.get()); | |
| 965 | |
| 966 // Get associated phone info. | |
| 967 AddAutofillProfilePhonesToProfile(db_, p.get()); | |
| 968 | |
| 969 *profile = p.release(); | |
| 970 return true; | |
| 971 } | |
| 972 | |
| 973 bool AutofillTable::GetAutofillProfiles( | |
| 974 std::vector<AutofillProfile*>* profiles) { | |
| 975 DCHECK(profiles); | |
| 976 profiles->clear(); | |
| 977 | |
| 978 sql::Statement s(db_->GetUniqueStatement( | |
| 979 "SELECT guid " | |
| 980 "FROM autofill_profiles")); | |
| 981 | |
| 982 while (s.Step()) { | |
| 983 std::string guid = s.ColumnString(0); | |
| 984 AutofillProfile* profile = NULL; | |
| 985 if (!GetAutofillProfile(guid, &profile)) | |
| 986 return false; | |
| 987 profiles->push_back(profile); | |
| 988 } | |
| 989 | |
| 990 return s.Succeeded(); | |
| 991 } | |
| 992 | |
| 993 bool AutofillTable::UpdateAutofillProfile(const AutofillProfile& profile) { | |
| 994 DCHECK(base::IsValidGUID(profile.guid())); | |
| 995 | |
| 996 // Don't update anything until the trash has been emptied. There may be | |
| 997 // pending modifications to process. | |
| 998 if (!IsAutofillProfilesTrashEmpty()) | |
| 999 return true; | |
| 1000 | |
| 1001 AutofillProfile* tmp_profile = NULL; | |
| 1002 if (!GetAutofillProfile(profile.guid(), &tmp_profile)) | |
| 1003 return false; | |
| 1004 | |
| 1005 // Preserve appropriate modification dates by not updating unchanged profiles. | |
| 1006 scoped_ptr<AutofillProfile> old_profile(tmp_profile); | |
| 1007 if (old_profile->Compare(profile) == 0) | |
| 1008 return true; | |
| 1009 | |
| 1010 AutofillProfile new_profile(profile); | |
| 1011 std::vector<string16> values; | |
| 1012 | |
| 1013 old_profile->GetRawMultiInfo(NAME_FULL, &values); | |
| 1014 values[0] = new_profile.GetRawInfo(NAME_FULL); | |
| 1015 new_profile.SetRawMultiInfo(NAME_FULL, values); | |
| 1016 | |
| 1017 old_profile->GetRawMultiInfo(EMAIL_ADDRESS, &values); | |
| 1018 values[0] = new_profile.GetRawInfo(EMAIL_ADDRESS); | |
| 1019 new_profile.SetRawMultiInfo(EMAIL_ADDRESS, values); | |
| 1020 | |
| 1021 old_profile->GetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, &values); | |
| 1022 values[0] = new_profile.GetRawInfo(PHONE_HOME_WHOLE_NUMBER); | |
| 1023 new_profile.SetRawMultiInfo(PHONE_HOME_WHOLE_NUMBER, values); | |
| 1024 | |
| 1025 return UpdateAutofillProfileMulti(new_profile); | |
| 1026 } | |
| 1027 | |
| 1028 bool AutofillTable::UpdateAutofillProfileMulti(const AutofillProfile& profile) { | |
| 1029 DCHECK(base::IsValidGUID(profile.guid())); | |
| 1030 | |
| 1031 // Don't update anything until the trash has been emptied. There may be | |
| 1032 // pending modifications to process. | |
| 1033 if (!IsAutofillProfilesTrashEmpty()) | |
| 1034 return true; | |
| 1035 | |
| 1036 AutofillProfile* tmp_profile = NULL; | |
| 1037 if (!GetAutofillProfile(profile.guid(), &tmp_profile)) | |
| 1038 return false; | |
| 1039 | |
| 1040 // Preserve appropriate modification dates by not updating unchanged profiles. | |
| 1041 scoped_ptr<AutofillProfile> old_profile(tmp_profile); | |
| 1042 if (old_profile->Compare(profile) == 0) | |
| 1043 return true; | |
| 1044 | |
| 1045 sql::Statement s(db_->GetUniqueStatement( | |
| 1046 "UPDATE autofill_profiles " | |
| 1047 "SET guid=?, company_name=?, address_line_1=?, address_line_2=?, " | |
| 1048 " city=?, state=?, zipcode=?, country=?, country_code=?, " | |
| 1049 " date_modified=? " | |
| 1050 "WHERE guid=?")); | |
| 1051 BindAutofillProfileToStatement(profile, &s); | |
| 1052 s.BindString(10, profile.guid()); | |
| 1053 | |
| 1054 bool result = s.Run(); | |
| 1055 DCHECK_GT(db_->GetLastChangeCount(), 0); | |
| 1056 if (!result) | |
| 1057 return result; | |
| 1058 | |
| 1059 // Remove the old names, emails, and phone numbers. | |
| 1060 if (!RemoveAutofillProfilePieces(profile.guid(), db_)) | |
| 1061 return false; | |
| 1062 | |
| 1063 return AddAutofillProfilePieces(profile, db_); | |
| 1064 } | |
| 1065 | |
| 1066 bool AutofillTable::RemoveAutofillProfile(const std::string& guid) { | |
| 1067 DCHECK(base::IsValidGUID(guid)); | |
| 1068 | |
| 1069 if (IsAutofillGUIDInTrash(guid)) { | |
| 1070 sql::Statement s_trash(db_->GetUniqueStatement( | |
| 1071 "DELETE FROM autofill_profiles_trash WHERE guid = ?")); | |
| 1072 s_trash.BindString(0, guid); | |
| 1073 | |
| 1074 bool success = s_trash.Run(); | |
| 1075 DCHECK_GT(db_->GetLastChangeCount(), 0) << "Expected item in trash"; | |
| 1076 return success; | |
| 1077 } | |
| 1078 | |
| 1079 sql::Statement s(db_->GetUniqueStatement( | |
| 1080 "DELETE FROM autofill_profiles WHERE guid = ?")); | |
| 1081 s.BindString(0, guid); | |
| 1082 | |
| 1083 if (!s.Run()) | |
| 1084 return false; | |
| 1085 | |
| 1086 return RemoveAutofillProfilePieces(guid, db_); | |
| 1087 } | |
| 1088 | |
| 1089 bool AutofillTable::ClearAutofillProfiles() { | |
| 1090 sql::Statement s1(db_->GetUniqueStatement( | |
| 1091 "DELETE FROM autofill_profiles")); | |
| 1092 | |
| 1093 if (!s1.Run()) | |
| 1094 return false; | |
| 1095 | |
| 1096 sql::Statement s2(db_->GetUniqueStatement( | |
| 1097 "DELETE FROM autofill_profile_names")); | |
| 1098 | |
| 1099 if (!s2.Run()) | |
| 1100 return false; | |
| 1101 | |
| 1102 sql::Statement s3(db_->GetUniqueStatement( | |
| 1103 "DELETE FROM autofill_profile_emails")); | |
| 1104 | |
| 1105 if (!s3.Run()) | |
| 1106 return false; | |
| 1107 | |
| 1108 sql::Statement s4(db_->GetUniqueStatement( | |
| 1109 "DELETE FROM autofill_profile_phones")); | |
| 1110 | |
| 1111 return s4.Run(); | |
| 1112 } | |
| 1113 | |
| 1114 bool AutofillTable::AddCreditCard(const CreditCard& credit_card) { | |
| 1115 sql::Statement s(db_->GetUniqueStatement( | |
| 1116 "INSERT INTO credit_cards" | |
| 1117 "(guid, name_on_card, expiration_month, expiration_year, " | |
| 1118 "card_number_encrypted, date_modified)" | |
| 1119 "VALUES (?,?,?,?,?,?)")); | |
| 1120 BindCreditCardToStatement(credit_card, &s); | |
| 1121 | |
| 1122 if (!s.Run()) | |
| 1123 return false; | |
| 1124 | |
| 1125 DCHECK_GT(db_->GetLastChangeCount(), 0); | |
| 1126 return true; | |
| 1127 } | |
| 1128 | |
| 1129 bool AutofillTable::GetCreditCard(const std::string& guid, | |
| 1130 CreditCard** credit_card) { | |
| 1131 DCHECK(base::IsValidGUID(guid)); | |
| 1132 sql::Statement s(db_->GetUniqueStatement( | |
| 1133 "SELECT guid, name_on_card, expiration_month, expiration_year, " | |
| 1134 "card_number_encrypted, date_modified " | |
| 1135 "FROM credit_cards " | |
| 1136 "WHERE guid = ?")); | |
| 1137 s.BindString(0, guid); | |
| 1138 | |
| 1139 if (!s.Step()) | |
| 1140 return false; | |
| 1141 | |
| 1142 *credit_card = CreditCardFromStatement(s); | |
| 1143 return true; | |
| 1144 } | |
| 1145 | |
| 1146 bool AutofillTable::GetCreditCards( | |
| 1147 std::vector<CreditCard*>* credit_cards) { | |
| 1148 DCHECK(credit_cards); | |
| 1149 credit_cards->clear(); | |
| 1150 | |
| 1151 sql::Statement s(db_->GetUniqueStatement( | |
| 1152 "SELECT guid " | |
| 1153 "FROM credit_cards")); | |
| 1154 | |
| 1155 while (s.Step()) { | |
| 1156 std::string guid = s.ColumnString(0); | |
| 1157 CreditCard* credit_card = NULL; | |
| 1158 if (!GetCreditCard(guid, &credit_card)) | |
| 1159 return false; | |
| 1160 credit_cards->push_back(credit_card); | |
| 1161 } | |
| 1162 | |
| 1163 return s.Succeeded(); | |
| 1164 } | |
| 1165 | |
| 1166 bool AutofillTable::UpdateCreditCard(const CreditCard& credit_card) { | |
| 1167 DCHECK(base::IsValidGUID(credit_card.guid())); | |
| 1168 | |
| 1169 CreditCard* tmp_credit_card = NULL; | |
| 1170 if (!GetCreditCard(credit_card.guid(), &tmp_credit_card)) | |
| 1171 return false; | |
| 1172 | |
| 1173 // Preserve appropriate modification dates by not updating unchanged cards. | |
| 1174 scoped_ptr<CreditCard> old_credit_card(tmp_credit_card); | |
| 1175 if (*old_credit_card == credit_card) | |
| 1176 return true; | |
| 1177 | |
| 1178 sql::Statement s(db_->GetUniqueStatement( | |
| 1179 "UPDATE credit_cards " | |
| 1180 "SET guid=?, name_on_card=?, expiration_month=?, " | |
| 1181 " expiration_year=?, card_number_encrypted=?, date_modified=? " | |
| 1182 "WHERE guid=?")); | |
| 1183 BindCreditCardToStatement(credit_card, &s); | |
| 1184 s.BindString(6, credit_card.guid()); | |
| 1185 | |
| 1186 bool result = s.Run(); | |
| 1187 DCHECK_GT(db_->GetLastChangeCount(), 0); | |
| 1188 return result; | |
| 1189 } | |
| 1190 | |
| 1191 bool AutofillTable::RemoveCreditCard(const std::string& guid) { | |
| 1192 DCHECK(base::IsValidGUID(guid)); | |
| 1193 sql::Statement s(db_->GetUniqueStatement( | |
| 1194 "DELETE FROM credit_cards WHERE guid = ?")); | |
| 1195 s.BindString(0, guid); | |
| 1196 | |
| 1197 return s.Run(); | |
| 1198 } | |
| 1199 | |
| 1200 bool AutofillTable::RemoveAutofillDataModifiedBetween( | |
| 1201 const Time& delete_begin, | |
| 1202 const Time& delete_end, | |
| 1203 std::vector<std::string>* profile_guids, | |
| 1204 std::vector<std::string>* credit_card_guids) { | |
| 1205 DCHECK(delete_end.is_null() || delete_begin < delete_end); | |
| 1206 | |
| 1207 time_t delete_begin_t = delete_begin.ToTimeT(); | |
| 1208 time_t delete_end_t = | |
| 1209 (delete_end.is_null() || delete_end == base::Time::Max()) ? | |
| 1210 std::numeric_limits<time_t>::max() : delete_end.ToTimeT(); | |
| 1211 | |
| 1212 // Remember Autofill profiles in the time range. | |
| 1213 sql::Statement s_profiles_get(db_->GetUniqueStatement( | |
| 1214 "SELECT guid FROM autofill_profiles " | |
| 1215 "WHERE date_modified >= ? AND date_modified < ?")); | |
| 1216 s_profiles_get.BindInt64(0, delete_begin_t); | |
| 1217 s_profiles_get.BindInt64(1, delete_end_t); | |
| 1218 | |
| 1219 profile_guids->clear(); | |
| 1220 while (s_profiles_get.Step()) { | |
| 1221 std::string guid = s_profiles_get.ColumnString(0); | |
| 1222 profile_guids->push_back(guid); | |
| 1223 } | |
| 1224 if (!s_profiles_get.Succeeded()) | |
| 1225 return false; | |
| 1226 | |
| 1227 // Remove Autofill profiles in the time range. | |
| 1228 sql::Statement s_profiles(db_->GetUniqueStatement( | |
| 1229 "DELETE FROM autofill_profiles " | |
| 1230 "WHERE date_modified >= ? AND date_modified < ?")); | |
| 1231 s_profiles.BindInt64(0, delete_begin_t); | |
| 1232 s_profiles.BindInt64(1, delete_end_t); | |
| 1233 | |
| 1234 if (!s_profiles.Run()) | |
| 1235 return false; | |
| 1236 | |
| 1237 // Remember Autofill credit cards in the time range. | |
| 1238 sql::Statement s_credit_cards_get(db_->GetUniqueStatement( | |
| 1239 "SELECT guid FROM credit_cards " | |
| 1240 "WHERE date_modified >= ? AND date_modified < ?")); | |
| 1241 s_credit_cards_get.BindInt64(0, delete_begin_t); | |
| 1242 s_credit_cards_get.BindInt64(1, delete_end_t); | |
| 1243 | |
| 1244 credit_card_guids->clear(); | |
| 1245 while (s_credit_cards_get.Step()) { | |
| 1246 std::string guid = s_credit_cards_get.ColumnString(0); | |
| 1247 credit_card_guids->push_back(guid); | |
| 1248 } | |
| 1249 if (!s_credit_cards_get.Succeeded()) | |
| 1250 return false; | |
| 1251 | |
| 1252 // Remove Autofill credit cards in the time range. | |
| 1253 sql::Statement s_credit_cards(db_->GetUniqueStatement( | |
| 1254 "DELETE FROM credit_cards " | |
| 1255 "WHERE date_modified >= ? AND date_modified < ?")); | |
| 1256 s_credit_cards.BindInt64(0, delete_begin_t); | |
| 1257 s_credit_cards.BindInt64(1, delete_end_t); | |
| 1258 | |
| 1259 return s_credit_cards.Run(); | |
| 1260 } | |
| 1261 | |
| 1262 bool AutofillTable::GetAutofillProfilesInTrash( | |
| 1263 std::vector<std::string>* guids) { | |
| 1264 guids->clear(); | |
| 1265 | |
| 1266 sql::Statement s(db_->GetUniqueStatement( | |
| 1267 "SELECT guid " | |
| 1268 "FROM autofill_profiles_trash")); | |
| 1269 | |
| 1270 while (s.Step()) { | |
| 1271 std::string guid = s.ColumnString(0); | |
| 1272 guids->push_back(guid); | |
| 1273 } | |
| 1274 | |
| 1275 return s.Succeeded(); | |
| 1276 } | |
| 1277 | |
| 1278 bool AutofillTable::EmptyAutofillProfilesTrash() { | |
| 1279 sql::Statement s(db_->GetUniqueStatement( | |
| 1280 "DELETE FROM autofill_profiles_trash")); | |
| 1281 | |
| 1282 return s.Run(); | |
| 1283 } | |
| 1284 | |
| 1285 | |
| 1286 bool AutofillTable::RemoveFormElementForID(int64 pair_id) { | |
| 1287 sql::Statement s(db_->GetUniqueStatement( | |
| 1288 "DELETE FROM autofill WHERE pair_id = ?")); | |
| 1289 s.BindInt64(0, pair_id); | |
| 1290 | |
| 1291 if (s.Run()) | |
| 1292 return RemoveFormElementForTimeRange(pair_id, Time(), Time(), NULL); | |
| 1293 | |
| 1294 return false; | |
| 1295 } | |
| 1296 | |
| 1297 bool AutofillTable::AddAutofillGUIDToTrash(const std::string& guid) { | |
| 1298 sql::Statement s(db_->GetUniqueStatement( | |
| 1299 "INSERT INTO autofill_profiles_trash" | |
| 1300 " (guid) " | |
| 1301 "VALUES (?)")); | |
| 1302 s.BindString(0, guid); | |
| 1303 | |
| 1304 return s.Run(); | |
| 1305 } | |
| 1306 | |
| 1307 bool AutofillTable::IsAutofillProfilesTrashEmpty() { | |
| 1308 sql::Statement s(db_->GetUniqueStatement( | |
| 1309 "SELECT guid " | |
| 1310 "FROM autofill_profiles_trash")); | |
| 1311 | |
| 1312 return !s.Step(); | |
| 1313 } | |
| 1314 | |
| 1315 bool AutofillTable::IsAutofillGUIDInTrash(const std::string& guid) { | |
| 1316 sql::Statement s(db_->GetUniqueStatement( | |
| 1317 "SELECT guid " | |
| 1318 "FROM autofill_profiles_trash " | |
| 1319 "WHERE guid = ?")); | |
| 1320 s.BindString(0, guid); | |
| 1321 | |
| 1322 return s.Step(); | |
| 1323 } | |
| 1324 | |
| 1325 bool AutofillTable::InitMainTable() { | |
| 1326 if (!db_->DoesTableExist("autofill")) { | |
| 1327 if (!db_->Execute("CREATE TABLE autofill (" | |
| 1328 "name VARCHAR, " | |
| 1329 "value VARCHAR, " | |
| 1330 "value_lower VARCHAR, " | |
| 1331 "pair_id INTEGER PRIMARY KEY, " | |
| 1332 "count INTEGER DEFAULT 1)")) { | |
| 1333 NOTREACHED(); | |
| 1334 return false; | |
| 1335 } | |
| 1336 if (!db_->Execute("CREATE INDEX autofill_name ON autofill (name)")) { | |
| 1337 NOTREACHED(); | |
| 1338 return false; | |
| 1339 } | |
| 1340 if (!db_->Execute("CREATE INDEX autofill_name_value_lower ON " | |
| 1341 "autofill (name, value_lower)")) { | |
| 1342 NOTREACHED(); | |
| 1343 return false; | |
| 1344 } | |
| 1345 } | |
| 1346 return true; | |
| 1347 } | |
| 1348 | |
| 1349 bool AutofillTable::InitCreditCardsTable() { | |
| 1350 if (!db_->DoesTableExist("credit_cards")) { | |
| 1351 if (!db_->Execute("CREATE TABLE credit_cards ( " | |
| 1352 "guid VARCHAR PRIMARY KEY, " | |
| 1353 "name_on_card VARCHAR, " | |
| 1354 "expiration_month INTEGER, " | |
| 1355 "expiration_year INTEGER, " | |
| 1356 "card_number_encrypted BLOB, " | |
| 1357 "date_modified INTEGER NOT NULL DEFAULT 0)")) { | |
| 1358 NOTREACHED(); | |
| 1359 return false; | |
| 1360 } | |
| 1361 } | |
| 1362 | |
| 1363 return true; | |
| 1364 } | |
| 1365 | |
| 1366 bool AutofillTable::InitDatesTable() { | |
| 1367 if (!db_->DoesTableExist("autofill_dates")) { | |
| 1368 if (!db_->Execute("CREATE TABLE autofill_dates ( " | |
| 1369 "pair_id INTEGER DEFAULT 0, " | |
| 1370 "date_created INTEGER DEFAULT 0)")) { | |
| 1371 NOTREACHED(); | |
| 1372 return false; | |
| 1373 } | |
| 1374 if (!db_->Execute("CREATE INDEX autofill_dates_pair_id ON " | |
| 1375 "autofill_dates (pair_id)")) { | |
| 1376 NOTREACHED(); | |
| 1377 return false; | |
| 1378 } | |
| 1379 } | |
| 1380 return true; | |
| 1381 } | |
| 1382 | |
| 1383 bool AutofillTable::InitProfilesTable() { | |
| 1384 if (!db_->DoesTableExist("autofill_profiles")) { | |
| 1385 if (!db_->Execute("CREATE TABLE autofill_profiles ( " | |
| 1386 "guid VARCHAR PRIMARY KEY, " | |
| 1387 "company_name VARCHAR, " | |
| 1388 "address_line_1 VARCHAR, " | |
| 1389 "address_line_2 VARCHAR, " | |
| 1390 "city VARCHAR, " | |
| 1391 "state VARCHAR, " | |
| 1392 "zipcode VARCHAR, " | |
| 1393 "country VARCHAR, " | |
| 1394 "country_code VARCHAR, " | |
| 1395 "date_modified INTEGER NOT NULL DEFAULT 0)")) { | |
| 1396 NOTREACHED(); | |
| 1397 return false; | |
| 1398 } | |
| 1399 } | |
| 1400 return true; | |
| 1401 } | |
| 1402 | |
| 1403 bool AutofillTable::InitProfileNamesTable() { | |
| 1404 if (!db_->DoesTableExist("autofill_profile_names")) { | |
| 1405 if (!db_->Execute("CREATE TABLE autofill_profile_names ( " | |
| 1406 "guid VARCHAR, " | |
| 1407 "first_name VARCHAR, " | |
| 1408 "middle_name VARCHAR, " | |
| 1409 "last_name VARCHAR)")) { | |
| 1410 NOTREACHED(); | |
| 1411 return false; | |
| 1412 } | |
| 1413 } | |
| 1414 return true; | |
| 1415 } | |
| 1416 | |
| 1417 bool AutofillTable::InitProfileEmailsTable() { | |
| 1418 if (!db_->DoesTableExist("autofill_profile_emails")) { | |
| 1419 if (!db_->Execute("CREATE TABLE autofill_profile_emails ( " | |
| 1420 "guid VARCHAR, " | |
| 1421 "email VARCHAR)")) { | |
| 1422 NOTREACHED(); | |
| 1423 return false; | |
| 1424 } | |
| 1425 } | |
| 1426 return true; | |
| 1427 } | |
| 1428 | |
| 1429 bool AutofillTable::InitProfilePhonesTable() { | |
| 1430 if (!db_->DoesTableExist("autofill_profile_phones")) { | |
| 1431 if (!db_->Execute("CREATE TABLE autofill_profile_phones ( " | |
| 1432 "guid VARCHAR, " | |
| 1433 "type INTEGER DEFAULT 0, " | |
| 1434 "number VARCHAR)")) { | |
| 1435 NOTREACHED(); | |
| 1436 return false; | |
| 1437 } | |
| 1438 } | |
| 1439 return true; | |
| 1440 } | |
| 1441 | |
| 1442 bool AutofillTable::InitProfileTrashTable() { | |
| 1443 if (!db_->DoesTableExist("autofill_profiles_trash")) { | |
| 1444 if (!db_->Execute("CREATE TABLE autofill_profiles_trash ( " | |
| 1445 "guid VARCHAR)")) { | |
| 1446 NOTREACHED(); | |
| 1447 return false; | |
| 1448 } | |
| 1449 } | |
| 1450 return true; | |
| 1451 } | |
| 1452 | |
| 1453 // Add the card_number_encrypted column if credit card table was not | |
| 1454 // created in this build (otherwise the column already exists). | |
| 1455 // WARNING: Do not change the order of the execution of the SQL | |
| 1456 // statements in this case! Profile corruption and data migration | |
| 1457 // issues WILL OCCUR. See http://crbug.com/10913 | |
| 1458 // | |
| 1459 // The problem is that if a user has a profile which was created before | |
| 1460 // r37036, when the credit_cards table was added, and then failed to | |
| 1461 // update this profile between the credit card addition and the addition | |
| 1462 // of the "encrypted" columns (44963), the next data migration will put | |
| 1463 // the user's profile in an incoherent state: The user will update from | |
| 1464 // a data profile set to be earlier than 22, and therefore pass through | |
| 1465 // this update case. But because the user did not have a credit_cards | |
| 1466 // table before starting Chrome, it will have just been initialized | |
| 1467 // above, and so already have these columns -- and thus this data | |
| 1468 // update step will have failed. | |
| 1469 // | |
| 1470 // The false assumption in this case is that at this step in the | |
| 1471 // migration, the user has a credit card table, and that this | |
| 1472 // table does not include encrypted columns! | |
| 1473 // Because this case does not roll back the complete set of SQL | |
| 1474 // transactions properly in case of failure (that is, it does not | |
| 1475 // roll back the table initialization done above), the incoherent | |
| 1476 // profile will now see itself as being at version 22 -- but include a | |
| 1477 // fully initialized credit_cards table. Every time Chrome runs, it | |
| 1478 // will try to update the web database and fail at this step, unless | |
| 1479 // we allow for the faulty assumption described above by checking for | |
| 1480 // the existence of the columns only AFTER we've executed the commands | |
| 1481 // to add them. | |
| 1482 bool AutofillTable::MigrateToVersion23AddCardNumberEncryptedColumn() { | |
| 1483 if (!db_->DoesColumnExist("credit_cards", "card_number_encrypted")) { | |
| 1484 if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN " | |
| 1485 "card_number_encrypted BLOB DEFAULT NULL")) { | |
| 1486 LOG(WARNING) << "Could not add card_number_encrypted to " | |
| 1487 "credit_cards table."; | |
| 1488 return false; | |
| 1489 } | |
| 1490 } | |
| 1491 | |
| 1492 if (!db_->DoesColumnExist("credit_cards", "verification_code_encrypted")) { | |
| 1493 if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN " | |
| 1494 "verification_code_encrypted BLOB DEFAULT NULL")) { | |
| 1495 LOG(WARNING) << "Could not add verification_code_encrypted to " | |
| 1496 "credit_cards table."; | |
| 1497 return false; | |
| 1498 } | |
| 1499 } | |
| 1500 | |
| 1501 return true; | |
| 1502 } | |
| 1503 | |
| 1504 // One-time cleanup for http://crbug.com/38364 - In the presence of | |
| 1505 // multi-byte UTF-8 characters, that bug could cause Autofill strings | |
| 1506 // to grow larger and more corrupt with each save. The cleanup removes | |
| 1507 // any row with a string field larger than a reasonable size. The string | |
| 1508 // fields examined here are precisely the ones that were subject to | |
| 1509 // corruption by the original bug. | |
| 1510 bool AutofillTable::MigrateToVersion24CleanupOversizedStringFields() { | |
| 1511 const std::string autofill_is_too_big = | |
| 1512 "max(length(name), length(value)) > 500"; | |
| 1513 | |
| 1514 const std::string credit_cards_is_too_big = | |
| 1515 "max(length(label), length(name_on_card), length(type), " | |
| 1516 " length(expiration_month), length(expiration_year), " | |
| 1517 " length(billing_address), length(shipping_address) " | |
| 1518 ") > 500"; | |
| 1519 | |
| 1520 const std::string autofill_profiles_is_too_big = | |
| 1521 "max(length(label), length(first_name), " | |
| 1522 " length(middle_name), length(last_name), length(email), " | |
| 1523 " length(company_name), length(address_line_1), " | |
| 1524 " length(address_line_2), length(city), length(state), " | |
| 1525 " length(zipcode), length(country), length(phone)) > 500"; | |
| 1526 | |
| 1527 std::string query = "DELETE FROM autofill_dates WHERE pair_id IN (" | |
| 1528 "SELECT pair_id FROM autofill WHERE " + autofill_is_too_big + ")"; | |
| 1529 | |
| 1530 if (!db_->Execute(query.c_str())) | |
| 1531 return false; | |
| 1532 | |
| 1533 query = "DELETE FROM autofill WHERE " + autofill_is_too_big; | |
| 1534 | |
| 1535 if (!db_->Execute(query.c_str())) | |
| 1536 return false; | |
| 1537 | |
| 1538 // Only delete from legacy credit card tables where specific columns exist. | |
| 1539 if (db_->DoesColumnExist("credit_cards", "label") && | |
| 1540 db_->DoesColumnExist("credit_cards", "name_on_card") && | |
| 1541 db_->DoesColumnExist("credit_cards", "type") && | |
| 1542 db_->DoesColumnExist("credit_cards", "expiration_month") && | |
| 1543 db_->DoesColumnExist("credit_cards", "expiration_year") && | |
| 1544 db_->DoesColumnExist("credit_cards", "billing_address") && | |
| 1545 db_->DoesColumnExist("credit_cards", "shipping_address") && | |
| 1546 db_->DoesColumnExist("autofill_profiles", "label")) { | |
| 1547 query = "DELETE FROM credit_cards WHERE (" + credit_cards_is_too_big + | |
| 1548 ") OR label IN (SELECT label FROM autofill_profiles WHERE " + | |
| 1549 autofill_profiles_is_too_big + ")"; | |
| 1550 | |
| 1551 if (!db_->Execute(query.c_str())) | |
| 1552 return false; | |
| 1553 } | |
| 1554 | |
| 1555 if (db_->DoesColumnExist("autofill_profiles", "label")) { | |
| 1556 query = "DELETE FROM autofill_profiles WHERE " + | |
| 1557 autofill_profiles_is_too_big; | |
| 1558 | |
| 1559 if (!db_->Execute(query.c_str())) | |
| 1560 return false; | |
| 1561 } | |
| 1562 | |
| 1563 return true; | |
| 1564 } | |
| 1565 | |
| 1566 // Change the credit_cards.billing_address column from a string to an | |
| 1567 // int. The stored string is the label of an address, so we have to | |
| 1568 // select the unique ID of this address using the label as a foreign | |
| 1569 // key into the |autofill_profiles| table. | |
| 1570 bool AutofillTable::MigrateToVersion27UpdateLegacyCreditCards() { | |
| 1571 // Only migrate from legacy credit card tables where specific columns | |
| 1572 // exist. | |
| 1573 if (!(db_->DoesColumnExist("credit_cards", "unique_id") && | |
| 1574 db_->DoesColumnExist("credit_cards", "billing_address") && | |
| 1575 db_->DoesColumnExist("autofill_profiles", "unique_id"))) { | |
| 1576 return true; | |
| 1577 } | |
| 1578 | |
| 1579 std::string stmt = | |
| 1580 "SELECT credit_cards.unique_id, autofill_profiles.unique_id " | |
| 1581 "FROM autofill_profiles, credit_cards " | |
| 1582 "WHERE credit_cards.billing_address = autofill_profiles.label"; | |
| 1583 sql::Statement s(db_->GetUniqueStatement(stmt.c_str())); | |
| 1584 | |
| 1585 std::map<int, int> cc_billing_map; | |
| 1586 while (s.Step()) | |
| 1587 cc_billing_map[s.ColumnInt(0)] = s.ColumnInt(1); | |
| 1588 if (!s.Succeeded()) | |
| 1589 return false; | |
| 1590 | |
| 1591 // Windows already stores the IDs as strings in |billing_address|. Try | |
| 1592 // to convert those. | |
| 1593 if (cc_billing_map.empty()) { | |
| 1594 std::string stmt = "SELECT unique_id,billing_address FROM credit_cards"; | |
| 1595 sql::Statement s(db_->GetUniqueStatement(stmt.c_str())); | |
| 1596 | |
| 1597 while (s.Step()) { | |
| 1598 int id = 0; | |
| 1599 if (base::StringToInt(s.ColumnString(1), &id)) | |
| 1600 cc_billing_map[s.ColumnInt(0)] = id; | |
| 1601 } | |
| 1602 if (!s.Succeeded()) | |
| 1603 return false; | |
| 1604 } | |
| 1605 | |
| 1606 if (!db_->Execute("CREATE TABLE credit_cards_temp ( " | |
| 1607 "label VARCHAR, " | |
| 1608 "unique_id INTEGER PRIMARY KEY, " | |
| 1609 "name_on_card VARCHAR, " | |
| 1610 "type VARCHAR, " | |
| 1611 "card_number VARCHAR, " | |
| 1612 "expiration_month INTEGER, " | |
| 1613 "expiration_year INTEGER, " | |
| 1614 "verification_code VARCHAR, " | |
| 1615 "billing_address INTEGER, " | |
| 1616 "shipping_address VARCHAR, " | |
| 1617 "card_number_encrypted BLOB, " | |
| 1618 "verification_code_encrypted BLOB)")) { | |
| 1619 return false; | |
| 1620 } | |
| 1621 | |
| 1622 if (!db_->Execute( | |
| 1623 "INSERT INTO credit_cards_temp " | |
| 1624 "SELECT label,unique_id,name_on_card,type,card_number," | |
| 1625 "expiration_month,expiration_year,verification_code,0," | |
| 1626 "shipping_address,card_number_encrypted," | |
| 1627 "verification_code_encrypted FROM credit_cards")) { | |
| 1628 return false; | |
| 1629 } | |
| 1630 | |
| 1631 if (!db_->Execute("DROP TABLE credit_cards")) | |
| 1632 return false; | |
| 1633 | |
| 1634 if (!db_->Execute("ALTER TABLE credit_cards_temp RENAME TO credit_cards")) | |
| 1635 return false; | |
| 1636 | |
| 1637 for (std::map<int, int>::const_iterator iter = cc_billing_map.begin(); | |
| 1638 iter != cc_billing_map.end(); ++iter) { | |
| 1639 sql::Statement s(db_->GetCachedStatement( | |
| 1640 SQL_FROM_HERE, | |
| 1641 "UPDATE credit_cards SET billing_address=? WHERE unique_id=?")); | |
| 1642 s.BindInt(0, (*iter).second); | |
| 1643 s.BindInt(1, (*iter).first); | |
| 1644 | |
| 1645 if (!s.Run()) | |
| 1646 return false; | |
| 1647 } | |
| 1648 | |
| 1649 return true; | |
| 1650 } | |
| 1651 | |
| 1652 bool AutofillTable::MigrateToVersion30AddDateModifed() { | |
| 1653 // Add date_modified to autofill_profiles. | |
| 1654 if (!db_->DoesColumnExist("autofill_profiles", "date_modified")) { | |
| 1655 if (!db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN " | |
| 1656 "date_modified INTEGER NON NULL DEFAULT 0")) { | |
| 1657 return false; | |
| 1658 } | |
| 1659 | |
| 1660 sql::Statement s(db_->GetUniqueStatement( | |
| 1661 "UPDATE autofill_profiles SET date_modified=?")); | |
| 1662 s.BindInt64(0, Time::Now().ToTimeT()); | |
| 1663 | |
| 1664 if (!s.Run()) | |
| 1665 return false; | |
| 1666 } | |
| 1667 | |
| 1668 // Add date_modified to credit_cards. | |
| 1669 if (!db_->DoesColumnExist("credit_cards", "date_modified")) { | |
| 1670 if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN " | |
| 1671 "date_modified INTEGER NON NULL DEFAULT 0")) { | |
| 1672 return false; | |
| 1673 } | |
| 1674 | |
| 1675 sql::Statement s(db_->GetUniqueStatement( | |
| 1676 "UPDATE credit_cards SET date_modified=?")); | |
| 1677 s.BindInt64(0, Time::Now().ToTimeT()); | |
| 1678 | |
| 1679 if (!s.Run()) | |
| 1680 return false; | |
| 1681 } | |
| 1682 | |
| 1683 return true; | |
| 1684 } | |
| 1685 | |
| 1686 bool AutofillTable::MigrateToVersion31AddGUIDToCreditCardsAndProfiles() { | |
| 1687 // Note that we need to check for the guid column's existence due to the | |
| 1688 // fact that for a version 22 database the |autofill_profiles| table | |
| 1689 // gets created fresh with |InitAutofillProfilesTable|. | |
| 1690 if (!db_->DoesColumnExist("autofill_profiles", "guid")) { | |
| 1691 if (!db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN " | |
| 1692 "guid VARCHAR NOT NULL DEFAULT \"\"")) { | |
| 1693 return false; | |
| 1694 } | |
| 1695 | |
| 1696 // Set all the |guid| fields to valid values. | |
| 1697 | |
| 1698 sql::Statement s(db_->GetUniqueStatement("SELECT unique_id " | |
| 1699 "FROM autofill_profiles")); | |
| 1700 | |
| 1701 while (s.Step()) { | |
| 1702 sql::Statement update_s( | |
| 1703 db_->GetUniqueStatement("UPDATE autofill_profiles " | |
| 1704 "SET guid=? WHERE unique_id=?")); | |
| 1705 update_s.BindString(0, base::GenerateGUID()); | |
| 1706 update_s.BindInt(1, s.ColumnInt(0)); | |
| 1707 | |
| 1708 if (!update_s.Run()) | |
| 1709 return false; | |
| 1710 } | |
| 1711 if (!s.Succeeded()) | |
| 1712 return false; | |
| 1713 } | |
| 1714 | |
| 1715 // Note that we need to check for the guid column's existence due to the | |
| 1716 // fact that for a version 22 database the |autofill_profiles| table | |
| 1717 // gets created fresh with |InitAutofillProfilesTable|. | |
| 1718 if (!db_->DoesColumnExist("credit_cards", "guid")) { | |
| 1719 if (!db_->Execute("ALTER TABLE credit_cards ADD COLUMN " | |
| 1720 "guid VARCHAR NOT NULL DEFAULT \"\"")) { | |
| 1721 return false; | |
| 1722 } | |
| 1723 | |
| 1724 // Set all the |guid| fields to valid values. | |
| 1725 | |
| 1726 sql::Statement s(db_->GetUniqueStatement("SELECT unique_id " | |
| 1727 "FROM credit_cards")); | |
| 1728 | |
| 1729 while (s.Step()) { | |
| 1730 sql::Statement update_s( | |
| 1731 db_->GetUniqueStatement("UPDATE credit_cards " | |
| 1732 "set guid=? WHERE unique_id=?")); | |
| 1733 update_s.BindString(0, base::GenerateGUID()); | |
| 1734 update_s.BindInt(1, s.ColumnInt(0)); | |
| 1735 | |
| 1736 if (!update_s.Run()) | |
| 1737 return false; | |
| 1738 } | |
| 1739 if (!s.Succeeded()) | |
| 1740 return false; | |
| 1741 } | |
| 1742 | |
| 1743 return true; | |
| 1744 } | |
| 1745 | |
| 1746 bool AutofillTable::MigrateToVersion32UpdateProfilesAndCreditCards() { | |
| 1747 if (db_->DoesColumnExist("autofill_profiles", "unique_id")) { | |
| 1748 if (!db_->Execute("CREATE TABLE autofill_profiles_temp ( " | |
| 1749 "guid VARCHAR PRIMARY KEY, " | |
| 1750 "label VARCHAR, " | |
| 1751 "first_name VARCHAR, " | |
| 1752 "middle_name VARCHAR, " | |
| 1753 "last_name VARCHAR, " | |
| 1754 "email VARCHAR, " | |
| 1755 "company_name VARCHAR, " | |
| 1756 "address_line_1 VARCHAR, " | |
| 1757 "address_line_2 VARCHAR, " | |
| 1758 "city VARCHAR, " | |
| 1759 "state VARCHAR, " | |
| 1760 "zipcode VARCHAR, " | |
| 1761 "country VARCHAR, " | |
| 1762 "phone VARCHAR, " | |
| 1763 "date_modified INTEGER NOT NULL DEFAULT 0)")) { | |
| 1764 return false; | |
| 1765 } | |
| 1766 | |
| 1767 if (!db_->Execute( | |
| 1768 "INSERT INTO autofill_profiles_temp " | |
| 1769 "SELECT guid, label, first_name, middle_name, last_name, email, " | |
| 1770 "company_name, address_line_1, address_line_2, city, state, " | |
| 1771 "zipcode, country, phone, date_modified " | |
| 1772 "FROM autofill_profiles")) { | |
| 1773 return false; | |
| 1774 } | |
| 1775 | |
| 1776 if (!db_->Execute("DROP TABLE autofill_profiles")) | |
| 1777 return false; | |
| 1778 | |
| 1779 if (!db_->Execute( | |
| 1780 "ALTER TABLE autofill_profiles_temp RENAME TO autofill_profiles")) { | |
| 1781 return false; | |
| 1782 } | |
| 1783 } | |
| 1784 | |
| 1785 if (db_->DoesColumnExist("credit_cards", "unique_id")) { | |
| 1786 if (!db_->Execute("CREATE TABLE credit_cards_temp ( " | |
| 1787 "guid VARCHAR PRIMARY KEY, " | |
| 1788 "label VARCHAR, " | |
| 1789 "name_on_card VARCHAR, " | |
| 1790 "expiration_month INTEGER, " | |
| 1791 "expiration_year INTEGER, " | |
| 1792 "card_number_encrypted BLOB, " | |
| 1793 "date_modified INTEGER NOT NULL DEFAULT 0)")) { | |
| 1794 return false; | |
| 1795 } | |
| 1796 | |
| 1797 if (!db_->Execute( | |
| 1798 "INSERT INTO credit_cards_temp " | |
| 1799 "SELECT guid, label, name_on_card, expiration_month, " | |
| 1800 "expiration_year, card_number_encrypted, date_modified " | |
| 1801 "FROM credit_cards")) { | |
| 1802 return false; | |
| 1803 } | |
| 1804 | |
| 1805 if (!db_->Execute("DROP TABLE credit_cards")) | |
| 1806 return false; | |
| 1807 | |
| 1808 if (!db_->Execute("ALTER TABLE credit_cards_temp RENAME TO credit_cards")) | |
| 1809 return false; | |
| 1810 } | |
| 1811 | |
| 1812 return true; | |
| 1813 } | |
| 1814 | |
| 1815 // Test the existence of the |first_name| column as an indication that | |
| 1816 // we need a migration. It is possible that the new |autofill_profiles| | |
| 1817 // schema is in place because the table was newly created when migrating | |
| 1818 // from a pre-version-22 database. | |
| 1819 bool AutofillTable::MigrateToVersion33ProfilesBasedOnFirstName() { | |
| 1820 if (db_->DoesColumnExist("autofill_profiles", "first_name")) { | |
| 1821 // Create autofill_profiles_temp table that will receive the data. | |
| 1822 if (!db_->DoesTableExist("autofill_profiles_temp")) { | |
| 1823 if (!db_->Execute("CREATE TABLE autofill_profiles_temp ( " | |
| 1824 "guid VARCHAR PRIMARY KEY, " | |
| 1825 "company_name VARCHAR, " | |
| 1826 "address_line_1 VARCHAR, " | |
| 1827 "address_line_2 VARCHAR, " | |
| 1828 "city VARCHAR, " | |
| 1829 "state VARCHAR, " | |
| 1830 "zipcode VARCHAR, " | |
| 1831 "country VARCHAR, " | |
| 1832 "date_modified INTEGER NOT NULL DEFAULT 0)")) { | |
| 1833 return false; | |
| 1834 } | |
| 1835 } | |
| 1836 | |
| 1837 sql::Statement s(db_->GetUniqueStatement( | |
| 1838 "SELECT guid, first_name, middle_name, last_name, email, " | |
| 1839 "company_name, address_line_1, address_line_2, city, state, " | |
| 1840 "zipcode, country, phone, date_modified " | |
| 1841 "FROM autofill_profiles")); | |
| 1842 | |
| 1843 while (s.Step()) { | |
| 1844 AutofillProfile profile; | |
| 1845 profile.set_guid(s.ColumnString(0)); | |
| 1846 DCHECK(base::IsValidGUID(profile.guid())); | |
| 1847 | |
| 1848 profile.SetRawInfo(NAME_FIRST, s.ColumnString16(1)); | |
| 1849 profile.SetRawInfo(NAME_MIDDLE, s.ColumnString16(2)); | |
| 1850 profile.SetRawInfo(NAME_LAST, s.ColumnString16(3)); | |
| 1851 profile.SetRawInfo(EMAIL_ADDRESS, s.ColumnString16(4)); | |
| 1852 profile.SetRawInfo(COMPANY_NAME, s.ColumnString16(5)); | |
| 1853 profile.SetRawInfo(ADDRESS_HOME_LINE1, s.ColumnString16(6)); | |
| 1854 profile.SetRawInfo(ADDRESS_HOME_LINE2, s.ColumnString16(7)); | |
| 1855 profile.SetRawInfo(ADDRESS_HOME_CITY, s.ColumnString16(8)); | |
| 1856 profile.SetRawInfo(ADDRESS_HOME_STATE, s.ColumnString16(9)); | |
| 1857 profile.SetRawInfo(ADDRESS_HOME_ZIP, s.ColumnString16(10)); | |
| 1858 profile.SetRawInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(11)); | |
| 1859 profile.SetRawInfo(PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(12)); | |
| 1860 int64 date_modified = s.ColumnInt64(13); | |
| 1861 | |
| 1862 sql::Statement s_insert(db_->GetUniqueStatement( | |
| 1863 "INSERT INTO autofill_profiles_temp" | |
| 1864 "(guid, company_name, address_line_1, address_line_2, city," | |
| 1865 " state, zipcode, country, date_modified)" | |
| 1866 "VALUES (?,?,?,?,?,?,?,?,?)")); | |
| 1867 s_insert.BindString(0, profile.guid()); | |
| 1868 s_insert.BindString16(1, profile.GetRawInfo(COMPANY_NAME)); | |
| 1869 s_insert.BindString16(2, profile.GetRawInfo(ADDRESS_HOME_LINE1)); | |
| 1870 s_insert.BindString16(3, profile.GetRawInfo(ADDRESS_HOME_LINE2)); | |
| 1871 s_insert.BindString16(4, profile.GetRawInfo(ADDRESS_HOME_CITY)); | |
| 1872 s_insert.BindString16(5, profile.GetRawInfo(ADDRESS_HOME_STATE)); | |
| 1873 s_insert.BindString16(6, profile.GetRawInfo(ADDRESS_HOME_ZIP)); | |
| 1874 s_insert.BindString16(7, profile.GetRawInfo(ADDRESS_HOME_COUNTRY)); | |
| 1875 s_insert.BindInt64(8, date_modified); | |
| 1876 | |
| 1877 if (!s_insert.Run()) | |
| 1878 return false; | |
| 1879 | |
| 1880 // Add the other bits: names, emails, and phone numbers. | |
| 1881 if (!AddAutofillProfilePieces(profile, db_)) | |
| 1882 return false; | |
| 1883 } // endwhile | |
| 1884 if (!s.Succeeded()) | |
| 1885 return false; | |
| 1886 | |
| 1887 if (!db_->Execute("DROP TABLE autofill_profiles")) | |
| 1888 return false; | |
| 1889 | |
| 1890 if (!db_->Execute( | |
| 1891 "ALTER TABLE autofill_profiles_temp RENAME TO autofill_profiles")) { | |
| 1892 return false; | |
| 1893 } | |
| 1894 } | |
| 1895 | |
| 1896 // Remove the labels column from the credit_cards table. | |
| 1897 if (db_->DoesColumnExist("credit_cards", "label")) { | |
| 1898 if (!db_->Execute("CREATE TABLE credit_cards_temp ( " | |
| 1899 "guid VARCHAR PRIMARY KEY, " | |
| 1900 "name_on_card VARCHAR, " | |
| 1901 "expiration_month INTEGER, " | |
| 1902 "expiration_year INTEGER, " | |
| 1903 "card_number_encrypted BLOB, " | |
| 1904 "date_modified INTEGER NOT NULL DEFAULT 0)")) { | |
| 1905 return false; | |
| 1906 } | |
| 1907 | |
| 1908 if (!db_->Execute( | |
| 1909 "INSERT INTO credit_cards_temp " | |
| 1910 "SELECT guid, name_on_card, expiration_month, " | |
| 1911 "expiration_year, card_number_encrypted, date_modified " | |
| 1912 "FROM credit_cards")) { | |
| 1913 return false; | |
| 1914 } | |
| 1915 | |
| 1916 if (!db_->Execute("DROP TABLE credit_cards")) | |
| 1917 return false; | |
| 1918 | |
| 1919 if (!db_->Execute("ALTER TABLE credit_cards_temp RENAME TO credit_cards")) | |
| 1920 return false; | |
| 1921 } | |
| 1922 | |
| 1923 return true; | |
| 1924 } | |
| 1925 | |
| 1926 // Test the existence of the |country_code| column as an indication that | |
| 1927 // we need a migration. It is possible that the new |autofill_profiles| | |
| 1928 // schema is in place because the table was newly created when migrating | |
| 1929 // from a pre-version-22 database. | |
| 1930 bool AutofillTable::MigrateToVersion34ProfilesBasedOnCountryCode() { | |
| 1931 if (!db_->DoesColumnExist("autofill_profiles", "country_code")) { | |
| 1932 if (!db_->Execute("ALTER TABLE autofill_profiles ADD COLUMN " | |
| 1933 "country_code VARCHAR")) { | |
| 1934 return false; | |
| 1935 } | |
| 1936 | |
| 1937 // Set all the |country_code| fields to match existing |country| values. | |
| 1938 sql::Statement s(db_->GetUniqueStatement("SELECT guid, country " | |
| 1939 "FROM autofill_profiles")); | |
| 1940 | |
| 1941 while (s.Step()) { | |
| 1942 sql::Statement update_s( | |
| 1943 db_->GetUniqueStatement("UPDATE autofill_profiles " | |
| 1944 "SET country_code=? WHERE guid=?")); | |
| 1945 | |
| 1946 string16 country = s.ColumnString16(1); | |
| 1947 update_s.BindString(0, AutofillCountry::GetCountryCode(country, | |
| 1948 app_locale_)); | |
| 1949 update_s.BindString(1, s.ColumnString(0)); | |
| 1950 | |
| 1951 if (!update_s.Run()) | |
| 1952 return false; | |
| 1953 } | |
| 1954 if (!s.Succeeded()) | |
| 1955 return false; | |
| 1956 } | |
| 1957 | |
| 1958 return true; | |
| 1959 } | |
| 1960 | |
| 1961 // Correct all country codes with value "UK" to be "GB". This data | |
| 1962 // was mistakenly introduced in build 686.0. This migration is to clean | |
| 1963 // it up. See http://crbug.com/74511 for details. | |
| 1964 bool AutofillTable::MigrateToVersion35GreatBritainCountryCodes() { | |
| 1965 sql::Statement s(db_->GetUniqueStatement( | |
| 1966 "UPDATE autofill_profiles SET country_code=\"GB\" " | |
| 1967 "WHERE country_code=\"UK\"")); | |
| 1968 | |
| 1969 return s.Run(); | |
| 1970 } | |
| 1971 | |
| 1972 // Merge and cull older profiles where possible. | |
| 1973 bool AutofillTable::MigrateToVersion37MergeAndCullOlderProfiles() { | |
| 1974 sql::Statement s(db_->GetUniqueStatement( | |
| 1975 "SELECT guid, date_modified FROM autofill_profiles")); | |
| 1976 | |
| 1977 // Accumulate the good profiles. | |
| 1978 std::vector<AutofillProfile> accumulated_profiles; | |
| 1979 std::vector<AutofillProfile*> accumulated_profiles_p; | |
| 1980 std::map<std::string, int64> modification_map; | |
| 1981 while (s.Step()) { | |
| 1982 std::string guid = s.ColumnString(0); | |
| 1983 int64 date_modified = s.ColumnInt64(1); | |
| 1984 modification_map.insert( | |
| 1985 std::pair<std::string, int64>(guid, date_modified)); | |
| 1986 AutofillProfile* profile = NULL; | |
| 1987 if (!GetAutofillProfile(guid, &profile)) | |
| 1988 return false; | |
| 1989 | |
| 1990 scoped_ptr<AutofillProfile> p(profile); | |
| 1991 | |
| 1992 if (PersonalDataManager::IsValidLearnableProfile(*p)) { | |
| 1993 std::vector<AutofillProfile> merged_profiles; | |
| 1994 bool merged = PersonalDataManager::MergeProfile( | |
| 1995 *p, accumulated_profiles_p, &merged_profiles); | |
| 1996 | |
| 1997 std::swap(accumulated_profiles, merged_profiles); | |
| 1998 | |
| 1999 accumulated_profiles_p.clear(); | |
| 2000 accumulated_profiles_p.resize(accumulated_profiles.size()); | |
| 2001 std::transform(accumulated_profiles.begin(), | |
| 2002 accumulated_profiles.end(), | |
| 2003 accumulated_profiles_p.begin(), | |
| 2004 address_of<AutofillProfile>); | |
| 2005 | |
| 2006 // If the profile got merged trash the original. | |
| 2007 if (merged) | |
| 2008 AddAutofillGUIDToTrash(p->guid()); | |
| 2009 | |
| 2010 } else { | |
| 2011 // An invalid profile, so trash it. | |
| 2012 AddAutofillGUIDToTrash(p->guid()); | |
| 2013 } | |
| 2014 } // endwhile | |
| 2015 if (!s.Succeeded()) | |
| 2016 return false; | |
| 2017 | |
| 2018 // Drop the current profiles. | |
| 2019 if (!ClearAutofillProfiles()) | |
| 2020 return false; | |
| 2021 | |
| 2022 // Add the newly merged profiles back in. | |
| 2023 for (std::vector<AutofillProfile>::const_iterator | |
| 2024 iter = accumulated_profiles.begin(); | |
| 2025 iter != accumulated_profiles.end(); | |
| 2026 ++iter) { | |
| 2027 if (!AddAutofillProfile(*iter)) | |
| 2028 return false; | |
| 2029 | |
| 2030 // Fix up the original modification date. | |
| 2031 std::map<std::string, int64>::const_iterator date_item = | |
| 2032 modification_map.find(iter->guid()); | |
| 2033 if (date_item == modification_map.end()) | |
| 2034 return false; | |
| 2035 | |
| 2036 sql::Statement s_date(db_->GetUniqueStatement( | |
| 2037 "UPDATE autofill_profiles SET date_modified=? " | |
| 2038 "WHERE guid=?")); | |
| 2039 s_date.BindInt64(0, date_item->second); | |
| 2040 s_date.BindString(1, iter->guid()); | |
| 2041 | |
| 2042 if (!s_date.Run()) | |
| 2043 return false; | |
| 2044 } | |
| 2045 | |
| 2046 return true; | |
| 2047 } | |
| OLD | NEW |