OLD | NEW |
---|---|
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "sql/recovery.h" | 5 #include "sql/recovery.h" |
6 | 6 |
7 #include <stddef.h> | 7 #include <stddef.h> |
8 | 8 |
9 #include "base/files/file_path.h" | 9 #include "base/files/file_path.h" |
10 #include "base/format_macros.h" | 10 #include "base/format_macros.h" |
(...skipping 357 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
368 // seen. |pk_column_count| counts the columns in the primary key. | 368 // seen. |pk_column_count| counts the columns in the primary key. |
369 // |rowid_decl| stores the ROWID version of the last INTEGER column | 369 // |rowid_decl| stores the ROWID version of the last INTEGER column |
370 // seen, which is at |rowid_ofs| in |create_column_decls|. | 370 // seen, which is at |rowid_ofs| in |create_column_decls|. |
371 size_t pk_column_count = 0; | 371 size_t pk_column_count = 0; |
372 size_t rowid_ofs = 0; // Only valid if rowid_decl is set. | 372 size_t rowid_ofs = 0; // Only valid if rowid_decl is set. |
373 std::string rowid_decl; // ROWID version of column |rowid_ofs|. | 373 std::string rowid_decl; // ROWID version of column |rowid_ofs|. |
374 | 374 |
375 while (s.Step()) { | 375 while (s.Step()) { |
376 const std::string column_name(s.ColumnString(1)); | 376 const std::string column_name(s.ColumnString(1)); |
377 const std::string column_type(s.ColumnString(2)); | 377 const std::string column_type(s.ColumnString(2)); |
378 const bool not_null = s.ColumnBool(3); | |
379 const int default_type = s.ColumnType(4); | 378 const int default_type = s.ColumnType(4); |
380 const bool default_is_null = (default_type == COLUMN_TYPE_NULL); | 379 const bool default_is_null = (default_type == COLUMN_TYPE_NULL); |
381 const int pk_column = s.ColumnInt(5); | 380 const int pk_column = s.ColumnInt(5); |
382 | 381 |
383 // http://www.sqlite.org/pragma.html#pragma_table_info documents column 5 as | 382 // http://www.sqlite.org/pragma.html#pragma_table_info documents column 5 as |
384 // the 1-based index of the column in the primary key, otherwise 0. | 383 // the 1-based index of the column in the primary key, otherwise 0. |
385 if (pk_column > 0) | 384 if (pk_column > 0) |
386 ++pk_column_count; | 385 ++pk_column_count; |
387 | 386 |
388 // Construct column declaration as "name type [optional constraint]". | 387 // Construct column declaration as "name type [optional constraint]". |
(...skipping 26 matching lines...) Expand all Loading... | |
415 // - contains("CLOB") -> TEXT | 414 // - contains("CLOB") -> TEXT |
416 // - contains("REAL") -> FLOAT | 415 // - contains("REAL") -> FLOAT |
417 // - contains("FLOA") -> FLOAT | 416 // - contains("FLOA") -> FLOAT |
418 // - other -> "NUMERIC" | 417 // - other -> "NUMERIC" |
419 // Just code those in as they come up. | 418 // Just code those in as they come up. |
420 NOTREACHED() << " Unsupported type " << column_type; | 419 NOTREACHED() << " Unsupported type " << column_type; |
421 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVER_UNRECOGNIZED_TYPE); | 420 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVER_UNRECOGNIZED_TYPE); |
422 return false; | 421 return false; |
423 } | 422 } |
424 | 423 |
425 // If column has constraint "NOT NULL", then inserting NULL into | |
426 // that column will fail. If the column has a non-NULL DEFAULT | |
427 // specified, the INSERT will handle it (see below). If the | |
428 // DEFAULT is also NULL, the row must be filtered out. | |
429 // TODO(shess): The above scenario applies to INSERT OR REPLACE, | |
430 // whereas INSERT OR IGNORE drops such rows. | |
431 // http://www.sqlite.org/lang_conflict.html | |
Ryan Hamilton
2016/02/04 01:38:17
Looks like you planned ahead! Nice comment.
| |
432 if (not_null && default_is_null) | |
433 column_decl += " NOT NULL"; | |
434 | |
435 create_column_decls.push_back(column_decl); | 424 create_column_decls.push_back(column_decl); |
436 | 425 |
437 // Per the NOTE in the header file, convert NULL values to the | 426 // Per the NOTE in the header file, convert NULL values to the |
438 // DEFAULT. All columns could be IFNULL(column_name,default), but | 427 // DEFAULT. All columns could be IFNULL(column_name,default), but |
439 // the NULL case would require special handling either way. | 428 // the NULL case would require special handling either way. |
440 if (default_is_null) { | 429 if (default_is_null) { |
441 insert_columns.push_back(column_name); | 430 insert_columns.push_back(column_name); |
442 } else { | 431 } else { |
443 // The default value appears to be pre-quoted, as if it is | 432 // The default value appears to be pre-quoted, as if it is |
444 // literally from the sqlite_master CREATE statement. | 433 // literally from the sqlite_master CREATE statement. |
(...skipping 12 matching lines...) Expand all Loading... | |
457 // If the PRIMARY KEY was a single INTEGER column, convert it to ROWID. | 446 // If the PRIMARY KEY was a single INTEGER column, convert it to ROWID. |
458 if (pk_column_count == 1 && !rowid_decl.empty()) | 447 if (pk_column_count == 1 && !rowid_decl.empty()) |
459 create_column_decls[rowid_ofs] = rowid_decl; | 448 create_column_decls[rowid_ofs] = rowid_decl; |
460 | 449 |
461 std::string recover_create(base::StringPrintf( | 450 std::string recover_create(base::StringPrintf( |
462 "CREATE VIRTUAL TABLE temp.recover_%s USING recover(corrupt.%s, %s)", | 451 "CREATE VIRTUAL TABLE temp.recover_%s USING recover(corrupt.%s, %s)", |
463 table_name, | 452 table_name, |
464 table_name, | 453 table_name, |
465 base::JoinString(create_column_decls, ",").c_str())); | 454 base::JoinString(create_column_decls, ",").c_str())); |
466 | 455 |
456 // INSERT OR IGNORE means that it will drop rows resulting from constraint | |
457 // violations. INSERT OR REPLACE only handles UNIQUE constraint violations. | |
467 std::string recover_insert(base::StringPrintf( | 458 std::string recover_insert(base::StringPrintf( |
468 "INSERT OR REPLACE INTO main.%s SELECT %s FROM temp.recover_%s", | 459 "INSERT OR IGNORE INTO main.%s SELECT %s FROM temp.recover_%s", |
469 table_name, | 460 table_name, |
470 base::JoinString(insert_columns, ",").c_str(), | 461 base::JoinString(insert_columns, ",").c_str(), |
471 table_name)); | 462 table_name)); |
472 | 463 |
473 std::string recover_drop(base::StringPrintf( | 464 std::string recover_drop(base::StringPrintf( |
474 "DROP TABLE temp.recover_%s", table_name)); | 465 "DROP TABLE temp.recover_%s", table_name)); |
475 | 466 |
476 if (!db()->Execute(recover_create.c_str())) { | 467 if (!db()->Execute(recover_create.c_str())) { |
477 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVER_CREATE); | 468 RecordRecoveryEvent(RECOVERY_FAILED_AUTORECOVER_CREATE); |
478 return false; | 469 return false; |
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
528 } | 519 } |
529 return false; | 520 return false; |
530 } | 521 } |
531 | 522 |
532 RecordRecoveryEvent(RECOVERY_SUCCESS_META_VERSION); | 523 RecordRecoveryEvent(RECOVERY_SUCCESS_META_VERSION); |
533 *version = recovery_version.ColumnInt(0); | 524 *version = recovery_version.ColumnInt(0); |
534 return true; | 525 return true; |
535 } | 526 } |
536 | 527 |
537 } // namespace sql | 528 } // namespace sql |
OLD | NEW |