Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(97)

Side by Side Diff: chrome/browser/webdata/web_database.cc

Issue 6677124: Move migration code out of WebDatabase and into table-specific classes. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/webdata/web_database.h" 5 #include "chrome/browser/webdata/web_database.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <limits>
9 #include <set>
10 #include <string>
11 8
12 #include "app/sql/statement.h" 9 #include "app/sql/statement.h"
13 #include "app/sql/transaction.h" 10 #include "app/sql/transaction.h"
14 #include "base/string_number_conversions.h"
15 #include "chrome/browser/autofill/autofill_country.h"
16 #include "chrome/browser/autofill/autofill_profile.h"
17 #include "chrome/browser/autofill/autofill_type.h"
18 #include "chrome/browser/autofill/personal_data_manager.h"
19 #include "chrome/browser/diagnostics/sqlite_diagnostics.h" 11 #include "chrome/browser/diagnostics/sqlite_diagnostics.h"
20 #include "chrome/browser/webdata/autofill_util.h"
21 #include "chrome/common/guid.h"
22 #include "content/common/notification_service.h" 12 #include "content/common/notification_service.h"
23 13
24 using base::Time;
25
26 namespace { 14 namespace {
27 15
28 // Current version number. Note: when changing the current version number, 16 // Current version number. Note: when changing the current version number,
29 // corresponding changes must happen in the unit tests, and new migration test 17 // corresponding changes must happen in the unit tests, and new migration test
30 // added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|. 18 // added. See |WebDatabaseMigrationTest::kCurrentTestedVersionNumber|.
31 const int kCurrentVersionNumber = 36; 19 const int kCurrentVersionNumber = 36;
32 const int kCompatibleVersionNumber = 36; 20 const int kCompatibleVersionNumber = 36;
33 21
34 // TODO(dhollowa): Find a common place for this. It is duplicated in
35 // personal_data_manager.cc.
36 template<typename T>
37 T* address_of(T& v) {
38 return &v;
39 }
40
41 } // anonymous namespace 22 } // anonymous namespace
42 23
43 WebDatabase::WebDatabase() {} 24 WebDatabase::WebDatabase() {}
44 25
45 WebDatabase::~WebDatabase() {} 26 WebDatabase::~WebDatabase() {}
46 27
47 void WebDatabase::BeginTransaction() { 28 void WebDatabase::BeginTransaction() {
48 db_.BeginTransaction(); 29 db_.BeginTransaction();
49 } 30 }
50 31
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
132 // If the file on disk is an older database version, bring it up to date. 113 // If the file on disk is an older database version, bring it up to date.
133 // If the migration fails we return an error to caller and do not commit 114 // If the migration fails we return an error to caller and do not commit
134 // the migration. 115 // the migration.
135 sql::InitStatus migration_status = MigrateOldVersionsAsNeeded(); 116 sql::InitStatus migration_status = MigrateOldVersionsAsNeeded();
136 if (migration_status != sql::INIT_OK) 117 if (migration_status != sql::INIT_OK)
137 return migration_status; 118 return migration_status;
138 119
139 return transaction.Commit() ? sql::INIT_OK : sql::INIT_FAILURE; 120 return transaction.Commit() ? sql::INIT_OK : sql::INIT_FAILURE;
140 } 121 }
141 122
123 void WebDatabase::ChangeVersion(int version_num,
124 bool update_compatible_version_num) {
125 meta_table_.SetVersionNumber(version_num);
126 if (update_compatible_version_num) {
127 meta_table_.SetCompatibleVersionNumber(
128 std::min(version_num, kCompatibleVersionNumber));
129 }
130 }
131
132 sql::InitStatus WebDatabase::FailedMigrationTo(int version_num) {
133 LOG(WARNING) << "Unable to update web database to version "
134 << version_num << ".";
135 NOTREACHED();
136 return sql::INIT_FAILURE;
137 }
138
142 sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded() { 139 sql::InitStatus WebDatabase::MigrateOldVersionsAsNeeded() {
143 // Migrate if necessary. 140 // Migrate if necessary.
144 int current_version = meta_table_.GetVersionNumber(); 141 int current_version = meta_table_.GetVersionNumber();
145 switch (current_version) { 142 switch (current_version) {
146 // Versions 1 - 19 are unhandled. Version numbers greater than 143 // Versions 1 - 19 are unhandled. Version numbers greater than
147 // kCurrentVersionNumber should have already been weeded out by the caller. 144 // kCurrentVersionNumber should have already been weeded out by the caller.
148 default: 145 default:
149 // When the version is too old, we return failure error code. The schema 146 // When the version is too old, we return failure error code. The schema
150 // is too out of date to migrate. 147 // is too out of date to migrate.
151 // There should not be a released product that makes a database too old to 148 // There should not be a released product that makes a database too old to
152 // migrate. If we do encounter such a legacy database, we will need a 149 // migrate. If we do encounter such a legacy database, we will need a
153 // better solution to handle it (i.e., pop up a dialog to tell the user, 150 // better solution to handle it (i.e., pop up a dialog to tell the user,
154 // erase all their prefs and start over, etc.). 151 // erase all their prefs and start over, etc.).
155 LOG(WARNING) << "Web database version " << current_version << 152 LOG(WARNING) << "Web database version " << current_version <<
156 " is too old to handle."; 153 " is too old to handle.";
157 NOTREACHED(); 154 NOTREACHED();
158 return sql::INIT_FAILURE; 155 return sql::INIT_FAILURE;
159 156
160 case 20: 157 case 20:
161 // Add the autogenerate_keyword column. 158 if (!keyword_table_->AddAutoGenerateKeywordColumnForVersion21())
162 if (!db_.Execute("ALTER TABLE keywords ADD COLUMN autogenerate_keyword " 159 return FailedMigrationTo(21);
163 "INTEGER DEFAULT 0")) { 160
164 LOG(WARNING) << "Unable to update web database to version 21."; 161 ChangeVersion(21, true);
165 NOTREACHED();
166 return sql::INIT_FAILURE;
167 }
168 meta_table_.SetVersionNumber(21);
169 meta_table_.SetCompatibleVersionNumber(
170 std::min(21, kCompatibleVersionNumber));
171 // FALL THROUGH 162 // FALL THROUGH
172 163
173 case 21: 164 case 21:
174 if (!autofill_table_->ClearAutofillEmptyValueElements()) { 165 if (!autofill_table_->ClearAutofillEmptyValueElements())
175 LOG(WARNING) << "Failed to clean-up autofill DB."; 166 return FailedMigrationTo(22);
176 NOTREACHED();
177 return sql::INIT_FAILURE;
178 }
179 meta_table_.SetVersionNumber(22);
180 // No change in the compatibility version number.
181 167
168 ChangeVersion(22, false);
182 // FALL THROUGH 169 // FALL THROUGH
183 170
184 case 22: 171 case 22:
185 // Add the card_number_encrypted column if credit card table was not 172 if (!autofill_table_->AddCardNumberEncryptedColumnForVersion23())
186 // created in this build (otherwise the column already exists). 173 return FailedMigrationTo(23);
187 // WARNING: Do not change the order of the execution of the SQL
188 // statements in this case! Profile corruption and data migration
189 // issues WILL OCCUR. (see http://crbug.com/10913)
190 //
191 // The problem is that if a user has a profile which was created before
192 // r37036, when the credit_cards table was added, and then failed to
193 // update this profile between the credit card addition and the addition
194 // of the "encrypted" columns (44963), the next data migration will put
195 // the user's profile in an incoherent state: The user will update from
196 // a data profile set to be earlier than 22, and therefore pass through
197 // this update case. But because the user did not have a credit_cards
198 // table before starting Chrome, it will have just been initialized
199 // above, and so already have these columns -- and thus this data
200 // update step will have failed.
201 //
202 // The false assumption in this case is that at this step in the
203 // migration, the user has a credit card table, and that this
204 // table does not include encrypted columns!
205 // Because this case does not roll back the complete set of SQL
206 // transactions properly in case of failure (that is, it does not
207 // roll back the table initialization done above), the incoherent
208 // profile will now see itself as being at version 22 -- but include a
209 // fully initialized credit_cards table. Every time Chrome runs, it
210 // will try to update the web database and fail at this step, unless
211 // we allow for the faulty assumption described above by checking for
212 // the existence of the columns only AFTER we've executed the commands
213 // to add them.
214 if (!db_.DoesColumnExist("credit_cards", "card_number_encrypted")) {
215 if (!db_.Execute("ALTER TABLE credit_cards ADD COLUMN "
216 "card_number_encrypted BLOB DEFAULT NULL")) {
217 LOG(WARNING) << "Could not add card_number_encrypted to "
218 "credit_cards table.";
219 NOTREACHED();
220 return sql::INIT_FAILURE;
221 }
222 }
223 174
224 if (!db_.DoesColumnExist("credit_cards", "verification_code_encrypted")) { 175 ChangeVersion(23, false);
225 if (!db_.Execute("ALTER TABLE credit_cards ADD COLUMN "
226 "verification_code_encrypted BLOB DEFAULT NULL")) {
227 LOG(WARNING) << "Could not add verification_code_encrypted to "
228 "credit_cards table.";
229 NOTREACHED();
230 return sql::INIT_FAILURE;
231 }
232 }
233 meta_table_.SetVersionNumber(23);
234 // FALL THROUGH 176 // FALL THROUGH
235 177
236 case 23: { 178 case 23:
237 // One-time cleanup for Chromium bug 38364. In the presence of 179 if (!autofill_table_->CleanupOversizedStringFieldsForVersion24())
238 // multi-byte UTF-8 characters, that bug could cause Autofill strings 180 return FailedMigrationTo(24);
239 // to grow larger and more corrupt with each save. The cleanup removes
240 // any row with a string field larger than a reasonable size. The string
241 // fields examined here are precisely the ones that were subject to
242 // corruption by the original bug.
243 const std::string autofill_is_too_big =
244 "max(length(name), length(value)) > 500";
245 181
246 const std::string credit_cards_is_too_big = 182 ChangeVersion(24, false);
247 "max(length(label), length(name_on_card), length(type), "
248 " length(expiration_month), length(expiration_year), "
249 " length(billing_address), length(shipping_address) "
250 ") > 500";
251
252 const std::string autofill_profiles_is_too_big =
253 "max(length(label), length(first_name), "
254 " length(middle_name), length(last_name), length(email), "
255 " length(company_name), length(address_line_1), "
256 " length(address_line_2), length(city), length(state), "
257 " length(zipcode), length(country), length(phone), "
258 " length(fax)) > 500";
259
260 std::string query = "DELETE FROM autofill_dates WHERE pair_id IN ("
261 "SELECT pair_id FROM autofill WHERE " + autofill_is_too_big + ")";
262 if (!db_.Execute(query.c_str())) {
263 LOG(WARNING) << "Unable to update web database to version 24.";
264 NOTREACHED();
265 return sql::INIT_FAILURE;
266 }
267 query = "DELETE FROM autofill WHERE " + autofill_is_too_big;
268 if (!db_.Execute(query.c_str())) {
269 LOG(WARNING) << "Unable to update web database to version 24.";
270 NOTREACHED();
271 return sql::INIT_FAILURE;
272 }
273 // Only delete from legacy credit card tables where specific columns
274 // exist.
275 if (db_.DoesColumnExist("credit_cards", "label") &&
276 db_.DoesColumnExist("credit_cards", "name_on_card") &&
277 db_.DoesColumnExist("credit_cards", "type") &&
278 db_.DoesColumnExist("credit_cards", "expiration_month") &&
279 db_.DoesColumnExist("credit_cards", "expiration_year") &&
280 db_.DoesColumnExist("credit_cards", "billing_address") &&
281 db_.DoesColumnExist("credit_cards", "shipping_address") &&
282 db_.DoesColumnExist("autofill_profiles", "label")) {
283 query = "DELETE FROM credit_cards WHERE (" + credit_cards_is_too_big +
284 ") OR label IN (SELECT label FROM autofill_profiles WHERE " +
285 autofill_profiles_is_too_big + ")";
286 if (!db_.Execute(query.c_str())) {
287 LOG(WARNING) << "Unable to update web database to version 24.";
288 NOTREACHED();
289 return sql::INIT_FAILURE;
290 }
291 }
292 if (db_.DoesColumnExist("autofill_profiles", "label")) {
293 query = "DELETE FROM autofill_profiles WHERE " +
294 autofill_profiles_is_too_big;
295 if (!db_.Execute(query.c_str())) {
296 LOG(WARNING) << "Unable to update web database to version 24.";
297 NOTREACHED();
298 return sql::INIT_FAILURE;
299 }
300 }
301
302 meta_table_.SetVersionNumber(24);
303
304 // FALL THROUGH 183 // FALL THROUGH
305 }
306 184
307 case 24: 185 case 24:
308 // Add the logo_id column if keyword table was not created in this build. 186 if (!keyword_table_->AddLogoIDColumnForVersionVersion25())
309 if (!db_.Execute("ALTER TABLE keywords ADD COLUMN logo_id " 187 return FailedMigrationTo(25);
310 "INTEGER DEFAULT 0")) { 188
311 LOG(WARNING) << "Unable to update web database to version 25."; 189 ChangeVersion(25, true);
312 NOTREACHED();
313 return sql::INIT_FAILURE;
314 }
315 meta_table_.SetVersionNumber(25);
316 meta_table_.SetCompatibleVersionNumber(
317 std::min(25, kCompatibleVersionNumber));
318 // FALL THROUGH 190 // FALL THROUGH
319 191
320 case 25: 192 case 25:
321 // Add the created_by_policy column. 193 if (!keyword_table_->AddCreatedByPolicyColumnForVersion26())
322 if (!db_.Execute("ALTER TABLE keywords ADD COLUMN created_by_policy " 194 return FailedMigrationTo(26);
323 "INTEGER DEFAULT 0")) {
324 LOG(WARNING) << "Unable to update web database to version 26.";
325 NOTREACHED();
326 return sql::INIT_FAILURE;
327 }
328 195
329 meta_table_.SetVersionNumber(26); 196 ChangeVersion(26, true);
330 meta_table_.SetCompatibleVersionNumber(
331 std::min(26, kCompatibleVersionNumber));
332 // FALL THROUGH 197 // FALL THROUGH
333 198
334 case 26: { 199 case 26:
335 // Only migrate from legacy credit card tables where specific columns 200 if (!autofill_table_->UpdateLegacyCreditCardsForVersion27())
336 // exist. 201 return FailedMigrationTo(27);
337 if (db_.DoesColumnExist("credit_cards", "unique_id") &&
338 db_.DoesColumnExist("credit_cards", "billing_address") &&
339 db_.DoesColumnExist("autofill_profiles", "unique_id")) {
340 // Change the credit_cards.billing_address column from a string to an
341 // int. The stored string is the label of an address, so we have to
342 // select the unique ID of this address using the label as a foreign
343 // key into the |autofill_profiles| table.
344 std::string stmt =
345 "SELECT credit_cards.unique_id, autofill_profiles.unique_id "
346 "FROM autofill_profiles, credit_cards "
347 "WHERE credit_cards.billing_address = autofill_profiles.label";
348 sql::Statement s(db_.GetUniqueStatement(stmt.c_str()));
349 if (!s) {
350 LOG(WARNING) << "Statement prepare failed";
351 NOTREACHED();
352 return sql::INIT_FAILURE;
353 }
354 202
355 std::map<int, int> cc_billing_map; 203 ChangeVersion(27, true);
356 while (s.Step())
357 cc_billing_map[s.ColumnInt(0)] = s.ColumnInt(1);
358
359 // Windows already stores the IDs as strings in |billing_address|. Try
360 // to convert those.
361 if (cc_billing_map.empty()) {
362 std::string stmt =
363 "SELECT unique_id,billing_address FROM credit_cards";
364 sql::Statement s(db_.GetUniqueStatement(stmt.c_str()));
365 if (!s) {
366 LOG(WARNING) << "Statement prepare failed";
367 NOTREACHED();
368 return sql::INIT_FAILURE;
369 }
370
371 while (s.Step()) {
372 int id = 0;
373 if (base::StringToInt(s.ColumnString(1), &id))
374 cc_billing_map[s.ColumnInt(0)] = id;
375 }
376 }
377
378 if (!db_.Execute("CREATE TABLE credit_cards_temp ( "
379 "label VARCHAR, "
380 "unique_id INTEGER PRIMARY KEY, "
381 "name_on_card VARCHAR, "
382 "type VARCHAR, "
383 "card_number VARCHAR, "
384 "expiration_month INTEGER, "
385 "expiration_year INTEGER, "
386 "verification_code VARCHAR, "
387 "billing_address INTEGER, "
388 "shipping_address VARCHAR, "
389 "card_number_encrypted BLOB, "
390 "verification_code_encrypted BLOB)")) {
391 LOG(WARNING) << "Unable to update web database to version 27.";
392 NOTREACHED();
393 return sql::INIT_FAILURE;
394 }
395
396 if (!db_.Execute(
397 "INSERT INTO credit_cards_temp "
398 "SELECT label,unique_id,name_on_card,type,card_number,"
399 "expiration_month,expiration_year,verification_code,0,"
400 "shipping_address,card_number_encrypted,"
401 "verification_code_encrypted FROM credit_cards")) {
402 LOG(WARNING) << "Unable to update web database to version 27.";
403 NOTREACHED();
404 return sql::INIT_FAILURE;
405 }
406
407 if (!db_.Execute("DROP TABLE credit_cards")) {
408 LOG(WARNING) << "Unable to update web database to version 27.";
409 NOTREACHED();
410 return sql::INIT_FAILURE;
411 }
412
413 if (!db_.Execute(
414 "ALTER TABLE credit_cards_temp RENAME TO credit_cards")) {
415 LOG(WARNING) << "Unable to update web database to version 27.";
416 NOTREACHED();
417 return sql::INIT_FAILURE;
418 }
419
420 for (std::map<int, int>::const_iterator iter = cc_billing_map.begin();
421 iter != cc_billing_map.end(); ++iter) {
422 sql::Statement s(db_.GetCachedStatement(
423 SQL_FROM_HERE,
424 "UPDATE credit_cards SET billing_address=? WHERE unique_id=?"));
425 if (!s) {
426 LOG(WARNING) << "Statement prepare failed";
427 NOTREACHED();
428 return sql::INIT_FAILURE;
429 }
430
431 s.BindInt(0, (*iter).second);
432 s.BindInt(1, (*iter).first);
433
434 if (!s.Run()) {
435 LOG(WARNING) << "Unable to update web database to version 27.";
436 NOTREACHED();
437 return sql::INIT_FAILURE;
438 }
439 }
440 }
441
442 meta_table_.SetVersionNumber(27);
443 meta_table_.SetCompatibleVersionNumber(
444 std::min(27, kCompatibleVersionNumber));
445
446 // FALL THROUGH 204 // FALL THROUGH
447 }
448 205
449 case 27: 206 case 27:
450 // Add supports_instant to keywords. 207 if (!keyword_table_->AddSupportsInstantColumnForVersion28())
451 if (!db_.Execute("ALTER TABLE keywords ADD COLUMN supports_instant " 208 return FailedMigrationTo(28);
452 "INTEGER DEFAULT 0")) {
453 LOG(WARNING) << "Unable to update web database to version 28.";
454 NOTREACHED();
455 return sql::INIT_FAILURE;
456 }
457 meta_table_.SetVersionNumber(28);
458 meta_table_.SetCompatibleVersionNumber(
459 std::min(28, kCompatibleVersionNumber));
460 209
210 ChangeVersion(28, true);
461 // FALL THROUGH 211 // FALL THROUGH
462 212
463 case 28: 213 case 28:
464 // Keywords loses the column supports_instant and gets instant_url. 214 if (!keyword_table_->ChangeInstantUrlToSupportsInstantForVersion29())
465 if (!db_.Execute("ALTER TABLE keywords ADD COLUMN instant_url " 215 return FailedMigrationTo(29);
466 "VARCHAR")) {
467 LOG(WARNING) << "Unable to update web database to version 29.";
468 NOTREACHED();
469 return sql::INIT_FAILURE;
470 }
471 if (!db_.Execute("CREATE TABLE keywords_temp ("
472 "id INTEGER PRIMARY KEY,"
473 "short_name VARCHAR NOT NULL,"
474 "keyword VARCHAR NOT NULL,"
475 "favicon_url VARCHAR NOT NULL,"
476 "url VARCHAR NOT NULL,"
477 "show_in_default_list INTEGER,"
478 "safe_for_autoreplace INTEGER,"
479 "originating_url VARCHAR,"
480 "date_created INTEGER DEFAULT 0,"
481 "usage_count INTEGER DEFAULT 0,"
482 "input_encodings VARCHAR,"
483 "suggest_url VARCHAR,"
484 "prepopulate_id INTEGER DEFAULT 0,"
485 "autogenerate_keyword INTEGER DEFAULT 0,"
486 "logo_id INTEGER DEFAULT 0,"
487 "created_by_policy INTEGER DEFAULT 0,"
488 "instant_url VARCHAR)")) {
489 LOG(WARNING) << "Unable to update web database to version 29.";
490 NOTREACHED();
491 return sql::INIT_FAILURE;
492 }
493 216
494 if (!db_.Execute( 217 ChangeVersion(29, true);
495 "INSERT INTO keywords_temp "
496 "SELECT id, short_name, keyword, favicon_url, url, "
497 "show_in_default_list, safe_for_autoreplace, originating_url, "
498 "date_created, usage_count, input_encodings, suggest_url, "
499 "prepopulate_id, autogenerate_keyword, logo_id, created_by_policy, "
500 "instant_url FROM keywords")) {
501 LOG(WARNING) << "Unable to update web database to version 29.";
502 NOTREACHED();
503 return sql::INIT_FAILURE;
504 }
505
506 if (!db_.Execute("DROP TABLE keywords")) {
507 LOG(WARNING) << "Unable to update web database to version 29.";
508 NOTREACHED();
509 return sql::INIT_FAILURE;
510 }
511
512 if (!db_.Execute(
513 "ALTER TABLE keywords_temp RENAME TO keywords")) {
514 LOG(WARNING) << "Unable to update web database to version 29.";
515 NOTREACHED();
516 return sql::INIT_FAILURE;
517 }
518
519 meta_table_.SetVersionNumber(29);
520 meta_table_.SetCompatibleVersionNumber(
521 std::min(29, kCompatibleVersionNumber));
522
523 // FALL THROUGH 218 // FALL THROUGH
524 219
525 case 29: 220 case 29:
526 // Add date_modified to autofill_profiles. 221 if (!autofill_table_->AddDateModifedForVersion30())
527 if (!db_.DoesColumnExist("autofill_profiles", "date_modified")) { 222 return FailedMigrationTo(30);
528 if (!db_.Execute("ALTER TABLE autofill_profiles ADD COLUMN "
529 "date_modified INTEGER NON NULL DEFAULT 0")) {
530 LOG(WARNING) << "Unable to update web database to version 30";
531 NOTREACHED();
532 return sql::INIT_FAILURE;
533 }
534 223
535 sql::Statement s(db_.GetUniqueStatement( 224 ChangeVersion(30, true);
536 "UPDATE autofill_profiles SET date_modified=?"));
537 if (!s) {
538 LOG(WARNING) << "Unable to update web database to version 30.";
539 NOTREACHED();
540 return sql::INIT_FAILURE;
541 }
542
543 s.BindInt64(0, Time::Now().ToTimeT());
544
545 if (!s.Run()) {
546 LOG(WARNING) << "Unable to update web database to version 30.";
547 NOTREACHED();
548 return sql::INIT_FAILURE;
549 }
550
551 }
552
553 // Add date_modified to credit_cards.
554 if (!db_.DoesColumnExist("credit_cards", "date_modified")) {
555 if (!db_.Execute("ALTER TABLE credit_cards ADD COLUMN "
556 "date_modified INTEGER NON NULL DEFAULT 0")) {
557 LOG(WARNING) << "Unable to update web database to version 30";
558 NOTREACHED();
559 return sql::INIT_FAILURE;
560 }
561
562 sql::Statement s(db_.GetUniqueStatement(
563 "UPDATE credit_cards SET date_modified=?"));
564 if (!s) {
565 LOG(WARNING) << "Unable to update web database to version 30.";
566 NOTREACHED();
567 return sql::INIT_FAILURE;
568 }
569
570 s.BindInt64(0, Time::Now().ToTimeT());
571
572 if (!s.Run()) {
573 LOG(WARNING) << "Unable to update web database to version 30.";
574 NOTREACHED();
575 return sql::INIT_FAILURE;
576 }
577 }
578
579 meta_table_.SetVersionNumber(30);
580 meta_table_.SetCompatibleVersionNumber(
581 std::min(30, kCompatibleVersionNumber));
582
583 // FALL THROUGH 225 // FALL THROUGH
584 226
585 case 30: 227 case 30:
586 // Add |guid| column to |autofill_profiles| table. 228 if (!autofill_table_->AddGUIDToCreditCardsAndProfilesForVersion31())
587 // Note that we need to check for the guid column's existence due to the 229 return FailedMigrationTo(31);
588 // fact that for a version 22 database the |autofill_profiles| table
589 // gets created fresh with |InitAutofillProfilesTable|.
590 if (!db_.DoesColumnExist("autofill_profiles", "guid")) {
591 if (!db_.Execute("ALTER TABLE autofill_profiles ADD COLUMN "
592 "guid VARCHAR NOT NULL DEFAULT \"\"")) {
593 LOG(WARNING) << "Unable to update web database to version 30.";
594 NOTREACHED();
595 return sql::INIT_FAILURE;
596 }
597 230
598 // Set all the |guid| fields to valid values. 231 ChangeVersion(31, true);
599 {
600 sql::Statement s(db_.GetUniqueStatement("SELECT unique_id "
601 "FROM autofill_profiles"));
602
603 if (!s) {
604 LOG(WARNING) << "Unable to update web database to version 30.";
605 NOTREACHED();
606 return sql::INIT_FAILURE;
607 }
608
609 while (s.Step()) {
610 sql::Statement update_s(
611 db_.GetUniqueStatement("UPDATE autofill_profiles "
612 "SET guid=? WHERE unique_id=?"));
613 if (!update_s) {
614 LOG(WARNING) << "Unable to update web database to version 30.";
615 NOTREACHED();
616 return sql::INIT_FAILURE;
617 }
618 update_s.BindString(0, guid::GenerateGUID());
619 update_s.BindInt(1, s.ColumnInt(0));
620
621 if (!update_s.Run()) {
622 LOG(WARNING) << "Unable to update web database to version 30.";
623 NOTREACHED();
624 return sql::INIT_FAILURE;
625 }
626 }
627 }
628 }
629
630 // Add |guid| column to |credit_cards| table.
631 // Note that we need to check for the guid column's existence due to the
632 // fact that for a version 22 database the |autofill_profiles| table
633 // gets created fresh with |InitAutofillProfilesTable|.
634 if (!db_.DoesColumnExist("credit_cards", "guid")) {
635 if (!db_.Execute("ALTER TABLE credit_cards ADD COLUMN "
636 "guid VARCHAR NOT NULL DEFAULT \"\"")) {
637 LOG(WARNING) << "Unable to update web database to version 30.";
638 NOTREACHED();
639 return sql::INIT_FAILURE;
640 }
641
642 // Set all the |guid| fields to valid values.
643 {
644 sql::Statement s(db_.GetUniqueStatement("SELECT unique_id "
645 "FROM credit_cards"));
646 if (!s) {
647 LOG(WARNING) << "Unable to update web database to version 30.";
648 NOTREACHED();
649 return sql::INIT_FAILURE;
650 }
651
652 while (s.Step()) {
653 sql::Statement update_s(
654 db_.GetUniqueStatement("UPDATE credit_cards "
655 "set guid=? WHERE unique_id=?"));
656 if (!update_s) {
657 LOG(WARNING) << "Unable to update web database to version 30.";
658 NOTREACHED();
659 return sql::INIT_FAILURE;
660 }
661 update_s.BindString(0, guid::GenerateGUID());
662 update_s.BindInt(1, s.ColumnInt(0));
663
664 if (!update_s.Run()) {
665 LOG(WARNING) << "Unable to update web database to version 30.";
666 NOTREACHED();
667 return sql::INIT_FAILURE;
668 }
669 }
670 }
671 }
672
673 meta_table_.SetVersionNumber(31);
674 meta_table_.SetCompatibleVersionNumber(
675 std::min(31, kCompatibleVersionNumber));
676
677 // FALL THROUGH 232 // FALL THROUGH
678 233
679 case 31: 234 case 31:
680 if (db_.DoesColumnExist("autofill_profiles", "unique_id")) { 235 if (!autofill_table_->UpdateProfilesAndCreditCardsForVersion32())
681 if (!db_.Execute("CREATE TABLE autofill_profiles_temp ( " 236 return FailedMigrationTo(32);
682 "guid VARCHAR PRIMARY KEY, "
683 "label VARCHAR, "
684 "first_name VARCHAR, "
685 "middle_name VARCHAR, "
686 "last_name VARCHAR, "
687 "email VARCHAR, "
688 "company_name VARCHAR, "
689 "address_line_1 VARCHAR, "
690 "address_line_2 VARCHAR, "
691 "city VARCHAR, "
692 "state VARCHAR, "
693 "zipcode VARCHAR, "
694 "country VARCHAR, "
695 "phone VARCHAR, "
696 "fax VARCHAR, "
697 "date_modified INTEGER NOT NULL DEFAULT 0)")) {
698 LOG(WARNING) << "Unable to update web database to version 32.";
699 NOTREACHED();
700 return sql::INIT_FAILURE;
701 }
702 237
703 if (!db_.Execute( 238 ChangeVersion(32, true);
704 "INSERT INTO autofill_profiles_temp "
705 "SELECT guid, label, first_name, middle_name, last_name, email, "
706 "company_name, address_line_1, address_line_2, city, state, "
707 "zipcode, country, phone, fax, date_modified "
708 "FROM autofill_profiles")) {
709 LOG(WARNING) << "Unable to update web database to version 32.";
710 NOTREACHED();
711 return sql::INIT_FAILURE;
712 }
713
714 if (!db_.Execute("DROP TABLE autofill_profiles")) {
715 LOG(WARNING) << "Unable to update web database to version 32.";
716 NOTREACHED();
717 return sql::INIT_FAILURE;
718 }
719
720 if (!db_.Execute(
721 "ALTER TABLE autofill_profiles_temp RENAME TO autofill_profiles")) {
722 LOG(WARNING) << "Unable to update web database to version 32.";
723 NOTREACHED();
724 return sql::INIT_FAILURE;
725 }
726 }
727
728 if (db_.DoesColumnExist("credit_cards", "unique_id")) {
729 if (!db_.Execute("CREATE TABLE credit_cards_temp ( "
730 "guid VARCHAR PRIMARY KEY, "
731 "label VARCHAR, "
732 "name_on_card VARCHAR, "
733 "expiration_month INTEGER, "
734 "expiration_year INTEGER, "
735 "card_number_encrypted BLOB, "
736 "date_modified INTEGER NOT NULL DEFAULT 0)")) {
737 LOG(WARNING) << "Unable to update web database to version 32.";
738 NOTREACHED();
739 return sql::INIT_FAILURE;
740 }
741
742 if (!db_.Execute(
743 "INSERT INTO credit_cards_temp "
744 "SELECT guid, label, name_on_card, expiration_month, "
745 "expiration_year, card_number_encrypted, date_modified "
746 "FROM credit_cards")) {
747 LOG(WARNING) << "Unable to update web database to version 32.";
748 NOTREACHED();
749 return sql::INIT_FAILURE;
750 }
751
752 if (!db_.Execute("DROP TABLE credit_cards")) {
753 LOG(WARNING) << "Unable to update web database to version 32.";
754 NOTREACHED();
755 return sql::INIT_FAILURE;
756 }
757
758 if (!db_.Execute(
759 "ALTER TABLE credit_cards_temp RENAME TO credit_cards")) {
760 LOG(WARNING) << "Unable to update web database to version 32.";
761 NOTREACHED();
762 return sql::INIT_FAILURE;
763 }
764 }
765
766 meta_table_.SetVersionNumber(32);
767 meta_table_.SetCompatibleVersionNumber(
768 std::min(32, kCompatibleVersionNumber));
769
770 // FALL THROUGH 239 // FALL THROUGH
771 240
772 case 32: 241 case 32:
773 // Test the existence of the |first_name| column as an indication that 242 if (!autofill_table_->UpdateProfilesBasedOnFirstNameForVersion33())
774 // we need a migration. It is possible that the new |autofill_profiles| 243 return FailedMigrationTo(33);
775 // schema is in place because the table was newly created when migrating
776 // from a pre-version-22 database.
777 if (db_.DoesColumnExist("autofill_profiles", "first_name")) {
778 // Create autofill_profiles_temp table that will receive the data.
779 if (!db_.DoesTableExist("autofill_profiles_temp")) {
780 if (!db_.Execute("CREATE TABLE autofill_profiles_temp ( "
781 "guid VARCHAR PRIMARY KEY, "
782 "company_name VARCHAR, "
783 "address_line_1 VARCHAR, "
784 "address_line_2 VARCHAR, "
785 "city VARCHAR, "
786 "state VARCHAR, "
787 "zipcode VARCHAR, "
788 "country VARCHAR, "
789 "date_modified INTEGER NOT NULL DEFAULT 0)")) {
790 NOTREACHED();
791 return sql::INIT_FAILURE;
792 }
793 }
794 244
795 { 245 ChangeVersion(33, true);
796 sql::Statement s(db_.GetUniqueStatement(
797 "SELECT guid, first_name, middle_name, last_name, email, "
798 "company_name, address_line_1, address_line_2, city, state, "
799 "zipcode, country, phone, fax, date_modified "
800 "FROM autofill_profiles"));
801 while (s.Step()) {
802 AutofillProfile profile;
803 profile.set_guid(s.ColumnString(0));
804 DCHECK(guid::IsValidGUID(profile.guid()));
805
806 profile.SetInfo(NAME_FIRST, s.ColumnString16(1));
807 profile.SetInfo(NAME_MIDDLE, s.ColumnString16(2));
808 profile.SetInfo(NAME_LAST, s.ColumnString16(3));
809 profile.SetInfo(EMAIL_ADDRESS, s.ColumnString16(4));
810 profile.SetInfo(COMPANY_NAME, s.ColumnString16(5));
811 profile.SetInfo(ADDRESS_HOME_LINE1, s.ColumnString16(6));
812 profile.SetInfo(ADDRESS_HOME_LINE2, s.ColumnString16(7));
813 profile.SetInfo(ADDRESS_HOME_CITY, s.ColumnString16(8));
814 profile.SetInfo(ADDRESS_HOME_STATE, s.ColumnString16(9));
815 profile.SetInfo(ADDRESS_HOME_ZIP, s.ColumnString16(10));
816 profile.SetInfo(ADDRESS_HOME_COUNTRY, s.ColumnString16(11));
817 profile.SetInfo(PHONE_HOME_WHOLE_NUMBER, s.ColumnString16(12));
818 profile.SetInfo(PHONE_FAX_WHOLE_NUMBER, s.ColumnString16(13));
819 int64 date_modified = s.ColumnInt64(14);
820
821 sql::Statement s_insert(db_.GetUniqueStatement(
822 "INSERT INTO autofill_profiles_temp"
823 "(guid, company_name, address_line_1, address_line_2, city,"
824 " state, zipcode, country, date_modified)"
825 "VALUES (?,?,?,?,?,?,?,?,?)"));
826 if (!s) {
827 LOG(WARNING) << "Unable to update web database to version 33.";
828 NOTREACHED();
829 return sql::INIT_FAILURE;
830 }
831 s_insert.BindString(0, profile.guid());
832 s_insert.BindString16(1, profile.GetInfo(COMPANY_NAME));
833 s_insert.BindString16(2, profile.GetInfo(ADDRESS_HOME_LINE1));
834 s_insert.BindString16(3, profile.GetInfo(ADDRESS_HOME_LINE2));
835 s_insert.BindString16(4, profile.GetInfo(ADDRESS_HOME_CITY));
836 s_insert.BindString16(5, profile.GetInfo(ADDRESS_HOME_STATE));
837 s_insert.BindString16(6, profile.GetInfo(ADDRESS_HOME_ZIP));
838 s_insert.BindString16(7, profile.GetInfo(ADDRESS_HOME_COUNTRY));
839 s_insert.BindInt64(8, date_modified);
840
841 if (!s_insert.Run()) {
842 NOTREACHED();
843 return sql::INIT_FAILURE;
844 }
845
846 // Add the other bits: names, emails, and phone/fax.
847 if (!autofill_util::AddAutofillProfilePieces(profile, &db_)) {
848 NOTREACHED();
849 return sql::INIT_FAILURE;
850 }
851 }
852 }
853
854 if (!db_.Execute("DROP TABLE autofill_profiles")) {
855 LOG(WARNING) << "Unable to update web database to version 33.";
856 NOTREACHED();
857 return sql::INIT_FAILURE;
858 }
859
860 if (!db_.Execute(
861 "ALTER TABLE autofill_profiles_temp RENAME TO autofill_profiles")) {
862 LOG(WARNING) << "Unable to update web database to version 33.";
863 NOTREACHED();
864 return sql::INIT_FAILURE;
865 }
866 }
867
868 // Remove the labels column from the credit_cards table.
869 if (db_.DoesColumnExist("credit_cards", "label")) {
870 if (!db_.Execute("CREATE TABLE credit_cards_temp ( "
871 "guid VARCHAR PRIMARY KEY, "
872 "name_on_card VARCHAR, "
873 "expiration_month INTEGER, "
874 "expiration_year INTEGER, "
875 "card_number_encrypted BLOB, "
876 "date_modified INTEGER NOT NULL DEFAULT 0)")) {
877 LOG(WARNING) << "Unable to update web database to version 33.";
878 NOTREACHED();
879 return sql::INIT_FAILURE;
880 }
881
882 if (!db_.Execute(
883 "INSERT INTO credit_cards_temp "
884 "SELECT guid, name_on_card, expiration_month, "
885 "expiration_year, card_number_encrypted, date_modified "
886 "FROM credit_cards")) {
887 LOG(WARNING) << "Unable to update web database to version 33.";
888 NOTREACHED();
889 return sql::INIT_FAILURE;
890 }
891
892 if (!db_.Execute("DROP TABLE credit_cards")) {
893 LOG(WARNING) << "Unable to update web database to version 33.";
894 NOTREACHED();
895 return sql::INIT_FAILURE;
896 }
897
898 if (!db_.Execute(
899 "ALTER TABLE credit_cards_temp RENAME TO credit_cards")) {
900 LOG(WARNING) << "Unable to update web database to version 33.";
901 NOTREACHED();
902 return sql::INIT_FAILURE;
903 }
904 }
905
906 meta_table_.SetVersionNumber(33);
907 meta_table_.SetCompatibleVersionNumber(
908 std::min(33, kCompatibleVersionNumber));
909
910 // FALL THROUGH 246 // FALL THROUGH
911 247
912 case 33: 248 case 33:
913 // Test the existence of the |country_code| column as an indication that 249 if (!autofill_table_->UpdatesProfilesBasedOnCountryCodeForVersion34())
914 // we need a migration. It is possible that the new |autofill_profiles| 250 return FailedMigrationTo(34);
915 // schema is in place because the table was newly created when migrating
916 // from a pre-version-22 database.
917 if (!db_.DoesColumnExist("autofill_profiles", "country_code")) {
918 if (!db_.Execute("ALTER TABLE autofill_profiles ADD COLUMN "
919 "country_code VARCHAR")) {
920 LOG(WARNING) << "Unable to update web database to version 33.";
921 NOTREACHED();
922 return sql::INIT_FAILURE;
923 }
924 251
925 // Set all the |country_code| fields to match existing |country| values. 252 ChangeVersion(34, true);
926 {
927 sql::Statement s(db_.GetUniqueStatement("SELECT guid, country "
928 "FROM autofill_profiles"));
929
930 if (!s) {
931 LOG(WARNING) << "Unable to update web database to version 33.";
932 NOTREACHED();
933 return sql::INIT_FAILURE;
934 }
935
936 while (s.Step()) {
937 sql::Statement update_s(
938 db_.GetUniqueStatement("UPDATE autofill_profiles "
939 "SET country_code=? WHERE guid=?"));
940 if (!update_s) {
941 LOG(WARNING) << "Unable to update web database to version 33.";
942 NOTREACHED();
943 return sql::INIT_FAILURE;
944 }
945 string16 country = s.ColumnString16(1);
946 std::string app_locale = AutofillCountry::ApplicationLocale();
947 update_s.BindString(0, AutofillCountry::GetCountryCode(country,
948 app_locale));
949 update_s.BindString(1, s.ColumnString(0));
950
951 if (!update_s.Run()) {
952 LOG(WARNING) << "Unable to update web database to version 33.";
953 NOTREACHED();
954 return sql::INIT_FAILURE;
955 }
956 }
957 }
958 }
959
960 meta_table_.SetVersionNumber(34);
961 meta_table_.SetCompatibleVersionNumber(
962 std::min(34, kCompatibleVersionNumber));
963
964 // FALL THROUGH 253 // FALL THROUGH
965 254
966 case 34: 255 case 34:
967 // Correct all country codes with value "UK" to be "GB". This data 256 if (!autofill_table_->CorrectGreatBritainCountryCodesForVersion35())
968 // was mistakenly introduced in build 686.0. This migration is to clean 257 return FailedMigrationTo(35);
969 // it up. See http://crbug.com/74511 for details.
970 {
971 sql::Statement s(db_.GetUniqueStatement(
972 "UPDATE autofill_profiles SET country_code=\"GB\" "
973 "WHERE country_code=\"UK\""));
974 258
975 if (!s.Run()) { 259 ChangeVersion(35, true);
976 LOG(WARNING) << "Unable to update web database to version 35.";
977 NOTREACHED();
978 return sql::INIT_FAILURE;
979 }
980 }
981
982 meta_table_.SetVersionNumber(35);
983 meta_table_.SetCompatibleVersionNumber(
984 std::min(35, kCompatibleVersionNumber));
985
986 // FALL THROUGH 260 // FALL THROUGH
987 261
988 case 35: 262 case 35:
989 // Merge and cull older profiles where possible. 263 if (!autofill_table_->MergeAndCullOlderProfilesForVersion36())
990 { 264 return FailedMigrationTo(36);
991 sql::Statement s(db_.GetUniqueStatement(
992 "SELECT guid, date_modified "
993 "FROM autofill_profiles"));
994 if (!s) {
995 NOTREACHED() << "Statement prepare failed";
996 return sql::INIT_FAILURE;
997 }
998 265
999 // Accumulate the good profiles. 266 ChangeVersion(36, true);
1000 std::vector<AutofillProfile> accumulated_profiles;
1001 std::vector<AutofillProfile*> accumulated_profiles_p;
1002 std::map<std::string, int64> modification_map;
1003 while (s.Step()) {
1004 std::string guid = s.ColumnString(0);
1005 int64 date_modified = s.ColumnInt64(1);
1006 modification_map.insert(
1007 std::pair<std::string, int64>(guid, date_modified));
1008 AutofillProfile* profile = NULL;
1009 if (!autofill_table_->GetAutofillProfile(guid, &profile)) {
1010 NOTREACHED() << "Bad read of profile.";
1011 return sql::INIT_FAILURE;
1012 }
1013 scoped_ptr<AutofillProfile> p(profile);
1014
1015 if (PersonalDataManager::IsValidLearnableProfile(*p)) {
1016 std::vector<AutofillProfile> merged_profiles;
1017 bool merged = PersonalDataManager::MergeProfile(
1018 *p, accumulated_profiles_p, &merged_profiles);
1019
1020 std::swap(accumulated_profiles, merged_profiles);
1021
1022 accumulated_profiles_p.clear();
1023 accumulated_profiles_p.resize(accumulated_profiles.size());
1024 std::transform(accumulated_profiles.begin(),
1025 accumulated_profiles.end(),
1026 accumulated_profiles_p.begin(),
1027 address_of<AutofillProfile>);
1028
1029 // If the profile got merged trash the original.
1030 if (merged)
1031 autofill_table_->AddAutofillGUIDToTrash(p->guid());
1032 } else {
1033 // An invalid profile, so trash it.
1034 autofill_table_->AddAutofillGUIDToTrash(p->guid());
1035 }
1036 }
1037
1038 // Drop the current profiles.
1039 if (!autofill_table_->ClearAutofillProfiles()) {
1040 LOG(WARNING) << "Unable to update web database to version 36.";
1041 NOTREACHED();
1042 return sql::INIT_FAILURE;
1043 }
1044
1045 // Add the newly merged profiles back in.
1046 for (std::vector<AutofillProfile>::const_iterator
1047 iter = accumulated_profiles.begin();
1048 iter != accumulated_profiles.end();
1049 ++iter) {
1050 if (!autofill_table_->AddAutofillProfile(*iter)) {
1051 LOG(WARNING) << "Unable to update web database to version 36.";
1052 NOTREACHED();
1053 return sql::INIT_FAILURE;
1054 }
1055
1056 // Fix up the original modification date.
1057 std::map<std::string, int64>::const_iterator date_item =
1058 modification_map.find(iter->guid());
1059 if (date_item == modification_map.end()) {
1060 LOG(WARNING) << "Unable to update web database to version 36.";
1061 NOTREACHED();
1062 return sql::INIT_FAILURE;
1063 }
1064 sql::Statement s_date(db_.GetUniqueStatement(
1065 "UPDATE autofill_profiles SET date_modified=? "
1066 "WHERE guid=?"));
1067 s_date.BindInt64(0, date_item->second);
1068 s_date.BindString(1, iter->guid());
1069 if (!s_date.Run()) {
1070 LOG(WARNING) << "Unable to update web database to version 36.";
1071 NOTREACHED();
1072 return sql::INIT_FAILURE;
1073 }
1074 }
1075 }
1076
1077 meta_table_.SetVersionNumber(36);
1078 meta_table_.SetCompatibleVersionNumber(
1079 std::min(36, kCompatibleVersionNumber));
1080
1081 // FALL THROUGH 267 // FALL THROUGH
1082 268
1083 // Add successive versions here. Each should set the version number and 269 // Add successive versions here. Each should set the version number and
1084 // compatible version number as appropriate, then fall through to the next 270 // compatible version number as appropriate, then fall through to the next
1085 // case. 271 // case.
1086 272
1087 case kCurrentVersionNumber: 273 case kCurrentVersionNumber:
1088 // No migration needed. 274 // No migration needed.
1089 return sql::INIT_OK; 275 return sql::INIT_OK;
1090 } 276 }
1091 } 277 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698