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 |
| 9 #include <memory> |
8 #include <string> | 10 #include <string> |
9 #include <utility> | 11 #include <utility> |
10 | 12 |
11 #include "base/bind.h" | 13 #include "base/bind.h" |
12 #include "base/files/file_path.h" | 14 #include "base/files/file_path.h" |
13 #include "base/files/file_util.h" | 15 #include "base/files/file_util.h" |
14 #include "base/files/scoped_temp_dir.h" | 16 #include "base/files/scoped_temp_dir.h" |
15 #include "base/path_service.h" | 17 #include "base/path_service.h" |
16 #include "base/strings/string_number_conversions.h" | 18 #include "base/strings/string_number_conversions.h" |
17 #include "sql/connection.h" | 19 #include "sql/connection.h" |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
73 const char kCreateSql[] = "CREATE TABLE x (t TEXT)"; | 75 const char kCreateSql[] = "CREATE TABLE x (t TEXT)"; |
74 const char kInsertSql[] = "INSERT INTO x VALUES ('This is a test')"; | 76 const char kInsertSql[] = "INSERT INTO x VALUES ('This is a test')"; |
75 const char kAltInsertSql[] = "INSERT INTO x VALUES ('That was a test')"; | 77 const char kAltInsertSql[] = "INSERT INTO x VALUES ('That was a test')"; |
76 ASSERT_TRUE(db().Execute(kCreateSql)); | 78 ASSERT_TRUE(db().Execute(kCreateSql)); |
77 ASSERT_TRUE(db().Execute(kInsertSql)); | 79 ASSERT_TRUE(db().Execute(kInsertSql)); |
78 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); | 80 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); |
79 | 81 |
80 // If the Recovery handle goes out of scope without being | 82 // If the Recovery handle goes out of scope without being |
81 // Recovered(), the database is razed. | 83 // Recovered(), the database is razed. |
82 { | 84 { |
83 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 85 std::unique_ptr<sql::Recovery> recovery = |
| 86 sql::Recovery::Begin(&db(), db_path()); |
84 ASSERT_TRUE(recovery.get()); | 87 ASSERT_TRUE(recovery.get()); |
85 } | 88 } |
86 EXPECT_FALSE(db().is_open()); | 89 EXPECT_FALSE(db().is_open()); |
87 ASSERT_TRUE(Reopen()); | 90 ASSERT_TRUE(Reopen()); |
88 EXPECT_TRUE(db().is_open()); | 91 EXPECT_TRUE(db().is_open()); |
89 ASSERT_EQ("", GetSchema(&db())); | 92 ASSERT_EQ("", GetSchema(&db())); |
90 | 93 |
91 // Recreate the database. | 94 // Recreate the database. |
92 ASSERT_TRUE(db().Execute(kCreateSql)); | 95 ASSERT_TRUE(db().Execute(kCreateSql)); |
93 ASSERT_TRUE(db().Execute(kInsertSql)); | 96 ASSERT_TRUE(db().Execute(kInsertSql)); |
94 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); | 97 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); |
95 | 98 |
96 // Unrecoverable() also razes. | 99 // Unrecoverable() also razes. |
97 { | 100 { |
98 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 101 std::unique_ptr<sql::Recovery> recovery = |
| 102 sql::Recovery::Begin(&db(), db_path()); |
99 ASSERT_TRUE(recovery.get()); | 103 ASSERT_TRUE(recovery.get()); |
100 sql::Recovery::Unrecoverable(std::move(recovery)); | 104 sql::Recovery::Unrecoverable(std::move(recovery)); |
101 | 105 |
102 // TODO(shess): Test that calls to recover.db() start failing. | 106 // TODO(shess): Test that calls to recover.db() start failing. |
103 } | 107 } |
104 EXPECT_FALSE(db().is_open()); | 108 EXPECT_FALSE(db().is_open()); |
105 ASSERT_TRUE(Reopen()); | 109 ASSERT_TRUE(Reopen()); |
106 EXPECT_TRUE(db().is_open()); | 110 EXPECT_TRUE(db().is_open()); |
107 ASSERT_EQ("", GetSchema(&db())); | 111 ASSERT_EQ("", GetSchema(&db())); |
108 | 112 |
109 // Attempting to recover a previously-recovered handle fails early. | 113 // Attempting to recover a previously-recovered handle fails early. |
110 { | 114 { |
111 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 115 std::unique_ptr<sql::Recovery> recovery = |
| 116 sql::Recovery::Begin(&db(), db_path()); |
112 ASSERT_TRUE(recovery.get()); | 117 ASSERT_TRUE(recovery.get()); |
113 recovery.reset(); | 118 recovery.reset(); |
114 | 119 |
115 recovery = sql::Recovery::Begin(&db(), db_path()); | 120 recovery = sql::Recovery::Begin(&db(), db_path()); |
116 ASSERT_FALSE(recovery.get()); | 121 ASSERT_FALSE(recovery.get()); |
117 } | 122 } |
118 ASSERT_TRUE(Reopen()); | 123 ASSERT_TRUE(Reopen()); |
119 | 124 |
120 // Recreate the database. | 125 // Recreate the database. |
121 ASSERT_TRUE(db().Execute(kCreateSql)); | 126 ASSERT_TRUE(db().Execute(kCreateSql)); |
122 ASSERT_TRUE(db().Execute(kInsertSql)); | 127 ASSERT_TRUE(db().Execute(kInsertSql)); |
123 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); | 128 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); |
124 | 129 |
125 // Unrecovered table to distinguish from recovered database. | 130 // Unrecovered table to distinguish from recovered database. |
126 ASSERT_TRUE(db().Execute("CREATE TABLE y (c INTEGER)")); | 131 ASSERT_TRUE(db().Execute("CREATE TABLE y (c INTEGER)")); |
127 ASSERT_NE("CREATE TABLE x (t TEXT)", GetSchema(&db())); | 132 ASSERT_NE("CREATE TABLE x (t TEXT)", GetSchema(&db())); |
128 | 133 |
129 // Recovered() replaces the original with the "recovered" version. | 134 // Recovered() replaces the original with the "recovered" version. |
130 { | 135 { |
131 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 136 std::unique_ptr<sql::Recovery> recovery = |
| 137 sql::Recovery::Begin(&db(), db_path()); |
132 ASSERT_TRUE(recovery.get()); | 138 ASSERT_TRUE(recovery.get()); |
133 | 139 |
134 // Create the new version of the table. | 140 // Create the new version of the table. |
135 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 141 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
136 | 142 |
137 // Insert different data to distinguish from original database. | 143 // Insert different data to distinguish from original database. |
138 ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql)); | 144 ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql)); |
139 | 145 |
140 // Successfully recovered. | 146 // Successfully recovered. |
141 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); | 147 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
142 } | 148 } |
143 EXPECT_FALSE(db().is_open()); | 149 EXPECT_FALSE(db().is_open()); |
144 ASSERT_TRUE(Reopen()); | 150 ASSERT_TRUE(Reopen()); |
145 EXPECT_TRUE(db().is_open()); | 151 EXPECT_TRUE(db().is_open()); |
146 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); | 152 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); |
147 | 153 |
148 const char* kXSql = "SELECT * FROM x ORDER BY 1"; | 154 const char* kXSql = "SELECT * FROM x ORDER BY 1"; |
149 ASSERT_EQ("That was a test", | 155 ASSERT_EQ("That was a test", |
150 ExecuteWithResults(&db(), kXSql, "|", "\n")); | 156 ExecuteWithResults(&db(), kXSql, "|", "\n")); |
151 | 157 |
152 // Reset the database contents. | 158 // Reset the database contents. |
153 ASSERT_TRUE(db().Execute("DELETE FROM x")); | 159 ASSERT_TRUE(db().Execute("DELETE FROM x")); |
154 ASSERT_TRUE(db().Execute(kInsertSql)); | 160 ASSERT_TRUE(db().Execute(kInsertSql)); |
155 | 161 |
156 // Rollback() discards recovery progress and leaves the database as it was. | 162 // Rollback() discards recovery progress and leaves the database as it was. |
157 { | 163 { |
158 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 164 std::unique_ptr<sql::Recovery> recovery = |
| 165 sql::Recovery::Begin(&db(), db_path()); |
159 ASSERT_TRUE(recovery.get()); | 166 ASSERT_TRUE(recovery.get()); |
160 | 167 |
161 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 168 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
162 ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql)); | 169 ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql)); |
163 | 170 |
164 sql::Recovery::Rollback(std::move(recovery)); | 171 sql::Recovery::Rollback(std::move(recovery)); |
165 } | 172 } |
166 EXPECT_FALSE(db().is_open()); | 173 EXPECT_FALSE(db().is_open()); |
167 ASSERT_TRUE(Reopen()); | 174 ASSERT_TRUE(Reopen()); |
168 EXPECT_TRUE(db().is_open()); | 175 EXPECT_TRUE(db().is_open()); |
169 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); | 176 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); |
170 | 177 |
171 ASSERT_EQ("This is a test", | 178 ASSERT_EQ("This is a test", |
172 ExecuteWithResults(&db(), kXSql, "|", "\n")); | 179 ExecuteWithResults(&db(), kXSql, "|", "\n")); |
173 } | 180 } |
174 | 181 |
175 // Test operation of the virtual table used by sql::Recovery. | 182 // Test operation of the virtual table used by sql::Recovery. |
176 TEST_F(SQLRecoveryTest, VirtualTable) { | 183 TEST_F(SQLRecoveryTest, VirtualTable) { |
177 const char kCreateSql[] = "CREATE TABLE x (t TEXT)"; | 184 const char kCreateSql[] = "CREATE TABLE x (t TEXT)"; |
178 ASSERT_TRUE(db().Execute(kCreateSql)); | 185 ASSERT_TRUE(db().Execute(kCreateSql)); |
179 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES ('This is a test')")); | 186 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES ('This is a test')")); |
180 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES ('That was a test')")); | 187 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES ('That was a test')")); |
181 | 188 |
182 // Successfully recover the database. | 189 // Successfully recover the database. |
183 { | 190 { |
184 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 191 std::unique_ptr<sql::Recovery> recovery = |
| 192 sql::Recovery::Begin(&db(), db_path()); |
185 | 193 |
186 // Tables to recover original DB, now at [corrupt]. | 194 // Tables to recover original DB, now at [corrupt]. |
187 const char kRecoveryCreateSql[] = | 195 const char kRecoveryCreateSql[] = |
188 "CREATE VIRTUAL TABLE temp.recover_x using recover(" | 196 "CREATE VIRTUAL TABLE temp.recover_x using recover(" |
189 " corrupt.x," | 197 " corrupt.x," |
190 " t TEXT STRICT" | 198 " t TEXT STRICT" |
191 ")"; | 199 ")"; |
192 ASSERT_TRUE(recovery->db()->Execute(kRecoveryCreateSql)); | 200 ASSERT_TRUE(recovery->db()->Execute(kRecoveryCreateSql)); |
193 | 201 |
194 // Re-create the original schema. | 202 // Re-create the original schema. |
(...skipping 19 matching lines...) Expand all Loading... |
214 } | 222 } |
215 | 223 |
216 void RecoveryCallback(sql::Connection* db, const base::FilePath& db_path, | 224 void RecoveryCallback(sql::Connection* db, const base::FilePath& db_path, |
217 const char* create_table, const char* create_index, | 225 const char* create_table, const char* create_index, |
218 int* record_error, int error, sql::Statement* stmt) { | 226 int* record_error, int error, sql::Statement* stmt) { |
219 *record_error = error; | 227 *record_error = error; |
220 | 228 |
221 // Clear the error callback to prevent reentrancy. | 229 // Clear the error callback to prevent reentrancy. |
222 db->reset_error_callback(); | 230 db->reset_error_callback(); |
223 | 231 |
224 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path); | 232 std::unique_ptr<sql::Recovery> recovery = sql::Recovery::Begin(db, db_path); |
225 ASSERT_TRUE(recovery.get()); | 233 ASSERT_TRUE(recovery.get()); |
226 | 234 |
227 ASSERT_TRUE(recovery->db()->Execute(create_table)); | 235 ASSERT_TRUE(recovery->db()->Execute(create_table)); |
228 ASSERT_TRUE(recovery->db()->Execute(create_index)); | 236 ASSERT_TRUE(recovery->db()->Execute(create_index)); |
229 | 237 |
230 size_t rows = 0; | 238 size_t rows = 0; |
231 ASSERT_TRUE(recovery->AutoRecoverTable("x", &rows)); | 239 ASSERT_TRUE(recovery->AutoRecoverTable("x", &rows)); |
232 | 240 |
233 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); | 241 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
234 } | 242 } |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
379 const int kCompatibleVersion = 2; | 387 const int kCompatibleVersion = 2; |
380 | 388 |
381 { | 389 { |
382 sql::MetaTable meta; | 390 sql::MetaTable meta; |
383 EXPECT_TRUE(meta.Init(&db(), kVersion, kCompatibleVersion)); | 391 EXPECT_TRUE(meta.Init(&db(), kVersion, kCompatibleVersion)); |
384 EXPECT_EQ(kVersion, meta.GetVersionNumber()); | 392 EXPECT_EQ(kVersion, meta.GetVersionNumber()); |
385 } | 393 } |
386 | 394 |
387 // Test expected case where everything works. | 395 // Test expected case where everything works. |
388 { | 396 { |
389 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 397 std::unique_ptr<sql::Recovery> recovery = |
| 398 sql::Recovery::Begin(&db(), db_path()); |
390 EXPECT_TRUE(recovery->SetupMeta()); | 399 EXPECT_TRUE(recovery->SetupMeta()); |
391 int version = 0; | 400 int version = 0; |
392 EXPECT_TRUE(recovery->GetMetaVersionNumber(&version)); | 401 EXPECT_TRUE(recovery->GetMetaVersionNumber(&version)); |
393 EXPECT_EQ(kVersion, version); | 402 EXPECT_EQ(kVersion, version); |
394 | 403 |
395 sql::Recovery::Rollback(std::move(recovery)); | 404 sql::Recovery::Rollback(std::move(recovery)); |
396 } | 405 } |
397 ASSERT_TRUE(Reopen()); // Handle was poisoned. | 406 ASSERT_TRUE(Reopen()); // Handle was poisoned. |
398 | 407 |
399 // Test version row missing. | 408 // Test version row missing. |
400 EXPECT_TRUE(db().Execute("DELETE FROM meta WHERE key = 'version'")); | 409 EXPECT_TRUE(db().Execute("DELETE FROM meta WHERE key = 'version'")); |
401 { | 410 { |
402 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 411 std::unique_ptr<sql::Recovery> recovery = |
| 412 sql::Recovery::Begin(&db(), db_path()); |
403 EXPECT_TRUE(recovery->SetupMeta()); | 413 EXPECT_TRUE(recovery->SetupMeta()); |
404 int version = 0; | 414 int version = 0; |
405 EXPECT_FALSE(recovery->GetMetaVersionNumber(&version)); | 415 EXPECT_FALSE(recovery->GetMetaVersionNumber(&version)); |
406 EXPECT_EQ(0, version); | 416 EXPECT_EQ(0, version); |
407 | 417 |
408 sql::Recovery::Rollback(std::move(recovery)); | 418 sql::Recovery::Rollback(std::move(recovery)); |
409 } | 419 } |
410 ASSERT_TRUE(Reopen()); // Handle was poisoned. | 420 ASSERT_TRUE(Reopen()); // Handle was poisoned. |
411 | 421 |
412 // Test meta table missing. | 422 // Test meta table missing. |
413 EXPECT_TRUE(db().Execute("DROP TABLE meta")); | 423 EXPECT_TRUE(db().Execute("DROP TABLE meta")); |
414 { | 424 { |
415 sql::ScopedErrorIgnorer ignore_errors; | 425 sql::ScopedErrorIgnorer ignore_errors; |
416 ignore_errors.IgnoreError(SQLITE_CORRUPT); // From virtual table. | 426 ignore_errors.IgnoreError(SQLITE_CORRUPT); // From virtual table. |
417 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 427 std::unique_ptr<sql::Recovery> recovery = |
| 428 sql::Recovery::Begin(&db(), db_path()); |
418 EXPECT_FALSE(recovery->SetupMeta()); | 429 EXPECT_FALSE(recovery->SetupMeta()); |
419 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); | 430 ASSERT_TRUE(ignore_errors.CheckIgnoredErrors()); |
420 } | 431 } |
421 } | 432 } |
422 | 433 |
423 // Baseline AutoRecoverTable() test. | 434 // Baseline AutoRecoverTable() test. |
424 TEST_F(SQLRecoveryTest, AutoRecoverTable) { | 435 TEST_F(SQLRecoveryTest, AutoRecoverTable) { |
425 // BIGINT and VARCHAR to test type affinity. | 436 // BIGINT and VARCHAR to test type affinity. |
426 const char kCreateSql[] = "CREATE TABLE x (id BIGINT, t TEXT, v VARCHAR)"; | 437 const char kCreateSql[] = "CREATE TABLE x (id BIGINT, t TEXT, v VARCHAR)"; |
427 ASSERT_TRUE(db().Execute(kCreateSql)); | 438 ASSERT_TRUE(db().Execute(kCreateSql)); |
428 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (11, 'This is', 'a test')")); | 439 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (11, 'This is', 'a test')")); |
429 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (5, 'That was', 'a test')")); | 440 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (5, 'That was', 'a test')")); |
430 | 441 |
431 // Save aside a copy of the original schema and data. | 442 // Save aside a copy of the original schema and data. |
432 const std::string orig_schema(GetSchema(&db())); | 443 const std::string orig_schema(GetSchema(&db())); |
433 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; | 444 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; |
434 const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); | 445 const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); |
435 | 446 |
436 // Create a lame-duck table which will not be propagated by recovery to | 447 // Create a lame-duck table which will not be propagated by recovery to |
437 // detect that the recovery code actually ran. | 448 // detect that the recovery code actually ran. |
438 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); | 449 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); |
439 ASSERT_NE(orig_schema, GetSchema(&db())); | 450 ASSERT_NE(orig_schema, GetSchema(&db())); |
440 | 451 |
441 { | 452 { |
442 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 453 std::unique_ptr<sql::Recovery> recovery = |
| 454 sql::Recovery::Begin(&db(), db_path()); |
443 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 455 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
444 | 456 |
445 // Save a copy of the temp db's schema before recovering the table. | 457 // Save a copy of the temp db's schema before recovering the table. |
446 const char kTempSchemaSql[] = "SELECT name, sql FROM sqlite_temp_master"; | 458 const char kTempSchemaSql[] = "SELECT name, sql FROM sqlite_temp_master"; |
447 const std::string temp_schema( | 459 const std::string temp_schema( |
448 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); | 460 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); |
449 | 461 |
450 size_t rows = 0; | 462 size_t rows = 0; |
451 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); | 463 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); |
452 EXPECT_EQ(2u, rows); | 464 EXPECT_EQ(2u, rows); |
453 | 465 |
454 // Test that any additional temp tables were cleaned up. | 466 // Test that any additional temp tables were cleaned up. |
455 EXPECT_EQ(temp_schema, | 467 EXPECT_EQ(temp_schema, |
456 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); | 468 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); |
457 | 469 |
458 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); | 470 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
459 } | 471 } |
460 | 472 |
461 // Since the database was not corrupt, the entire schema and all | 473 // Since the database was not corrupt, the entire schema and all |
462 // data should be recovered. | 474 // data should be recovered. |
463 ASSERT_TRUE(Reopen()); | 475 ASSERT_TRUE(Reopen()); |
464 ASSERT_EQ(orig_schema, GetSchema(&db())); | 476 ASSERT_EQ(orig_schema, GetSchema(&db())); |
465 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); | 477 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); |
466 | 478 |
467 // Recovery fails if the target table doesn't exist. | 479 // Recovery fails if the target table doesn't exist. |
468 { | 480 { |
469 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 481 std::unique_ptr<sql::Recovery> recovery = |
| 482 sql::Recovery::Begin(&db(), db_path()); |
470 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 483 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
471 | 484 |
472 // TODO(shess): Should this failure implicitly lead to Raze()? | 485 // TODO(shess): Should this failure implicitly lead to Raze()? |
473 size_t rows = 0; | 486 size_t rows = 0; |
474 EXPECT_FALSE(recovery->AutoRecoverTable("y", &rows)); | 487 EXPECT_FALSE(recovery->AutoRecoverTable("y", &rows)); |
475 | 488 |
476 sql::Recovery::Unrecoverable(std::move(recovery)); | 489 sql::Recovery::Unrecoverable(std::move(recovery)); |
477 } | 490 } |
478 } | 491 } |
479 | 492 |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
516 std::string final_data(orig_data); | 529 std::string final_data(orig_data); |
517 size_t pos; | 530 size_t pos; |
518 while ((pos = final_schema.find("'a''a'")) != std::string::npos) { | 531 while ((pos = final_schema.find("'a''a'")) != std::string::npos) { |
519 final_schema.replace(pos, 6, "'c''c'"); | 532 final_schema.replace(pos, 6, "'c''c'"); |
520 } | 533 } |
521 while ((pos = final_data.find("5|a'a")) != std::string::npos) { | 534 while ((pos = final_data.find("5|a'a")) != std::string::npos) { |
522 final_data.replace(pos, 5, "5|c'c"); | 535 final_data.replace(pos, 5, "5|c'c"); |
523 } | 536 } |
524 | 537 |
525 { | 538 { |
526 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 539 std::unique_ptr<sql::Recovery> recovery = |
| 540 sql::Recovery::Begin(&db(), db_path()); |
527 // Different default to detect which table provides the default. | 541 // Different default to detect which table provides the default. |
528 ASSERT_TRUE(recovery->db()->Execute(final_schema.c_str())); | 542 ASSERT_TRUE(recovery->db()->Execute(final_schema.c_str())); |
529 | 543 |
530 size_t rows = 0; | 544 size_t rows = 0; |
531 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); | 545 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); |
532 EXPECT_EQ(4u, rows); | 546 EXPECT_EQ(4u, rows); |
533 | 547 |
534 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); | 548 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
535 } | 549 } |
536 | 550 |
(...skipping 16 matching lines...) Expand all Loading... |
553 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (5, null)")); | 567 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (5, null)")); |
554 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (15, 'this is a test')")); | 568 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (15, 'this is a test')")); |
555 | 569 |
556 // Create a lame-duck table which will not be propagated by recovery to | 570 // Create a lame-duck table which will not be propagated by recovery to |
557 // detect that the recovery code actually ran. | 571 // detect that the recovery code actually ran. |
558 ASSERT_EQ(kOrigSchema, GetSchema(&db())); | 572 ASSERT_EQ(kOrigSchema, GetSchema(&db())); |
559 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); | 573 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); |
560 ASSERT_NE(kOrigSchema, GetSchema(&db())); | 574 ASSERT_NE(kOrigSchema, GetSchema(&db())); |
561 | 575 |
562 { | 576 { |
563 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 577 std::unique_ptr<sql::Recovery> recovery = |
| 578 sql::Recovery::Begin(&db(), db_path()); |
564 ASSERT_TRUE(recovery->db()->Execute(kFinalSchema)); | 579 ASSERT_TRUE(recovery->db()->Execute(kFinalSchema)); |
565 | 580 |
566 size_t rows = 0; | 581 size_t rows = 0; |
567 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); | 582 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); |
568 EXPECT_EQ(1u, rows); | 583 EXPECT_EQ(1u, rows); |
569 | 584 |
570 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); | 585 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
571 } | 586 } |
572 | 587 |
573 // The schema should be the same, but only one row of data should | 588 // The schema should be the same, but only one row of data should |
(...skipping 18 matching lines...) Expand all Loading... |
592 const std::string orig_schema(GetSchema(&db())); | 607 const std::string orig_schema(GetSchema(&db())); |
593 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; | 608 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; |
594 const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); | 609 const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); |
595 | 610 |
596 // Create a lame-duck table which will not be propagated by recovery to | 611 // Create a lame-duck table which will not be propagated by recovery to |
597 // detect that the recovery code actually ran. | 612 // detect that the recovery code actually ran. |
598 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); | 613 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); |
599 ASSERT_NE(orig_schema, GetSchema(&db())); | 614 ASSERT_NE(orig_schema, GetSchema(&db())); |
600 | 615 |
601 { | 616 { |
602 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 617 std::unique_ptr<sql::Recovery> recovery = |
| 618 sql::Recovery::Begin(&db(), db_path()); |
603 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 619 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
604 | 620 |
605 size_t rows = 0; | 621 size_t rows = 0; |
606 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); | 622 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); |
607 EXPECT_EQ(2u, rows); | 623 EXPECT_EQ(2u, rows); |
608 | 624 |
609 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); | 625 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
610 } | 626 } |
611 | 627 |
612 // Since the database was not corrupt, the entire schema and all | 628 // Since the database was not corrupt, the entire schema and all |
(...skipping 24 matching lines...) Expand all Loading... |
637 const std::string orig_schema(GetSchema(&db())); | 653 const std::string orig_schema(GetSchema(&db())); |
638 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; | 654 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; |
639 const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); | 655 const std::string orig_data(ExecuteWithResults(&db(), kXSql, "|", "\n")); |
640 | 656 |
641 // Create a lame-duck table which will not be propagated by recovery to | 657 // Create a lame-duck table which will not be propagated by recovery to |
642 // detect that the recovery code actually ran. | 658 // detect that the recovery code actually ran. |
643 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); | 659 ASSERT_TRUE(db().Execute("CREATE TABLE y (c TEXT)")); |
644 ASSERT_NE(orig_schema, GetSchema(&db())); | 660 ASSERT_NE(orig_schema, GetSchema(&db())); |
645 | 661 |
646 { | 662 { |
647 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 663 std::unique_ptr<sql::Recovery> recovery = |
| 664 sql::Recovery::Begin(&db(), db_path()); |
648 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 665 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
649 | 666 |
650 size_t rows = 0; | 667 size_t rows = 0; |
651 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); | 668 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); |
652 EXPECT_EQ(3u, rows); | 669 EXPECT_EQ(3u, rows); |
653 | 670 |
654 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); | 671 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
655 } | 672 } |
656 | 673 |
657 // Since the database was not corrupt, the entire schema and all | 674 // Since the database was not corrupt, the entire schema and all |
(...skipping 25 matching lines...) Expand all Loading... |
683 expected_data = ExecuteWithResults(&db(), kXSql, "|", "\n"); | 700 expected_data = ExecuteWithResults(&db(), kXSql, "|", "\n"); |
684 | 701 |
685 db().RollbackTransaction(); | 702 db().RollbackTransaction(); |
686 } | 703 } |
687 | 704 |
688 // Following tests are pointless if the rollback didn't work. | 705 // Following tests are pointless if the rollback didn't work. |
689 ASSERT_EQ(orig_schema, GetSchema(&db())); | 706 ASSERT_EQ(orig_schema, GetSchema(&db())); |
690 | 707 |
691 // Recover the previous version of the table into the altered version. | 708 // Recover the previous version of the table into the altered version. |
692 { | 709 { |
693 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 710 std::unique_ptr<sql::Recovery> recovery = |
| 711 sql::Recovery::Begin(&db(), db_path()); |
694 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 712 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
695 ASSERT_TRUE(recovery->db()->Execute(kAlterSql)); | 713 ASSERT_TRUE(recovery->db()->Execute(kAlterSql)); |
696 size_t rows = 0; | 714 size_t rows = 0; |
697 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); | 715 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); |
698 EXPECT_EQ(2u, rows); | 716 EXPECT_EQ(2u, rows); |
699 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); | 717 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
700 } | 718 } |
701 | 719 |
702 // Since the database was not corrupt, the entire schema and all | 720 // Since the database was not corrupt, the entire schema and all |
703 // data should be recovered. | 721 // data should be recovered. |
704 ASSERT_TRUE(Reopen()); | 722 ASSERT_TRUE(Reopen()); |
705 ASSERT_EQ(expected_schema, GetSchema(&db())); | 723 ASSERT_EQ(expected_schema, GetSchema(&db())); |
706 ASSERT_EQ(expected_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); | 724 ASSERT_EQ(expected_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); |
707 } | 725 } |
708 | 726 |
709 // Recover a golden file where an interior page has been manually modified so | 727 // Recover a golden file where an interior page has been manually modified so |
710 // that the number of cells is greater than will fit on a single page. This | 728 // that the number of cells is greater than will fit on a single page. This |
711 // case happened in <http://crbug.com/387868>. | 729 // case happened in <http://crbug.com/387868>. |
712 TEST_F(SQLRecoveryTest, Bug387868) { | 730 TEST_F(SQLRecoveryTest, Bug387868) { |
713 base::FilePath golden_path; | 731 base::FilePath golden_path; |
714 ASSERT_TRUE(PathService::Get(sql::test::DIR_TEST_DATA, &golden_path)); | 732 ASSERT_TRUE(PathService::Get(sql::test::DIR_TEST_DATA, &golden_path)); |
715 golden_path = golden_path.AppendASCII("recovery_387868"); | 733 golden_path = golden_path.AppendASCII("recovery_387868"); |
716 db().Close(); | 734 db().Close(); |
717 ASSERT_TRUE(base::CopyFile(golden_path, db_path())); | 735 ASSERT_TRUE(base::CopyFile(golden_path, db_path())); |
718 ASSERT_TRUE(Reopen()); | 736 ASSERT_TRUE(Reopen()); |
719 | 737 |
720 { | 738 { |
721 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 739 std::unique_ptr<sql::Recovery> recovery = |
| 740 sql::Recovery::Begin(&db(), db_path()); |
722 ASSERT_TRUE(recovery.get()); | 741 ASSERT_TRUE(recovery.get()); |
723 | 742 |
724 // Create the new version of the table. | 743 // Create the new version of the table. |
725 const char kCreateSql[] = | 744 const char kCreateSql[] = |
726 "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)"; | 745 "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)"; |
727 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 746 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
728 | 747 |
729 size_t rows = 0; | 748 size_t rows = 0; |
730 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); | 749 EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows)); |
731 EXPECT_EQ(43u, rows); | 750 EXPECT_EQ(43u, rows); |
732 | 751 |
733 // Successfully recovered. | 752 // Successfully recovered. |
734 EXPECT_TRUE(sql::Recovery::Recovered(std::move(recovery))); | 753 EXPECT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
735 } | 754 } |
736 } | 755 } |
737 | 756 |
738 // Memory-mapped I/O interacts poorly with I/O errors. Make sure the recovery | 757 // Memory-mapped I/O interacts poorly with I/O errors. Make sure the recovery |
739 // database doesn't accidentally enable it. | 758 // database doesn't accidentally enable it. |
740 TEST_F(SQLRecoveryTest, NoMmap) { | 759 TEST_F(SQLRecoveryTest, NoMmap) { |
741 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 760 std::unique_ptr<sql::Recovery> recovery = |
| 761 sql::Recovery::Begin(&db(), db_path()); |
742 ASSERT_TRUE(recovery.get()); | 762 ASSERT_TRUE(recovery.get()); |
743 | 763 |
744 // In the current implementation, the PRAGMA successfully runs with no result | 764 // In the current implementation, the PRAGMA successfully runs with no result |
745 // rows. Running with a single result of |0| is also acceptable. | 765 // rows. Running with a single result of |0| is also acceptable. |
746 sql::Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size")); | 766 sql::Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size")); |
747 EXPECT_TRUE(!s.Step() || !s.ColumnInt64(0)); | 767 EXPECT_TRUE(!s.Step() || !s.ColumnInt64(0)); |
748 } | 768 } |
749 | 769 |
750 } // namespace | 770 } // namespace |
OLD | NEW |