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 <memory> | 9 #include <memory> |
10 #include <string> | 10 #include <string> |
(...skipping 749 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
760 std::unique_ptr<sql::Recovery> recovery = | 760 std::unique_ptr<sql::Recovery> recovery = |
761 sql::Recovery::Begin(&db(), db_path()); | 761 sql::Recovery::Begin(&db(), db_path()); |
762 ASSERT_TRUE(recovery.get()); | 762 ASSERT_TRUE(recovery.get()); |
763 | 763 |
764 // In the current implementation, the PRAGMA successfully runs with no result | 764 // In the current implementation, the PRAGMA successfully runs with no result |
765 // rows. Running with a single result of |0| is also acceptable. | 765 // rows. Running with a single result of |0| is also acceptable. |
766 sql::Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size")); | 766 sql::Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size")); |
767 EXPECT_TRUE(!s.Step() || !s.ColumnInt64(0)); | 767 EXPECT_TRUE(!s.Step() || !s.ColumnInt64(0)); |
768 } | 768 } |
769 | 769 |
| 770 TEST_F(SQLRecoveryTest, RecoverDatabase) { |
| 771 // As a side effect, AUTOINCREMENT creates the sqlite_sequence table for |
| 772 // RecoverDatabase() to handle. |
| 773 ASSERT_TRUE(db().Execute( |
| 774 "CREATE TABLE x (id INTEGER PRIMARY KEY AUTOINCREMENT, v TEXT)")); |
| 775 EXPECT_TRUE(db().Execute("INSERT INTO x (v) VALUES ('turtle')")); |
| 776 EXPECT_TRUE(db().Execute("INSERT INTO x (v) VALUES ('truck')")); |
| 777 EXPECT_TRUE(db().Execute("INSERT INTO x (v) VALUES ('trailer')")); |
| 778 |
| 779 // This table needs index and a unique index to work. |
| 780 ASSERT_TRUE(db().Execute("CREATE TABLE y (name TEXT, v TEXT)")); |
| 781 ASSERT_TRUE(db().Execute("CREATE UNIQUE INDEX y_name ON y(name)")); |
| 782 ASSERT_TRUE(db().Execute("CREATE INDEX y_v ON y(v)")); |
| 783 EXPECT_TRUE(db().Execute("INSERT INTO y VALUES ('jim', 'telephone')")); |
| 784 EXPECT_TRUE(db().Execute("INSERT INTO y VALUES ('bob', 'truck')")); |
| 785 EXPECT_TRUE(db().Execute("INSERT INTO y VALUES ('dean', 'trailer')")); |
| 786 |
| 787 // View which is the intersection of [x.v] and [y.v]. |
| 788 ASSERT_TRUE(db().Execute( |
| 789 "CREATE VIEW v AS SELECT x.v FROM x, y WHERE x.v = y.v")); |
| 790 |
| 791 // When an element is deleted from [x], trigger a delete on [y]. Between the |
| 792 // BEGIN and END, [old] stands for the deleted rows from [x]. |
| 793 ASSERT_TRUE(db().Execute("CREATE TRIGGER t AFTER DELETE ON x " |
| 794 "BEGIN DELETE FROM y WHERE y.v = old.v; END")); |
| 795 |
| 796 // Save aside a copy of the original schema, verifying that it has the created |
| 797 // items plus the sqlite_sequence table. |
| 798 const std::string orig_schema(GetSchema(&db())); |
| 799 ASSERT_EQ(6, std::count(orig_schema.begin(), orig_schema.end(), '\n')); |
| 800 |
| 801 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; |
| 802 const char kYSql[] = "SELECT * FROM y ORDER BY 1"; |
| 803 const char kVSql[] = "SELECT * FROM v ORDER BY 1"; |
| 804 EXPECT_EQ("1|turtle\n2|truck\n3|trailer", |
| 805 ExecuteWithResults(&db(), kXSql, "|", "\n")); |
| 806 EXPECT_EQ("bob|truck\ndean|trailer\njim|telephone", |
| 807 ExecuteWithResults(&db(), kYSql, "|", "\n")); |
| 808 EXPECT_EQ("trailer\ntruck", ExecuteWithResults(&db(), kVSql, "|", "\n")); |
| 809 |
| 810 // Database handle is valid before recovery, poisoned after. |
| 811 const char kTrivialSql[] = "SELECT COUNT(*) FROM sqlite_master"; |
| 812 EXPECT_TRUE(db().IsSQLValid(kTrivialSql)); |
| 813 sql::Recovery::RecoverDatabase(&db(), db_path()); |
| 814 EXPECT_FALSE(db().IsSQLValid(kTrivialSql)); |
| 815 |
| 816 // Since the database was not corrupt, the entire schema and all |
| 817 // data should be recovered. |
| 818 ASSERT_TRUE(Reopen()); |
| 819 ASSERT_EQ(orig_schema, GetSchema(&db())); |
| 820 EXPECT_EQ("1|turtle\n2|truck\n3|trailer", |
| 821 ExecuteWithResults(&db(), kXSql, "|", "\n")); |
| 822 EXPECT_EQ("bob|truck\ndean|trailer\njim|telephone", |
| 823 ExecuteWithResults(&db(), kYSql, "|", "\n")); |
| 824 EXPECT_EQ("trailer\ntruck", ExecuteWithResults(&db(), kVSql, "|", "\n")); |
| 825 |
| 826 // Test that the trigger works. |
| 827 ASSERT_TRUE(db().Execute("DELETE FROM x WHERE v = 'truck'")); |
| 828 EXPECT_EQ("1|turtle\n3|trailer", |
| 829 ExecuteWithResults(&db(), kXSql, "|", "\n")); |
| 830 EXPECT_EQ("dean|trailer\njim|telephone", |
| 831 ExecuteWithResults(&db(), kYSql, "|", "\n")); |
| 832 EXPECT_EQ("trailer", ExecuteWithResults(&db(), kVSql, "|", "\n")); |
| 833 } |
| 834 |
770 } // namespace | 835 } // namespace |
OLD | NEW |