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

Side by Side Diff: sql/recovery_unittest.cc

Issue 1666473003: [sql] Remove misleading AutoRecoverTable() parameter. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Give me a night to think about it, and I'll make a pointless change. Created 4 years, 10 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
« sql/recovery.cc ('K') | « sql/recovery.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 #include <string> 8 #include <string>
9 #include <utility> 9 #include <utility>
10 10
(...skipping 411 matching lines...) Expand 10 before | Expand all | Expand 10 after
422 { 422 {
423 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); 423 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
424 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); 424 ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
425 425
426 // Save a copy of the temp db's schema before recovering the table. 426 // Save a copy of the temp db's schema before recovering the table.
427 const char kTempSchemaSql[] = "SELECT name, sql FROM sqlite_temp_master"; 427 const char kTempSchemaSql[] = "SELECT name, sql FROM sqlite_temp_master";
428 const std::string temp_schema( 428 const std::string temp_schema(
429 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); 429 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n"));
430 430
431 size_t rows = 0; 431 size_t rows = 0;
432 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); 432 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
433 EXPECT_EQ(2u, rows); 433 EXPECT_EQ(2u, rows);
434 434
435 // Test that any additional temp tables were cleaned up. 435 // Test that any additional temp tables were cleaned up.
436 EXPECT_EQ(temp_schema, 436 EXPECT_EQ(temp_schema,
437 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); 437 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n"));
438 438
439 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); 439 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery)));
440 } 440 }
441 441
442 // Since the database was not corrupt, the entire schema and all 442 // Since the database was not corrupt, the entire schema and all
443 // data should be recovered. 443 // data should be recovered.
444 ASSERT_TRUE(Reopen()); 444 ASSERT_TRUE(Reopen());
445 ASSERT_EQ(orig_schema, GetSchema(&db())); 445 ASSERT_EQ(orig_schema, GetSchema(&db()));
446 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); 446 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n"));
447 447
448 // Recovery fails if the target table doesn't exist. 448 // Recovery fails if the target table doesn't exist.
449 { 449 {
450 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); 450 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
451 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); 451 ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
452 452
453 // TODO(shess): Should this failure implicitly lead to Raze()? 453 // TODO(shess): Should this failure implicitly lead to Raze()?
454 size_t rows = 0; 454 size_t rows = 0;
455 EXPECT_FALSE(recovery->AutoRecoverTable("y", 0, &rows)); 455 EXPECT_FALSE(recovery->AutoRecoverTable("y", &rows));
456 456
457 sql::Recovery::Unrecoverable(std::move(recovery)); 457 sql::Recovery::Unrecoverable(std::move(recovery));
458 } 458 }
459 } 459 }
460 460
461 // Test that default values correctly replace nulls. The recovery 461 // Test that default values correctly replace nulls. The recovery
462 // virtual table reads directly from the database, so DEFAULT is not 462 // virtual table reads directly from the database, so DEFAULT is not
463 // interpretted at that level. 463 // interpretted at that level.
464 TEST_F(SQLRecoveryTest, AutoRecoverTableWithDefault) { 464 TEST_F(SQLRecoveryTest, AutoRecoverTableWithDefault) {
465 ASSERT_TRUE(db().Execute("CREATE TABLE x (id INTEGER)")); 465 ASSERT_TRUE(db().Execute("CREATE TABLE x (id INTEGER)"));
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
502 while ((pos = final_data.find("5|a'a")) != std::string::npos) { 502 while ((pos = final_data.find("5|a'a")) != std::string::npos) {
503 final_data.replace(pos, 5, "5|c'c"); 503 final_data.replace(pos, 5, "5|c'c");
504 } 504 }
505 505
506 { 506 {
507 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); 507 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
508 // Different default to detect which table provides the default. 508 // Different default to detect which table provides the default.
509 ASSERT_TRUE(recovery->db()->Execute(final_schema.c_str())); 509 ASSERT_TRUE(recovery->db()->Execute(final_schema.c_str()));
510 510
511 size_t rows = 0; 511 size_t rows = 0;
512 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); 512 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
513 EXPECT_EQ(4u, rows); 513 EXPECT_EQ(4u, rows);
514 514
515 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); 515 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery)));
516 } 516 }
517 517
518 // Since the database was not corrupt, the entire schema and all 518 // Since the database was not corrupt, the entire schema and all
519 // data should be recovered. 519 // data should be recovered.
520 ASSERT_TRUE(Reopen()); 520 ASSERT_TRUE(Reopen());
521 ASSERT_EQ(final_schema, GetSchema(&db())); 521 ASSERT_EQ(final_schema, GetSchema(&db()));
522 ASSERT_EQ(final_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); 522 ASSERT_EQ(final_data, ExecuteWithResults(&db(), kXSql, "|", "\n"));
(...skipping 15 matching lines...) Expand all
538 // detect that the recovery code actually ran. 538 // detect that the recovery code actually ran.
539 ASSERT_EQ(kOrigSchema, GetSchema(&db())); 539 ASSERT_EQ(kOrigSchema, GetSchema(&db()));
540 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); 540 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)"));
541 ASSERT_NE(kOrigSchema, GetSchema(&db())); 541 ASSERT_NE(kOrigSchema, GetSchema(&db()));
542 542
543 { 543 {
544 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); 544 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
545 ASSERT_TRUE(recovery->db()->Execute(kFinalSchema)); 545 ASSERT_TRUE(recovery->db()->Execute(kFinalSchema));
546 546
547 size_t rows = 0; 547 size_t rows = 0;
548 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); 548 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
549 EXPECT_EQ(1u, rows); 549 EXPECT_EQ(1u, rows);
550 550
551 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); 551 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery)));
552 } 552 }
553 553
554 // The schema should be the same, but only one row of data should 554 // The schema should be the same, but only one row of data should
555 // have been recovered. 555 // have been recovered.
556 ASSERT_TRUE(Reopen()); 556 ASSERT_TRUE(Reopen());
557 ASSERT_EQ(kFinalSchema, GetSchema(&db())); 557 ASSERT_EQ(kFinalSchema, GetSchema(&db()));
558 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; 558 const char kXSql[] = "SELECT * FROM x ORDER BY 1";
(...skipping 18 matching lines...) Expand all
577 // Create a lame-duck table which will not be propagated by recovery to 577 // Create a lame-duck table which will not be propagated by recovery to
578 // detect that the recovery code actually ran. 578 // detect that the recovery code actually ran.
579 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); 579 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)"));
580 ASSERT_NE(orig_schema, GetSchema(&db())); 580 ASSERT_NE(orig_schema, GetSchema(&db()));
581 581
582 { 582 {
583 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); 583 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
584 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); 584 ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
585 585
586 size_t rows = 0; 586 size_t rows = 0;
587 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); 587 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
588 EXPECT_EQ(2u, rows); 588 EXPECT_EQ(2u, rows);
589 589
590 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); 590 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery)));
591 } 591 }
592 592
593 // Since the database was not corrupt, the entire schema and all 593 // Since the database was not corrupt, the entire schema and all
594 // data should be recovered. 594 // data should be recovered.
595 ASSERT_TRUE(Reopen()); 595 ASSERT_TRUE(Reopen());
596 ASSERT_EQ(orig_schema, GetSchema(&db())); 596 ASSERT_EQ(orig_schema, GetSchema(&db()));
597 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); 597 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n"));
(...skipping 24 matching lines...) Expand all
622 // Create a lame-duck table which will not be propagated by recovery to 622 // Create a lame-duck table which will not be propagated by recovery to
623 // detect that the recovery code actually ran. 623 // detect that the recovery code actually ran.
624 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); 624 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)"));
625 ASSERT_NE(orig_schema, GetSchema(&db())); 625 ASSERT_NE(orig_schema, GetSchema(&db()));
626 626
627 { 627 {
628 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); 628 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
629 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); 629 ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
630 630
631 size_t rows = 0; 631 size_t rows = 0;
632 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); 632 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
633 EXPECT_EQ(3u, rows); 633 EXPECT_EQ(3u, rows);
634 634
635 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); 635 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery)));
636 } 636 }
637 637
638 // Since the database was not corrupt, the entire schema and all 638 // Since the database was not corrupt, the entire schema and all
639 // data should be recovered. 639 // data should be recovered.
640 ASSERT_TRUE(Reopen()); 640 ASSERT_TRUE(Reopen());
641 ASSERT_EQ(orig_schema, GetSchema(&db())); 641 ASSERT_EQ(orig_schema, GetSchema(&db()));
642 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); 642 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n"));
643 } 643 }
644 644
645 // Test |extend_columns| support. 645 // Test recovering from a table with fewer columns than the target.
646 TEST_F(SQLRecoveryTest, AutoRecoverTableExtendColumns) { 646 TEST_F(SQLRecoveryTest, AutoRecoverTableMissingColumns) {
647 const char kCreateSql[] = "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)"; 647 const char kCreateSql[] = "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)";
648 const char kAlterSql[] = "ALTER TABLE x ADD COLUMN t1 TEXT DEFAULT 't'";
648 ASSERT_TRUE(db().Execute(kCreateSql)); 649 ASSERT_TRUE(db().Execute(kCreateSql));
649 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (1, 'This is')")); 650 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (1, 'This is')"));
650 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (2, 'That was')")); 651 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (2, 'That was')"));
651 652
652 // Save aside a copy of the original schema and data. 653 // Generate the expected info by faking a table to match what recovery will
654 // create.
653 const std::string orig_schema(GetSchema(&db())); 655 const std::string orig_schema(GetSchema(&db()));
654 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; 656 const char kXSql[] = "SELECT * FROM x ORDER BY 1";
655 const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); 657 std::string expected_schema;
658 std::string expected_data;
659 {
660 ASSERT_TRUE(db().BeginTransaction());
661 ASSERT_TRUE(db().Execute(kAlterSql));
656 662
657 // Modify the table to add a column, and add data to that column. 663 expected_schema = GetSchema(&db());
658 ASSERT_TRUE(db().Execute("ALTER TABLE x ADD COLUMN t1 TEXT")); 664 expected_data = ExecuteWithResults(&db(), kXSql, "|", "\n");
659 ASSERT_TRUE(db().Execute("UPDATE x SET t1 = 'a test'"));
660 ASSERT_NE(orig_schema, GetSchema(&db()));
661 ASSERT_NE(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n"));
662 665
666 db().RollbackTransaction();
667 }
668
669 // Following tests are pointless if the rollback didn't work.
670 ASSERT_EQ(orig_schema, GetSchema(&db()));
671
672 // Recover the previous version of the table into the altered version.
663 { 673 {
664 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); 674 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
665 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); 675 ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
676 ASSERT_TRUE(recovery->db()->Execute(kAlterSql));
666 size_t rows = 0; 677 size_t rows = 0;
667 EXPECT_TRUE(recovery->AutoRecoverTable("x", 1, &rows)); 678 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
668 EXPECT_EQ(2u, rows); 679 EXPECT_EQ(2u, rows);
669 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); 680 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery)));
670 } 681 }
671 682
672 // Since the database was not corrupt, the entire schema and all 683 // Since the database was not corrupt, the entire schema and all
673 // data should be recovered. 684 // data should be recovered.
674 ASSERT_TRUE(Reopen()); 685 ASSERT_TRUE(Reopen());
675 ASSERT_EQ(orig_schema, GetSchema(&db())); 686 ASSERT_EQ(expected_schema, GetSchema(&db()));
676 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); 687 ASSERT_EQ(expected_data, ExecuteWithResults(&db(), kXSql, "|", "\n"));
677 } 688 }
678 689
679 // Recover a golden file where an interior page has been manually modified so 690 // Recover a golden file where an interior page has been manually modified so
680 // that the number of cells is greater than will fit on a single page. This 691 // that the number of cells is greater than will fit on a single page. This
681 // case happened in <http://crbug.com/387868>. 692 // case happened in <http://crbug.com/387868>.
682 TEST_F(SQLRecoveryTest, Bug387868) { 693 TEST_F(SQLRecoveryTest, Bug387868) {
683 base::FilePath golden_path; 694 base::FilePath golden_path;
684 ASSERT_TRUE(PathService::Get(sql::test::DIR_TEST_DATA, &golden_path)); 695 ASSERT_TRUE(PathService::Get(sql::test::DIR_TEST_DATA, &golden_path));
685 golden_path = golden_path.AppendASCII("recovery_387868"); 696 golden_path = golden_path.AppendASCII("recovery_387868");
686 db().Close(); 697 db().Close();
687 ASSERT_TRUE(base::CopyFile(golden_path, db_path())); 698 ASSERT_TRUE(base::CopyFile(golden_path, db_path()));
688 ASSERT_TRUE(Reopen()); 699 ASSERT_TRUE(Reopen());
689 700
690 { 701 {
691 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); 702 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
692 ASSERT_TRUE(recovery.get()); 703 ASSERT_TRUE(recovery.get());
693 704
694 // Create the new version of the table. 705 // Create the new version of the table.
695 const char kCreateSql[] = 706 const char kCreateSql[] =
696 "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)"; 707 "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)";
697 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); 708 ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
698 709
699 size_t rows = 0; 710 size_t rows = 0;
700 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); 711 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
701 EXPECT_EQ(43u, rows); 712 EXPECT_EQ(43u, rows);
702 713
703 // Successfully recovered. 714 // Successfully recovered.
704 EXPECT_TRUE(sql::Recovery::Recovered(std::move(recovery))); 715 EXPECT_TRUE(sql::Recovery::Recovered(std::move(recovery)));
705 } 716 }
706 } 717 }
707 #endif // !defined(USE_SYSTEM_SQLITE) 718 #endif // !defined(USE_SYSTEM_SQLITE)
708 719
709 // Memory-mapped I/O interacts poorly with I/O errors. Make sure the recovery 720 // Memory-mapped I/O interacts poorly with I/O errors. Make sure the recovery
710 // database doesn't accidentally enable it. 721 // database doesn't accidentally enable it.
711 TEST_F(SQLRecoveryTest, NoMmap) { 722 TEST_F(SQLRecoveryTest, NoMmap) {
712 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); 723 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path());
713 ASSERT_TRUE(recovery.get()); 724 ASSERT_TRUE(recovery.get());
714 725
715 // In the current implementation, the PRAGMA successfully runs with no result 726 // In the current implementation, the PRAGMA successfully runs with no result
716 // rows. Running with a single result of |0| is also acceptable. 727 // rows. Running with a single result of |0| is also acceptable.
717 sql::Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size")); 728 sql::Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size"));
718 EXPECT_TRUE(!s.Step() || !s.ColumnInt64(0)); 729 EXPECT_TRUE(!s.Step() || !s.ColumnInt64(0));
719 } 730 }
720 731
721 } // namespace 732 } // namespace
OLDNEW
« sql/recovery.cc ('K') | « sql/recovery.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698