Chromium Code Reviews| 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 |