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" |
| 6 |
5 #include <stddef.h> | 7 #include <stddef.h> |
6 | |
7 #include <string> | 8 #include <string> |
| 9 #include <utility> |
8 | 10 |
9 #include "base/bind.h" | 11 #include "base/bind.h" |
10 #include "base/files/file_path.h" | 12 #include "base/files/file_path.h" |
11 #include "base/files/file_util.h" | 13 #include "base/files/file_util.h" |
12 #include "base/files/scoped_temp_dir.h" | 14 #include "base/files/scoped_temp_dir.h" |
13 #include "base/path_service.h" | 15 #include "base/path_service.h" |
14 #include "base/strings/string_number_conversions.h" | 16 #include "base/strings/string_number_conversions.h" |
15 #include "sql/connection.h" | 17 #include "sql/connection.h" |
16 #include "sql/meta_table.h" | 18 #include "sql/meta_table.h" |
17 #include "sql/recovery.h" | |
18 #include "sql/statement.h" | 19 #include "sql/statement.h" |
19 #include "sql/test/paths.h" | 20 #include "sql/test/paths.h" |
20 #include "sql/test/scoped_error_ignorer.h" | 21 #include "sql/test/scoped_error_ignorer.h" |
21 #include "sql/test/sql_test_base.h" | 22 #include "sql/test/sql_test_base.h" |
22 #include "sql/test/test_helpers.h" | 23 #include "sql/test/test_helpers.h" |
23 #include "testing/gtest/include/gtest/gtest.h" | 24 #include "testing/gtest/include/gtest/gtest.h" |
24 #include "third_party/sqlite/sqlite3.h" | 25 #include "third_party/sqlite/sqlite3.h" |
25 | 26 |
26 namespace { | 27 namespace { |
27 | 28 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
86 | 87 |
87 // Recreate the database. | 88 // Recreate the database. |
88 ASSERT_TRUE(db().Execute(kCreateSql)); | 89 ASSERT_TRUE(db().Execute(kCreateSql)); |
89 ASSERT_TRUE(db().Execute(kInsertSql)); | 90 ASSERT_TRUE(db().Execute(kInsertSql)); |
90 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); | 91 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); |
91 | 92 |
92 // Unrecoverable() also razes. | 93 // Unrecoverable() also razes. |
93 { | 94 { |
94 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 95 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
95 ASSERT_TRUE(recovery.get()); | 96 ASSERT_TRUE(recovery.get()); |
96 sql::Recovery::Unrecoverable(recovery.Pass()); | 97 sql::Recovery::Unrecoverable(std::move(recovery)); |
97 | 98 |
98 // TODO(shess): Test that calls to recover.db() start failing. | 99 // TODO(shess): Test that calls to recover.db() start failing. |
99 } | 100 } |
100 EXPECT_FALSE(db().is_open()); | 101 EXPECT_FALSE(db().is_open()); |
101 ASSERT_TRUE(Reopen()); | 102 ASSERT_TRUE(Reopen()); |
102 EXPECT_TRUE(db().is_open()); | 103 EXPECT_TRUE(db().is_open()); |
103 ASSERT_EQ("", GetSchema(&db())); | 104 ASSERT_EQ("", GetSchema(&db())); |
104 | 105 |
105 // Recreate the database. | 106 // Recreate the database. |
106 ASSERT_TRUE(db().Execute(kCreateSql)); | 107 ASSERT_TRUE(db().Execute(kCreateSql)); |
107 ASSERT_TRUE(db().Execute(kInsertSql)); | 108 ASSERT_TRUE(db().Execute(kInsertSql)); |
108 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); | 109 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); |
109 | 110 |
110 // Recovered() replaces the original with the "recovered" version. | 111 // Recovered() replaces the original with the "recovered" version. |
111 { | 112 { |
112 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 113 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
113 ASSERT_TRUE(recovery.get()); | 114 ASSERT_TRUE(recovery.get()); |
114 | 115 |
115 // Create the new version of the table. | 116 // Create the new version of the table. |
116 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 117 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
117 | 118 |
118 // Insert different data to distinguish from original database. | 119 // Insert different data to distinguish from original database. |
119 const char kAltInsertSql[] = "INSERT INTO x VALUES ('That was a test')"; | 120 const char kAltInsertSql[] = "INSERT INTO x VALUES ('That was a test')"; |
120 ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql)); | 121 ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql)); |
121 | 122 |
122 // Successfully recovered. | 123 // Successfully recovered. |
123 ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass())); | 124 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
124 } | 125 } |
125 EXPECT_FALSE(db().is_open()); | 126 EXPECT_FALSE(db().is_open()); |
126 ASSERT_TRUE(Reopen()); | 127 ASSERT_TRUE(Reopen()); |
127 EXPECT_TRUE(db().is_open()); | 128 EXPECT_TRUE(db().is_open()); |
128 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); | 129 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); |
129 | 130 |
130 const char* kXSql = "SELECT * FROM x ORDER BY 1"; | 131 const char* kXSql = "SELECT * FROM x ORDER BY 1"; |
131 ASSERT_EQ("That was a test", | 132 ASSERT_EQ("That was a test", |
132 ExecuteWithResults(&db(), kXSql, "|", "\n")); | 133 ExecuteWithResults(&db(), kXSql, "|", "\n")); |
133 } | 134 } |
(...skipping 22 matching lines...) Expand all Loading... |
156 | 157 |
157 // Re-create the original schema. | 158 // Re-create the original schema. |
158 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 159 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
159 | 160 |
160 // Copy the data from the recovery tables to the new database. | 161 // Copy the data from the recovery tables to the new database. |
161 const char kRecoveryCopySql[] = | 162 const char kRecoveryCopySql[] = |
162 "INSERT INTO x SELECT t FROM recover_x"; | 163 "INSERT INTO x SELECT t FROM recover_x"; |
163 ASSERT_TRUE(recovery->db()->Execute(kRecoveryCopySql)); | 164 ASSERT_TRUE(recovery->db()->Execute(kRecoveryCopySql)); |
164 | 165 |
165 // Successfully recovered. | 166 // Successfully recovered. |
166 ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass())); | 167 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
167 } | 168 } |
168 | 169 |
169 // Since the database was not corrupt, the entire schema and all | 170 // Since the database was not corrupt, the entire schema and all |
170 // data should be recovered. | 171 // data should be recovered. |
171 ASSERT_TRUE(Reopen()); | 172 ASSERT_TRUE(Reopen()); |
172 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); | 173 ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db())); |
173 | 174 |
174 const char* kXSql = "SELECT * FROM x ORDER BY 1"; | 175 const char* kXSql = "SELECT * FROM x ORDER BY 1"; |
175 ASSERT_EQ("That was a test\nThis is a test", | 176 ASSERT_EQ("That was a test\nThis is a test", |
176 ExecuteWithResults(&db(), kXSql, "|", "\n")); | 177 ExecuteWithResults(&db(), kXSql, "|", "\n")); |
(...skipping 20 matching lines...) Expand all Loading... |
197 | 198 |
198 // Replicate data over. | 199 // Replicate data over. |
199 const char kRecoveryCopySql[] = | 200 const char kRecoveryCopySql[] = |
200 "INSERT OR REPLACE INTO x SELECT id, v FROM recover_x"; | 201 "INSERT OR REPLACE INTO x SELECT id, v FROM recover_x"; |
201 | 202 |
202 ASSERT_TRUE(recovery->db()->Execute(kRecoveryCreateSql)); | 203 ASSERT_TRUE(recovery->db()->Execute(kRecoveryCreateSql)); |
203 ASSERT_TRUE(recovery->db()->Execute(kCreateTable)); | 204 ASSERT_TRUE(recovery->db()->Execute(kCreateTable)); |
204 ASSERT_TRUE(recovery->db()->Execute(kCreateIndex)); | 205 ASSERT_TRUE(recovery->db()->Execute(kCreateIndex)); |
205 ASSERT_TRUE(recovery->db()->Execute(kRecoveryCopySql)); | 206 ASSERT_TRUE(recovery->db()->Execute(kRecoveryCopySql)); |
206 | 207 |
207 ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass())); | 208 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
208 } | 209 } |
209 | 210 |
210 // Build a database, corrupt it by making an index reference to | 211 // Build a database, corrupt it by making an index reference to |
211 // deleted row, then recover when a query selects that row. | 212 // deleted row, then recover when a query selects that row. |
212 TEST_F(SQLRecoveryTest, RecoverCorruptIndex) { | 213 TEST_F(SQLRecoveryTest, RecoverCorruptIndex) { |
213 const char kCreateTable[] = "CREATE TABLE x (id INTEGER, v INTEGER)"; | 214 const char kCreateTable[] = "CREATE TABLE x (id INTEGER, v INTEGER)"; |
214 const char kCreateIndex[] = "CREATE UNIQUE INDEX x_id ON x (id)"; | 215 const char kCreateIndex[] = "CREATE UNIQUE INDEX x_id ON x (id)"; |
215 ASSERT_TRUE(db().Execute(kCreateTable)); | 216 ASSERT_TRUE(db().Execute(kCreateTable)); |
216 ASSERT_TRUE(db().Execute(kCreateIndex)); | 217 ASSERT_TRUE(db().Execute(kCreateIndex)); |
217 | 218 |
(...skipping 136 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
354 } | 355 } |
355 | 356 |
356 // Test expected case where everything works. | 357 // Test expected case where everything works. |
357 { | 358 { |
358 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 359 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
359 EXPECT_TRUE(recovery->SetupMeta()); | 360 EXPECT_TRUE(recovery->SetupMeta()); |
360 int version = 0; | 361 int version = 0; |
361 EXPECT_TRUE(recovery->GetMetaVersionNumber(&version)); | 362 EXPECT_TRUE(recovery->GetMetaVersionNumber(&version)); |
362 EXPECT_EQ(kVersion, version); | 363 EXPECT_EQ(kVersion, version); |
363 | 364 |
364 sql::Recovery::Rollback(recovery.Pass()); | 365 sql::Recovery::Rollback(std::move(recovery)); |
365 } | 366 } |
366 ASSERT_TRUE(Reopen()); // Handle was poisoned. | 367 ASSERT_TRUE(Reopen()); // Handle was poisoned. |
367 | 368 |
368 // Test version row missing. | 369 // Test version row missing. |
369 EXPECT_TRUE(db().Execute("DELETE FROM meta WHERE key = 'version'")); | 370 EXPECT_TRUE(db().Execute("DELETE FROM meta WHERE key = 'version'")); |
370 { | 371 { |
371 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 372 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
372 EXPECT_TRUE(recovery->SetupMeta()); | 373 EXPECT_TRUE(recovery->SetupMeta()); |
373 int version = 0; | 374 int version = 0; |
374 EXPECT_FALSE(recovery->GetMetaVersionNumber(&version)); | 375 EXPECT_FALSE(recovery->GetMetaVersionNumber(&version)); |
375 EXPECT_EQ(0, version); | 376 EXPECT_EQ(0, version); |
376 | 377 |
377 sql::Recovery::Rollback(recovery.Pass()); | 378 sql::Recovery::Rollback(std::move(recovery)); |
378 } | 379 } |
379 ASSERT_TRUE(Reopen()); // Handle was poisoned. | 380 ASSERT_TRUE(Reopen()); // Handle was poisoned. |
380 | 381 |
381 // Test meta table missing. | 382 // Test meta table missing. |
382 EXPECT_TRUE(db().Execute("DROP TABLE meta")); | 383 EXPECT_TRUE(db().Execute("DROP TABLE meta")); |
383 { | 384 { |
384 sql::ScopedErrorIgnorer ignore_errors; | 385 sql::ScopedErrorIgnorer ignore_errors; |
385 ignore_errors.IgnoreError(SQLITE_CORRUPT); // From virtual table. | 386 ignore_errors.IgnoreError(SQLITE_CORRUPT); // From virtual table. |
386 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 387 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
387 EXPECT_FALSE(recovery->SetupMeta()); | 388 EXPECT_FALSE(recovery->SetupMeta()); |
(...skipping 29 matching lines...) Expand all Loading... |
417 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); | 418 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); |
418 | 419 |
419 size_t rows = 0; | 420 size_t rows = 0; |
420 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); | 421 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); |
421 EXPECT_EQ(2u, rows); | 422 EXPECT_EQ(2u, rows); |
422 | 423 |
423 // Test that any additional temp tables were cleaned up. | 424 // Test that any additional temp tables were cleaned up. |
424 EXPECT_EQ(temp_schema, | 425 EXPECT_EQ(temp_schema, |
425 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); | 426 ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n")); |
426 | 427 |
427 ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass())); | 428 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
428 } | 429 } |
429 | 430 |
430 // Since the database was not corrupt, the entire schema and all | 431 // Since the database was not corrupt, the entire schema and all |
431 // data should be recovered. | 432 // data should be recovered. |
432 ASSERT_TRUE(Reopen()); | 433 ASSERT_TRUE(Reopen()); |
433 ASSERT_EQ(orig_schema, GetSchema(&db())); | 434 ASSERT_EQ(orig_schema, GetSchema(&db())); |
434 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); | 435 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); |
435 | 436 |
436 // Recovery fails if the target table doesn't exist. | 437 // Recovery fails if the target table doesn't exist. |
437 { | 438 { |
438 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 439 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
439 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 440 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
440 | 441 |
441 // TODO(shess): Should this failure implicitly lead to Raze()? | 442 // TODO(shess): Should this failure implicitly lead to Raze()? |
442 size_t rows = 0; | 443 size_t rows = 0; |
443 EXPECT_FALSE(recovery->AutoRecoverTable("y", 0, &rows)); | 444 EXPECT_FALSE(recovery->AutoRecoverTable("y", 0, &rows)); |
444 | 445 |
445 sql::Recovery::Unrecoverable(recovery.Pass()); | 446 sql::Recovery::Unrecoverable(std::move(recovery)); |
446 } | 447 } |
447 } | 448 } |
448 | 449 |
449 // Test that default values correctly replace nulls. The recovery | 450 // Test that default values correctly replace nulls. The recovery |
450 // virtual table reads directly from the database, so DEFAULT is not | 451 // virtual table reads directly from the database, so DEFAULT is not |
451 // interpretted at that level. | 452 // interpretted at that level. |
452 TEST_F(SQLRecoveryTest, AutoRecoverTableWithDefault) { | 453 TEST_F(SQLRecoveryTest, AutoRecoverTableWithDefault) { |
453 ASSERT_TRUE(db().Execute("CREATE TABLE x (id INTEGER)")); | 454 ASSERT_TRUE(db().Execute("CREATE TABLE x (id INTEGER)")); |
454 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (5)")); | 455 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (5)")); |
455 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (15)")); | 456 ASSERT_TRUE(db().Execute("INSERT INTO x VALUES (15)")); |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
493 | 494 |
494 { | 495 { |
495 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 496 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
496 // Different default to detect which table provides the default. | 497 // Different default to detect which table provides the default. |
497 ASSERT_TRUE(recovery->db()->Execute(final_schema.c_str())); | 498 ASSERT_TRUE(recovery->db()->Execute(final_schema.c_str())); |
498 | 499 |
499 size_t rows = 0; | 500 size_t rows = 0; |
500 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); | 501 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); |
501 EXPECT_EQ(4u, rows); | 502 EXPECT_EQ(4u, rows); |
502 | 503 |
503 ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass())); | 504 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
504 } | 505 } |
505 | 506 |
506 // Since the database was not corrupt, the entire schema and all | 507 // Since the database was not corrupt, the entire schema and all |
507 // data should be recovered. | 508 // data should be recovered. |
508 ASSERT_TRUE(Reopen()); | 509 ASSERT_TRUE(Reopen()); |
509 ASSERT_EQ(final_schema, GetSchema(&db())); | 510 ASSERT_EQ(final_schema, GetSchema(&db())); |
510 ASSERT_EQ(final_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); | 511 ASSERT_EQ(final_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); |
511 } | 512 } |
512 | 513 |
513 // Test that rows with NULL in a NOT NULL column are filtered | 514 // Test that rows with NULL in a NOT NULL column are filtered |
(...skipping 15 matching lines...) Expand all Loading... |
529 ASSERT_NE(kOrigSchema, GetSchema(&db())); | 530 ASSERT_NE(kOrigSchema, GetSchema(&db())); |
530 | 531 |
531 { | 532 { |
532 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 533 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
533 ASSERT_TRUE(recovery->db()->Execute(kFinalSchema)); | 534 ASSERT_TRUE(recovery->db()->Execute(kFinalSchema)); |
534 | 535 |
535 size_t rows = 0; | 536 size_t rows = 0; |
536 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); | 537 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); |
537 EXPECT_EQ(1u, rows); | 538 EXPECT_EQ(1u, rows); |
538 | 539 |
539 ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass())); | 540 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
540 } | 541 } |
541 | 542 |
542 // The schema should be the same, but only one row of data should | 543 // The schema should be the same, but only one row of data should |
543 // have been recovered. | 544 // have been recovered. |
544 ASSERT_TRUE(Reopen()); | 545 ASSERT_TRUE(Reopen()); |
545 ASSERT_EQ(kFinalSchema, GetSchema(&db())); | 546 ASSERT_EQ(kFinalSchema, GetSchema(&db())); |
546 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; | 547 const char kXSql[] = "SELECT * FROM x ORDER BY 1"; |
547 ASSERT_EQ("15|this is a test", ExecuteWithResults(&db(), kXSql, "|", "\n")); | 548 ASSERT_EQ("15|this is a test", ExecuteWithResults(&db(), kXSql, "|", "\n")); |
548 } | 549 } |
549 | 550 |
(...skipping 18 matching lines...) Expand all Loading... |
568 ASSERT_NE(orig_schema, GetSchema(&db())); | 569 ASSERT_NE(orig_schema, GetSchema(&db())); |
569 | 570 |
570 { | 571 { |
571 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 572 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
572 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 573 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
573 | 574 |
574 size_t rows = 0; | 575 size_t rows = 0; |
575 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); | 576 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); |
576 EXPECT_EQ(2u, rows); | 577 EXPECT_EQ(2u, rows); |
577 | 578 |
578 ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass())); | 579 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
579 } | 580 } |
580 | 581 |
581 // Since the database was not corrupt, the entire schema and all | 582 // Since the database was not corrupt, the entire schema and all |
582 // data should be recovered. | 583 // data should be recovered. |
583 ASSERT_TRUE(Reopen()); | 584 ASSERT_TRUE(Reopen()); |
584 ASSERT_EQ(orig_schema, GetSchema(&db())); | 585 ASSERT_EQ(orig_schema, GetSchema(&db())); |
585 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); | 586 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); |
586 } | 587 } |
587 | 588 |
588 // Test that a compound primary key doesn't fire the ROWID code. | 589 // Test that a compound primary key doesn't fire the ROWID code. |
(...skipping 24 matching lines...) Expand all Loading... |
613 ASSERT_NE(orig_schema, GetSchema(&db())); | 614 ASSERT_NE(orig_schema, GetSchema(&db())); |
614 | 615 |
615 { | 616 { |
616 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 617 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
617 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 618 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
618 | 619 |
619 size_t rows = 0; | 620 size_t rows = 0; |
620 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); | 621 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); |
621 EXPECT_EQ(3u, rows); | 622 EXPECT_EQ(3u, rows); |
622 | 623 |
623 ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass())); | 624 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
624 } | 625 } |
625 | 626 |
626 // Since the database was not corrupt, the entire schema and all | 627 // Since the database was not corrupt, the entire schema and all |
627 // data should be recovered. | 628 // data should be recovered. |
628 ASSERT_TRUE(Reopen()); | 629 ASSERT_TRUE(Reopen()); |
629 ASSERT_EQ(orig_schema, GetSchema(&db())); | 630 ASSERT_EQ(orig_schema, GetSchema(&db())); |
630 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); | 631 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); |
631 } | 632 } |
632 | 633 |
633 // Test |extend_columns| support. | 634 // Test |extend_columns| support. |
(...skipping 13 matching lines...) Expand all Loading... |
647 ASSERT_TRUE(db().Execute("UPDATE x SET t1 = 'a test'")); | 648 ASSERT_TRUE(db().Execute("UPDATE x SET t1 = 'a test'")); |
648 ASSERT_NE(orig_schema, GetSchema(&db())); | 649 ASSERT_NE(orig_schema, GetSchema(&db())); |
649 ASSERT_NE(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); | 650 ASSERT_NE(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); |
650 | 651 |
651 { | 652 { |
652 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 653 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
653 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 654 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
654 size_t rows = 0; | 655 size_t rows = 0; |
655 EXPECT_TRUE(recovery->AutoRecoverTable("x", 1, &rows)); | 656 EXPECT_TRUE(recovery->AutoRecoverTable("x", 1, &rows)); |
656 EXPECT_EQ(2u, rows); | 657 EXPECT_EQ(2u, rows); |
657 ASSERT_TRUE(sql::Recovery::Recovered(recovery.Pass())); | 658 ASSERT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
658 } | 659 } |
659 | 660 |
660 // Since the database was not corrupt, the entire schema and all | 661 // Since the database was not corrupt, the entire schema and all |
661 // data should be recovered. | 662 // data should be recovered. |
662 ASSERT_TRUE(Reopen()); | 663 ASSERT_TRUE(Reopen()); |
663 ASSERT_EQ(orig_schema, GetSchema(&db())); | 664 ASSERT_EQ(orig_schema, GetSchema(&db())); |
664 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); | 665 ASSERT_EQ(orig_data, ExecuteWithResults(&db(), kXSql, "|", "\n")); |
665 } | 666 } |
666 | 667 |
667 // Recover a golden file where an interior page has been manually modified so | 668 // Recover a golden file where an interior page has been manually modified so |
(...skipping 14 matching lines...) Expand all Loading... |
682 // Create the new version of the table. | 683 // Create the new version of the table. |
683 const char kCreateSql[] = | 684 const char kCreateSql[] = |
684 "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)"; | 685 "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)"; |
685 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); | 686 ASSERT_TRUE(recovery->db()->Execute(kCreateSql)); |
686 | 687 |
687 size_t rows = 0; | 688 size_t rows = 0; |
688 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); | 689 EXPECT_TRUE(recovery->AutoRecoverTable("x", 0, &rows)); |
689 EXPECT_EQ(43u, rows); | 690 EXPECT_EQ(43u, rows); |
690 | 691 |
691 // Successfully recovered. | 692 // Successfully recovered. |
692 EXPECT_TRUE(sql::Recovery::Recovered(recovery.Pass())); | 693 EXPECT_TRUE(sql::Recovery::Recovered(std::move(recovery))); |
693 } | 694 } |
694 } | 695 } |
695 #endif // !defined(USE_SYSTEM_SQLITE) | 696 #endif // !defined(USE_SYSTEM_SQLITE) |
696 | 697 |
697 // Memory-mapped I/O interacts poorly with I/O errors. Make sure the recovery | 698 // Memory-mapped I/O interacts poorly with I/O errors. Make sure the recovery |
698 // database doesn't accidentally enable it. | 699 // database doesn't accidentally enable it. |
699 TEST_F(SQLRecoveryTest, NoMmap) { | 700 TEST_F(SQLRecoveryTest, NoMmap) { |
700 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); | 701 scoped_ptr<sql::Recovery> recovery = sql::Recovery::Begin(&db(), db_path()); |
701 ASSERT_TRUE(recovery.get()); | 702 ASSERT_TRUE(recovery.get()); |
702 | 703 |
703 // In the current implementation, the PRAGMA successfully runs with no result | 704 // In the current implementation, the PRAGMA successfully runs with no result |
704 // rows. Running with a single result of |0| is also acceptable. | 705 // rows. Running with a single result of |0| is also acceptable. |
705 sql::Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size")); | 706 sql::Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size")); |
706 EXPECT_TRUE(!s.Step() || !s.ColumnInt64(0)); | 707 EXPECT_TRUE(!s.Step() || !s.ColumnInt64(0)); |
707 } | 708 } |
708 | 709 |
709 } // namespace | 710 } // namespace |
OLD | NEW |