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