recovery_unittest.cc 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081
  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
  3. // found in the LICENSE file.
  4. #include "sql/recovery.h"
  5. #include <stddef.h>
  6. #include <memory>
  7. #include <string>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/files/file_path.h"
  11. #include "base/files/file_util.h"
  12. #include "base/files/scoped_temp_dir.h"
  13. #include "base/path_service.h"
  14. #include "base/ranges/algorithm.h"
  15. #include "base/strings/string_number_conversions.h"
  16. #include "base/test/bind.h"
  17. #include "sql/database.h"
  18. #include "sql/meta_table.h"
  19. #include "sql/statement.h"
  20. #include "sql/test/paths.h"
  21. #include "sql/test/scoped_error_expecter.h"
  22. #include "sql/test/test_helpers.h"
  23. #include "testing/gtest/include/gtest/gtest.h"
  24. #include "third_party/sqlite/sqlite3.h"
  25. namespace sql {
  26. namespace {
  27. using sql::test::ExecuteWithResult;
  28. using sql::test::ExecuteWithResults;
  29. // Dump consistent human-readable representation of the database
  30. // schema. For tables or indices, this will contain the sql command
  31. // to create the table or index. For certain automatic SQLite
  32. // structures with no sql, the name is used.
  33. std::string GetSchema(Database* db) {
  34. static const char kSql[] =
  35. "SELECT COALESCE(sql, name) FROM sqlite_schema ORDER BY 1";
  36. return ExecuteWithResults(db, kSql, "|", "\n");
  37. }
  38. class SQLRecoveryTest : public testing::Test {
  39. public:
  40. ~SQLRecoveryTest() override = default;
  41. void SetUp() override {
  42. ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  43. db_path_ = temp_dir_.GetPath().AppendASCII("recovery_test.sqlite");
  44. ASSERT_TRUE(db_.Open(db_path_));
  45. }
  46. bool Reopen() {
  47. db_.Close();
  48. return db_.Open(db_path_);
  49. }
  50. bool OverwriteDatabaseHeader() {
  51. base::File file(db_path_,
  52. base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
  53. static constexpr char kText[] = "Now is the winter of our discontent.";
  54. constexpr int kTextBytes = sizeof(kText) - 1;
  55. return file.Write(0, kText, kTextBytes) == kTextBytes;
  56. }
  57. protected:
  58. base::ScopedTempDir temp_dir_;
  59. base::FilePath db_path_;
  60. Database db_;
  61. };
  62. // Baseline Recovery test covering the different ways to dispose of the
  63. // scoped pointer received from Recovery::Begin().
  64. TEST_F(SQLRecoveryTest, RecoverBasic) {
  65. static const char kCreateSql[] = "CREATE TABLE x (t TEXT)";
  66. static const char kInsertSql[] = "INSERT INTO x VALUES ('This is a test')";
  67. static const char kAltInsertSql[] =
  68. "INSERT INTO x VALUES ('That was a test')";
  69. ASSERT_TRUE(db_.Execute(kCreateSql));
  70. ASSERT_TRUE(db_.Execute(kInsertSql));
  71. ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_));
  72. // If the Recovery handle goes out of scope without being
  73. // Recovered(), the database is razed.
  74. {
  75. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  76. ASSERT_TRUE(recovery.get());
  77. }
  78. EXPECT_FALSE(db_.is_open());
  79. ASSERT_TRUE(Reopen());
  80. EXPECT_TRUE(db_.is_open());
  81. ASSERT_EQ("", GetSchema(&db_));
  82. // Recreate the database.
  83. ASSERT_TRUE(db_.Execute(kCreateSql));
  84. ASSERT_TRUE(db_.Execute(kInsertSql));
  85. ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_));
  86. // Unrecoverable() also razes.
  87. {
  88. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  89. ASSERT_TRUE(recovery.get());
  90. Recovery::Unrecoverable(std::move(recovery));
  91. // TODO(shess): Test that calls to recover.db_ start failing.
  92. }
  93. EXPECT_FALSE(db_.is_open());
  94. ASSERT_TRUE(Reopen());
  95. EXPECT_TRUE(db_.is_open());
  96. ASSERT_EQ("", GetSchema(&db_));
  97. // Attempting to recover a previously-recovered handle fails early.
  98. {
  99. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  100. ASSERT_TRUE(recovery.get());
  101. recovery.reset();
  102. recovery = Recovery::Begin(&db_, db_path_);
  103. ASSERT_FALSE(recovery.get());
  104. }
  105. ASSERT_TRUE(Reopen());
  106. // Recreate the database.
  107. ASSERT_TRUE(db_.Execute(kCreateSql));
  108. ASSERT_TRUE(db_.Execute(kInsertSql));
  109. ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_));
  110. // Unrecovered table to distinguish from recovered database.
  111. ASSERT_TRUE(db_.Execute("CREATE TABLE y (c INTEGER)"));
  112. ASSERT_NE("CREATE TABLE x (t TEXT)", GetSchema(&db_));
  113. // Recovered() replaces the original with the "recovered" version.
  114. {
  115. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  116. ASSERT_TRUE(recovery.get());
  117. // Create the new version of the table.
  118. ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
  119. // Insert different data to distinguish from original database.
  120. ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql));
  121. // Successfully recovered.
  122. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  123. }
  124. EXPECT_FALSE(db_.is_open());
  125. ASSERT_TRUE(Reopen());
  126. EXPECT_TRUE(db_.is_open());
  127. ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_));
  128. const char* kXSql = "SELECT * FROM x ORDER BY 1";
  129. ASSERT_EQ("That was a test", ExecuteWithResult(&db_, kXSql));
  130. // Reset the database contents.
  131. ASSERT_TRUE(db_.Execute("DELETE FROM x"));
  132. ASSERT_TRUE(db_.Execute(kInsertSql));
  133. // Rollback() discards recovery progress and leaves the database as it was.
  134. {
  135. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  136. ASSERT_TRUE(recovery.get());
  137. ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
  138. ASSERT_TRUE(recovery->db()->Execute(kAltInsertSql));
  139. Recovery::Rollback(std::move(recovery));
  140. }
  141. EXPECT_FALSE(db_.is_open());
  142. ASSERT_TRUE(Reopen());
  143. EXPECT_TRUE(db_.is_open());
  144. ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_));
  145. ASSERT_EQ("This is a test", ExecuteWithResult(&db_, kXSql));
  146. }
  147. // Test operation of the virtual table used by Recovery.
  148. TEST_F(SQLRecoveryTest, VirtualTable) {
  149. static const char kCreateSql[] = "CREATE TABLE x (t TEXT)";
  150. ASSERT_TRUE(db_.Execute(kCreateSql));
  151. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('This is a test')"));
  152. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('That was a test')"));
  153. // Successfully recover the database.
  154. {
  155. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  156. // Tables to recover original DB, now at [corrupt].
  157. static const char kRecoveryCreateSql[] =
  158. "CREATE VIRTUAL TABLE temp.recover_x using recover("
  159. " corrupt.x,"
  160. " t TEXT STRICT"
  161. ")";
  162. ASSERT_TRUE(recovery->db()->Execute(kRecoveryCreateSql));
  163. // Re-create the original schema.
  164. ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
  165. // Copy the data from the recovery tables to the new database.
  166. static const char kRecoveryCopySql[] =
  167. "INSERT INTO x SELECT t FROM recover_x";
  168. ASSERT_TRUE(recovery->db()->Execute(kRecoveryCopySql));
  169. // Successfully recovered.
  170. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  171. }
  172. // Since the database was not corrupt, the entire schema and all
  173. // data should be recovered.
  174. ASSERT_TRUE(Reopen());
  175. ASSERT_EQ("CREATE TABLE x (t TEXT)", GetSchema(&db_));
  176. static const char* kXSql = "SELECT * FROM x ORDER BY 1";
  177. ASSERT_EQ("That was a test\nThis is a test",
  178. ExecuteWithResults(&db_, kXSql, "|", "\n"));
  179. }
  180. // Our corruption handling assumes that a corrupt index doesn't impact
  181. // SQL statements that only operate on the associated table. This test verifies
  182. // the assumption.
  183. TEST_F(SQLRecoveryTest, TableIndependentFromCorruptIndex) {
  184. static const char kCreateTable[] =
  185. "CREATE TABLE rows(indexed INTEGER NOT NULL, unindexed INTEGER NOT NULL)";
  186. ASSERT_TRUE(db_.Execute(kCreateTable));
  187. ASSERT_TRUE(db_.Execute("CREATE UNIQUE INDEX rows_index ON rows(indexed)"));
  188. // Populate the table with powers of two. These numbers make it easy to see if
  189. // SUM() missed a row.
  190. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(1, 1)"));
  191. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(2, 2)"));
  192. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(4, 4)"));
  193. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(8, 8)"));
  194. // SQL statement that performs a table scan. SUM(unindexed) heavily nudges
  195. // SQLite to use the table instead of the index.
  196. static const char kUnindexedCountSql[] = "SELECT SUM(unindexed) FROM rows";
  197. EXPECT_EQ("15", ExecuteWithResult(&db_, kUnindexedCountSql))
  198. << "No SQL statement should fail before corruption";
  199. // SQL statement that performs an index scan.
  200. static const char kIndexedCountSql[] =
  201. "SELECT SUM(indexed) FROM rows INDEXED BY rows_index";
  202. EXPECT_EQ("15", ExecuteWithResult(&db_, kIndexedCountSql))
  203. << "Table scan should not fail due to corrupt index";
  204. db_.Close();
  205. ASSERT_TRUE(sql::test::CorruptIndexRootPage(db_path_, "rows_index"));
  206. ASSERT_TRUE(Reopen());
  207. {
  208. sql::test::ScopedErrorExpecter expecter;
  209. expecter.ExpectError(SQLITE_CORRUPT);
  210. EXPECT_FALSE(db_.Execute(kIndexedCountSql))
  211. << "Index scan on corrupt index should fail";
  212. EXPECT_TRUE(expecter.SawExpectedErrors())
  213. << "Index scan on corrupt index should fail";
  214. }
  215. EXPECT_EQ("15", ExecuteWithResult(&db_, kUnindexedCountSql))
  216. << "Table scan should not fail due to corrupt index";
  217. }
  218. TEST_F(SQLRecoveryTest, RecoverCorruptIndex) {
  219. static const char kCreateTable[] =
  220. "CREATE TABLE rows(indexed INTEGER NOT NULL, unindexed INTEGER NOT NULL)";
  221. ASSERT_TRUE(db_.Execute(kCreateTable));
  222. static const char kCreateIndex[] =
  223. "CREATE UNIQUE INDEX rows_index ON rows(indexed)";
  224. ASSERT_TRUE(db_.Execute(kCreateIndex));
  225. // Populate the table with powers of two. These numbers make it easy to see if
  226. // SUM() missed a row.
  227. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(1, 1)"));
  228. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(2, 2)"));
  229. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(4, 4)"));
  230. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(8, 8)"));
  231. db_.Close();
  232. ASSERT_TRUE(sql::test::CorruptIndexRootPage(db_path_, "rows_index"));
  233. ASSERT_TRUE(Reopen());
  234. int error = SQLITE_OK;
  235. db_.set_error_callback(
  236. base::BindLambdaForTesting([&](int sqlite_error, Statement* statement) {
  237. error = sqlite_error;
  238. // Recovery::Begin() does not support a pre-existing error callback.
  239. db_.reset_error_callback();
  240. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  241. ASSERT_TRUE(recovery.get());
  242. ASSERT_TRUE(recovery->db()->Execute(kCreateTable));
  243. ASSERT_TRUE(recovery->db()->Execute(kCreateIndex));
  244. size_t rows = 0;
  245. ASSERT_TRUE(recovery->AutoRecoverTable("rows", &rows));
  246. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  247. }));
  248. // SUM(unindexed) heavily nudges SQLite to use the table instead of the index.
  249. static const char kUnindexedCountSql[] = "SELECT SUM(unindexed) FROM rows";
  250. EXPECT_EQ("15", ExecuteWithResult(&db_, kUnindexedCountSql))
  251. << "Table scan should not fail due to corrupt index";
  252. EXPECT_EQ(SQLITE_OK, error)
  253. << "Successful statement execution should not invoke the error callback";
  254. static const char kIndexedCountSql[] =
  255. "SELECT SUM(indexed) FROM rows INDEXED BY rows_index";
  256. EXPECT_EQ("", ExecuteWithResult(&db_, kIndexedCountSql))
  257. << "Index scan on corrupt index should fail";
  258. EXPECT_EQ(SQLITE_CORRUPT, error)
  259. << "Error callback should be called during scan on corrupt index";
  260. EXPECT_EQ("", ExecuteWithResult(&db_, kUnindexedCountSql))
  261. << "Table scan should not succeed anymore on a poisoned database";
  262. ASSERT_TRUE(Reopen());
  263. // The recovered table has consistency between the index and the table.
  264. EXPECT_EQ("15", ExecuteWithResult(&db_, kUnindexedCountSql))
  265. << "Table should survive database recovery";
  266. EXPECT_EQ("15", ExecuteWithResult(&db_, kIndexedCountSql))
  267. << "Index should be reconstructed during database recovery";
  268. }
  269. TEST_F(SQLRecoveryTest, RecoverCorruptTable) {
  270. // The `filler` column is used to cause a record to overflow multiple pages.
  271. static const char kCreateTable[] =
  272. // clang-format off
  273. "CREATE TABLE rows(indexed INTEGER NOT NULL, unindexed INTEGER NOT NULL,"
  274. "filler BLOB NOT NULL)";
  275. // clang-format on
  276. ASSERT_TRUE(db_.Execute(kCreateTable));
  277. static const char kCreateIndex[] =
  278. "CREATE UNIQUE INDEX rows_index ON rows(indexed)";
  279. ASSERT_TRUE(db_.Execute(kCreateIndex));
  280. // Populate the table with powers of two. These numbers make it easy to see if
  281. // SUM() missed a row.
  282. ASSERT_TRUE(db_.Execute(
  283. "INSERT INTO rows(indexed, unindexed, filler) VALUES(1, 1, x'31')"));
  284. ASSERT_TRUE(db_.Execute(
  285. "INSERT INTO rows(indexed, unindexed, filler) VALUES(2, 2, x'32')"));
  286. ASSERT_TRUE(db_.Execute(
  287. "INSERT INTO rows(indexed, unindexed, filler) VALUES(4, 4, x'34')"));
  288. constexpr int kDbPageSize = 4096;
  289. {
  290. // Insert a record that will overflow the page.
  291. std::vector<uint8_t> large_buffer;
  292. ASSERT_EQ(db_.page_size(), kDbPageSize)
  293. << "Page overflow relies on specific size";
  294. large_buffer.resize(kDbPageSize * 2);
  295. base::ranges::fill(large_buffer, '8');
  296. sql::Statement insert(db_.GetUniqueStatement(
  297. "INSERT INTO rows(indexed,unindexed,filler) VALUES(8,8,?)"));
  298. insert.BindBlob(0, large_buffer);
  299. ASSERT_TRUE(insert.Run());
  300. }
  301. db_.Close();
  302. {
  303. // Zero out the last page of the database. This should be the overflow page
  304. // allocated for the last inserted row. So, deleting it should corrupt the
  305. // rows table.
  306. base::File db_file(db_path_, base::File::FLAG_OPEN | base::File::FLAG_READ |
  307. base::File::FLAG_WRITE);
  308. ASSERT_TRUE(db_file.IsValid());
  309. int64_t db_size = db_file.GetLength();
  310. ASSERT_GT(db_size, kDbPageSize)
  311. << "The database should have multiple pages";
  312. ASSERT_TRUE(db_file.SetLength(db_size - kDbPageSize));
  313. }
  314. {
  315. sql::test::ScopedErrorExpecter expecter;
  316. expecter.ExpectError(SQLITE_CORRUPT);
  317. ASSERT_TRUE(Reopen());
  318. EXPECT_TRUE(expecter.SawExpectedErrors());
  319. // PRAGMAs executed inside Database::Open() will error out.
  320. }
  321. int error = SQLITE_OK;
  322. db_.set_error_callback(
  323. base::BindLambdaForTesting([&](int sqlite_error, Statement* statement) {
  324. error = sqlite_error;
  325. // Recovery::Begin() does not support a pre-existing error callback.
  326. db_.reset_error_callback();
  327. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  328. ASSERT_TRUE(recovery.get());
  329. ASSERT_TRUE(recovery->db()->Execute(kCreateTable));
  330. ASSERT_TRUE(recovery->db()->Execute(kCreateIndex));
  331. size_t rows = 0;
  332. ASSERT_TRUE(recovery->AutoRecoverTable("rows", &rows));
  333. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  334. }));
  335. // SUM(unindexed) heavily nudges SQLite to use the table instead of the index.
  336. static const char kUnindexedCountSql[] = "SELECT SUM(unindexed) FROM rows";
  337. EXPECT_FALSE(db_.Execute(kUnindexedCountSql))
  338. << "Table scan on corrupt table should fail";
  339. EXPECT_EQ(SQLITE_CORRUPT, error)
  340. << "Error callback should be called during scan on corrupt index";
  341. ASSERT_TRUE(Reopen());
  342. // All rows should be recovered. Only the BLOB in the last row was damaged.
  343. EXPECT_EQ("15", ExecuteWithResult(&db_, kUnindexedCountSql))
  344. << "Table should survive database recovery";
  345. static const char kIndexedCountSql[] =
  346. "SELECT SUM(indexed) FROM rows INDEXED BY rows_index";
  347. EXPECT_EQ("15", ExecuteWithResult(&db_, kIndexedCountSql))
  348. << "Index should be reconstructed during database recovery";
  349. }
  350. TEST_F(SQLRecoveryTest, Meta) {
  351. const int kVersion = 3;
  352. const int kCompatibleVersion = 2;
  353. {
  354. MetaTable meta;
  355. EXPECT_TRUE(meta.Init(&db_, kVersion, kCompatibleVersion));
  356. EXPECT_EQ(kVersion, meta.GetVersionNumber());
  357. }
  358. // Test expected case where everything works.
  359. {
  360. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  361. EXPECT_TRUE(recovery->SetupMeta());
  362. int version = 0;
  363. EXPECT_TRUE(recovery->GetMetaVersionNumber(&version));
  364. EXPECT_EQ(kVersion, version);
  365. Recovery::Rollback(std::move(recovery));
  366. }
  367. ASSERT_TRUE(Reopen()); // Handle was poisoned.
  368. // Test version row missing.
  369. EXPECT_TRUE(db_.Execute("DELETE FROM meta WHERE key = 'version'"));
  370. {
  371. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  372. EXPECT_TRUE(recovery->SetupMeta());
  373. int version = 0;
  374. EXPECT_FALSE(recovery->GetMetaVersionNumber(&version));
  375. EXPECT_EQ(0, version);
  376. Recovery::Rollback(std::move(recovery));
  377. }
  378. ASSERT_TRUE(Reopen()); // Handle was poisoned.
  379. // Test meta table missing.
  380. EXPECT_TRUE(db_.Execute("DROP TABLE meta"));
  381. {
  382. sql::test::ScopedErrorExpecter expecter;
  383. expecter.ExpectError(SQLITE_CORRUPT); // From virtual table.
  384. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  385. EXPECT_FALSE(recovery->SetupMeta());
  386. ASSERT_TRUE(expecter.SawExpectedErrors());
  387. }
  388. }
  389. // Baseline AutoRecoverTable() test.
  390. TEST_F(SQLRecoveryTest, AutoRecoverTable) {
  391. // BIGINT and VARCHAR to test type affinity.
  392. static const char kCreateSql[] =
  393. "CREATE TABLE x (id BIGINT, t TEXT, v VARCHAR)";
  394. ASSERT_TRUE(db_.Execute(kCreateSql));
  395. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (11, 'This is', 'a test')"));
  396. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (5, 'That was', 'a test')"));
  397. // Save aside a copy of the original schema and data.
  398. const std::string orig_schema(GetSchema(&db_));
  399. static const char kXSql[] = "SELECT * FROM x ORDER BY 1";
  400. const std::string orig_data(ExecuteWithResults(&db_, kXSql, "|", "\n"));
  401. // Create a lame-duck table which will not be propagated by recovery to
  402. // detect that the recovery code actually ran.
  403. ASSERT_TRUE(db_.Execute("CREATE TABLE y (c TEXT)"));
  404. ASSERT_NE(orig_schema, GetSchema(&db_));
  405. {
  406. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  407. ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
  408. // Save a copy of the temp db's schema before recovering the table.
  409. static const char kTempSchemaSql[] =
  410. "SELECT name, sql FROM sqlite_temp_schema";
  411. const std::string temp_schema(
  412. ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n"));
  413. size_t rows = 0;
  414. EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
  415. EXPECT_EQ(2u, rows);
  416. // Test that any additional temp tables were cleaned up.
  417. EXPECT_EQ(temp_schema,
  418. ExecuteWithResults(recovery->db(), kTempSchemaSql, "|", "\n"));
  419. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  420. }
  421. // Since the database was not corrupt, the entire schema and all
  422. // data should be recovered.
  423. ASSERT_TRUE(Reopen());
  424. ASSERT_EQ(orig_schema, GetSchema(&db_));
  425. ASSERT_EQ(orig_data, ExecuteWithResults(&db_, kXSql, "|", "\n"));
  426. // Recovery fails if the target table doesn't exist.
  427. {
  428. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  429. ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
  430. // TODO(shess): Should this failure implicitly lead to Raze()?
  431. size_t rows = 0;
  432. EXPECT_FALSE(recovery->AutoRecoverTable("y", &rows));
  433. Recovery::Unrecoverable(std::move(recovery));
  434. }
  435. }
  436. // Test that default values correctly replace nulls. The recovery
  437. // virtual table reads directly from the database, so DEFAULT is not
  438. // interpretted at that level.
  439. TEST_F(SQLRecoveryTest, AutoRecoverTableWithDefault) {
  440. ASSERT_TRUE(db_.Execute("CREATE TABLE x (id INTEGER)"));
  441. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (5)"));
  442. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (15)"));
  443. // ALTER effectively leaves the new columns NULL in the first two
  444. // rows. The row with 17 will get the default injected at insert
  445. // time, while the row with 42 will get the actual value provided.
  446. // Embedded "'" to make sure default-handling continues to be quoted
  447. // correctly.
  448. ASSERT_TRUE(db_.Execute("ALTER TABLE x ADD COLUMN t TEXT DEFAULT 'a''a'"));
  449. ASSERT_TRUE(db_.Execute("ALTER TABLE x ADD COLUMN b BLOB DEFAULT x'AA55'"));
  450. ASSERT_TRUE(db_.Execute("ALTER TABLE x ADD COLUMN i INT DEFAULT 93"));
  451. ASSERT_TRUE(db_.Execute("INSERT INTO x (id) VALUES (17)"));
  452. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (42, 'b', x'1234', 12)"));
  453. // Save aside a copy of the original schema and data.
  454. const std::string orig_schema(GetSchema(&db_));
  455. static const char kXSql[] = "SELECT * FROM x ORDER BY 1";
  456. const std::string orig_data(ExecuteWithResults(&db_, kXSql, "|", "\n"));
  457. // Create a lame-duck table which will not be propagated by recovery to
  458. // detect that the recovery code actually ran.
  459. ASSERT_TRUE(db_.Execute("CREATE TABLE y (c TEXT)"));
  460. ASSERT_NE(orig_schema, GetSchema(&db_));
  461. // Mechanically adjust the stored schema and data to allow detecting
  462. // where the default value is coming from. The target table is just
  463. // like the original with the default for [t] changed, to signal
  464. // defaults coming from the recovery system. The two %5 rows should
  465. // get the target-table default for [t], while the others should get
  466. // the source-table default.
  467. std::string final_schema(orig_schema);
  468. std::string final_data(orig_data);
  469. size_t pos;
  470. while ((pos = final_schema.find("'a''a'")) != std::string::npos) {
  471. final_schema.replace(pos, 6, "'c''c'");
  472. }
  473. while ((pos = final_data.find("5|a'a")) != std::string::npos) {
  474. final_data.replace(pos, 5, "5|c'c");
  475. }
  476. {
  477. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  478. // Different default to detect which table provides the default.
  479. ASSERT_TRUE(recovery->db()->Execute(final_schema.c_str()));
  480. size_t rows = 0;
  481. EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
  482. EXPECT_EQ(4u, rows);
  483. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  484. }
  485. // Since the database was not corrupt, the entire schema and all
  486. // data should be recovered.
  487. ASSERT_TRUE(Reopen());
  488. ASSERT_EQ(final_schema, GetSchema(&db_));
  489. ASSERT_EQ(final_data, ExecuteWithResults(&db_, kXSql, "|", "\n"));
  490. }
  491. // Test that rows with NULL in a NOT NULL column are filtered
  492. // correctly. In the wild, this would probably happen due to
  493. // corruption, but here it is simulated by recovering a table which
  494. // allowed nulls into a table which does not.
  495. TEST_F(SQLRecoveryTest, AutoRecoverTableNullFilter) {
  496. static const char kOrigSchema[] = "CREATE TABLE x (id INTEGER, t TEXT)";
  497. static const char kFinalSchema[] =
  498. "CREATE TABLE x (id INTEGER, t TEXT NOT NULL)";
  499. ASSERT_TRUE(db_.Execute(kOrigSchema));
  500. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (5, NULL)"));
  501. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (15, 'this is a test')"));
  502. // Create a lame-duck table which will not be propagated by recovery to
  503. // detect that the recovery code actually ran.
  504. ASSERT_EQ(kOrigSchema, GetSchema(&db_));
  505. ASSERT_TRUE(db_.Execute("CREATE TABLE y (c TEXT)"));
  506. ASSERT_NE(kOrigSchema, GetSchema(&db_));
  507. {
  508. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  509. ASSERT_TRUE(recovery->db()->Execute(kFinalSchema));
  510. size_t rows = 0;
  511. EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
  512. EXPECT_EQ(1u, rows);
  513. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  514. }
  515. // The schema should be the same, but only one row of data should
  516. // have been recovered.
  517. ASSERT_TRUE(Reopen());
  518. ASSERT_EQ(kFinalSchema, GetSchema(&db_));
  519. static const char kXSql[] = "SELECT * FROM x ORDER BY 1";
  520. ASSERT_EQ("15|this is a test", ExecuteWithResults(&db_, kXSql, "|", "\n"));
  521. }
  522. // Test AutoRecoverTable with a ROWID alias.
  523. TEST_F(SQLRecoveryTest, AutoRecoverTableWithRowid) {
  524. // The rowid alias is almost always the first column, intentionally
  525. // put it later.
  526. static const char kCreateSql[] =
  527. "CREATE TABLE x (t TEXT, id INTEGER PRIMARY KEY NOT NULL)";
  528. ASSERT_TRUE(db_.Execute(kCreateSql));
  529. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('This is a test', NULL)"));
  530. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('That was a test', NULL)"));
  531. // Save aside a copy of the original schema and data.
  532. const std::string orig_schema(GetSchema(&db_));
  533. static const char kXSql[] = "SELECT * FROM x ORDER BY 1";
  534. const std::string orig_data(ExecuteWithResults(&db_, kXSql, "|", "\n"));
  535. // Create a lame-duck table which will not be propagated by recovery to
  536. // detect that the recovery code actually ran.
  537. ASSERT_TRUE(db_.Execute("CREATE TABLE y (c TEXT)"));
  538. ASSERT_NE(orig_schema, GetSchema(&db_));
  539. {
  540. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  541. ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
  542. size_t rows = 0;
  543. EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
  544. EXPECT_EQ(2u, rows);
  545. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  546. }
  547. // Since the database was not corrupt, the entire schema and all
  548. // data should be recovered.
  549. ASSERT_TRUE(Reopen());
  550. ASSERT_EQ(orig_schema, GetSchema(&db_));
  551. ASSERT_EQ(orig_data, ExecuteWithResults(&db_, kXSql, "|", "\n"));
  552. }
  553. // Test that a compound primary key doesn't fire the ROWID code.
  554. TEST_F(SQLRecoveryTest, AutoRecoverTableWithCompoundKey) {
  555. static const char kCreateSql[] =
  556. "CREATE TABLE x ("
  557. "id INTEGER NOT NULL,"
  558. "id2 TEXT NOT NULL,"
  559. "t TEXT,"
  560. "PRIMARY KEY (id, id2)"
  561. ")";
  562. ASSERT_TRUE(db_.Execute(kCreateSql));
  563. // NOTE(shess): Do not accidentally use [id] 1, 2, 3, as those will
  564. // be the ROWID values.
  565. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (1, 'a', 'This is a test')"));
  566. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (1, 'b', 'That was a test')"));
  567. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (2, 'a', 'Another test')"));
  568. // Save aside a copy of the original schema and data.
  569. const std::string orig_schema(GetSchema(&db_));
  570. static const char kXSql[] = "SELECT * FROM x ORDER BY 1";
  571. const std::string orig_data(ExecuteWithResults(&db_, kXSql, "|", "\n"));
  572. // Create a lame-duck table which will not be propagated by recovery to
  573. // detect that the recovery code actually ran.
  574. ASSERT_TRUE(db_.Execute("CREATE TABLE y (c TEXT)"));
  575. ASSERT_NE(orig_schema, GetSchema(&db_));
  576. {
  577. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  578. ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
  579. size_t rows = 0;
  580. EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
  581. EXPECT_EQ(3u, rows);
  582. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  583. }
  584. // Since the database was not corrupt, the entire schema and all
  585. // data should be recovered.
  586. ASSERT_TRUE(Reopen());
  587. ASSERT_EQ(orig_schema, GetSchema(&db_));
  588. ASSERT_EQ(orig_data, ExecuteWithResults(&db_, kXSql, "|", "\n"));
  589. }
  590. // Test recovering from a table with fewer columns than the target.
  591. TEST_F(SQLRecoveryTest, AutoRecoverTableMissingColumns) {
  592. static const char kCreateSql[] =
  593. "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)";
  594. static const char kAlterSql[] =
  595. "ALTER TABLE x ADD COLUMN t1 TEXT DEFAULT 't'";
  596. ASSERT_TRUE(db_.Execute(kCreateSql));
  597. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (1, 'This is')"));
  598. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES (2, 'That was')"));
  599. // Generate the expected info by faking a table to match what recovery will
  600. // create.
  601. const std::string orig_schema(GetSchema(&db_));
  602. static const char kXSql[] = "SELECT * FROM x ORDER BY 1";
  603. std::string expected_schema;
  604. std::string expected_data;
  605. {
  606. ASSERT_TRUE(db_.BeginTransaction());
  607. ASSERT_TRUE(db_.Execute(kAlterSql));
  608. expected_schema = GetSchema(&db_);
  609. expected_data = ExecuteWithResults(&db_, kXSql, "|", "\n");
  610. db_.RollbackTransaction();
  611. }
  612. // Following tests are pointless if the rollback didn't work.
  613. ASSERT_EQ(orig_schema, GetSchema(&db_));
  614. // Recover the previous version of the table into the altered version.
  615. {
  616. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  617. ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
  618. ASSERT_TRUE(recovery->db()->Execute(kAlterSql));
  619. size_t rows = 0;
  620. EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
  621. EXPECT_EQ(2u, rows);
  622. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  623. }
  624. // Since the database was not corrupt, the entire schema and all
  625. // data should be recovered.
  626. ASSERT_TRUE(Reopen());
  627. ASSERT_EQ(expected_schema, GetSchema(&db_));
  628. ASSERT_EQ(expected_data, ExecuteWithResults(&db_, kXSql, "|", "\n"));
  629. }
  630. // Recover a golden file where an interior page has been manually modified so
  631. // that the number of cells is greater than will fit on a single page. This
  632. // case happened in <http://crbug.com/387868>.
  633. TEST_F(SQLRecoveryTest, Bug387868) {
  634. base::FilePath golden_path;
  635. ASSERT_TRUE(base::PathService::Get(sql::test::DIR_TEST_DATA, &golden_path));
  636. golden_path = golden_path.AppendASCII("recovery_387868");
  637. db_.Close();
  638. ASSERT_TRUE(base::CopyFile(golden_path, db_path_));
  639. ASSERT_TRUE(Reopen());
  640. {
  641. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  642. ASSERT_TRUE(recovery.get());
  643. // Create the new version of the table.
  644. static const char kCreateSql[] =
  645. "CREATE TABLE x (id INTEGER PRIMARY KEY, t0 TEXT)";
  646. ASSERT_TRUE(recovery->db()->Execute(kCreateSql));
  647. size_t rows = 0;
  648. EXPECT_TRUE(recovery->AutoRecoverTable("x", &rows));
  649. EXPECT_EQ(43u, rows);
  650. // Successfully recovered.
  651. EXPECT_TRUE(Recovery::Recovered(std::move(recovery)));
  652. }
  653. }
  654. // Memory-mapped I/O interacts poorly with I/O errors. Make sure the recovery
  655. // database doesn't accidentally enable it.
  656. TEST_F(SQLRecoveryTest, NoMmap) {
  657. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  658. ASSERT_TRUE(recovery.get());
  659. // In the current implementation, the PRAGMA successfully runs with no result
  660. // rows. Running with a single result of |0| is also acceptable.
  661. Statement s(recovery->db()->GetUniqueStatement("PRAGMA mmap_size"));
  662. EXPECT_TRUE(!s.Step() || !s.ColumnInt64(0));
  663. }
  664. TEST_F(SQLRecoveryTest, RecoverDatabase) {
  665. // As a side effect, AUTOINCREMENT creates the sqlite_sequence table for
  666. // RecoverDatabase() to handle.
  667. ASSERT_TRUE(db_.Execute(
  668. "CREATE TABLE table1(id INTEGER PRIMARY KEY AUTOINCREMENT, value TEXT)"));
  669. EXPECT_TRUE(db_.Execute("INSERT INTO table1(value) VALUES('turtle')"));
  670. EXPECT_TRUE(db_.Execute("INSERT INTO table1(value) VALUES('truck')"));
  671. EXPECT_TRUE(db_.Execute("INSERT INTO table1(value) VALUES('trailer')"));
  672. // This table needs index and a unique index to work.
  673. ASSERT_TRUE(db_.Execute("CREATE TABLE table2(name TEXT, value TEXT)"));
  674. ASSERT_TRUE(db_.Execute("CREATE UNIQUE INDEX table2_name ON table2(name)"));
  675. ASSERT_TRUE(db_.Execute("CREATE INDEX table2_value ON table2(value)"));
  676. EXPECT_TRUE(db_.Execute(
  677. "INSERT INTO table2(name, value) VALUES('jim', 'telephone')"));
  678. EXPECT_TRUE(
  679. db_.Execute("INSERT INTO table2(name, value) VALUES('bob', 'truck')"));
  680. EXPECT_TRUE(
  681. db_.Execute("INSERT INTO table2(name, value) VALUES('dean', 'trailer')"));
  682. // Save aside a copy of the original schema, verifying that it has the created
  683. // items plus the sqlite_sequence table.
  684. const std::string original_schema = GetSchema(&db_);
  685. ASSERT_EQ(4, std::count(original_schema.begin(), original_schema.end(), '\n'))
  686. << original_schema;
  687. static constexpr char kTable1Sql[] = "SELECT * FROM table1 ORDER BY 1";
  688. static constexpr char kTable2Sql[] = "SELECT * FROM table2 ORDER BY 1";
  689. EXPECT_EQ("1|turtle\n2|truck\n3|trailer",
  690. ExecuteWithResults(&db_, kTable1Sql, "|", "\n"));
  691. EXPECT_EQ("bob|truck\ndean|trailer\njim|telephone",
  692. ExecuteWithResults(&db_, kTable2Sql, "|", "\n"));
  693. // Database handle is valid before recovery, poisoned after.
  694. static constexpr char kTrivialSql[] = "SELECT COUNT(*) FROM sqlite_schema";
  695. EXPECT_TRUE(db_.IsSQLValid(kTrivialSql));
  696. Recovery::RecoverDatabase(&db_, db_path_);
  697. EXPECT_FALSE(db_.IsSQLValid(kTrivialSql));
  698. // Since the database was not corrupt, the entire schema and all data should
  699. // be recovered.
  700. ASSERT_TRUE(Reopen());
  701. ASSERT_EQ(original_schema, GetSchema(&db_));
  702. EXPECT_EQ("1|turtle\n2|truck\n3|trailer",
  703. ExecuteWithResults(&db_, kTable1Sql, "|", "\n"));
  704. EXPECT_EQ("bob|truck\ndean|trailer\njim|telephone",
  705. ExecuteWithResults(&db_, kTable2Sql, "|", "\n"));
  706. }
  707. TEST_F(SQLRecoveryTest, RecoverDatabaseWithView) {
  708. db_.Close();
  709. sql::Database db({.enable_views_discouraged = true});
  710. ASSERT_TRUE(db.Open(db_path_));
  711. ASSERT_TRUE(db.Execute(
  712. "CREATE TABLE table1(id INTEGER PRIMARY KEY AUTOINCREMENT, value TEXT)"));
  713. EXPECT_TRUE(db.Execute("INSERT INTO table1(value) VALUES('turtle')"));
  714. EXPECT_TRUE(db.Execute("INSERT INTO table1(value) VALUES('truck')"));
  715. EXPECT_TRUE(db.Execute("INSERT INTO table1(value) VALUES('trailer')"));
  716. ASSERT_TRUE(db.Execute("CREATE TABLE table2(name TEXT, value TEXT)"));
  717. ASSERT_TRUE(db.Execute("CREATE UNIQUE INDEX table2_name ON table2(name)"));
  718. EXPECT_TRUE(
  719. db.Execute("INSERT INTO table2(name, value) VALUES('jim', 'telephone')"));
  720. EXPECT_TRUE(
  721. db.Execute("INSERT INTO table2(name, value) VALUES('bob', 'truck')"));
  722. EXPECT_TRUE(
  723. db.Execute("INSERT INTO table2(name, value) VALUES('dean', 'trailer')"));
  724. // View which is the intersection of [table1.value] and [table2.value].
  725. ASSERT_TRUE(db.Execute(
  726. "CREATE VIEW view_table12 AS SELECT table1.value FROM table1, table2 "
  727. "WHERE table1.value = table2.value"));
  728. static constexpr char kViewSql[] = "SELECT * FROM view_table12 ORDER BY 1";
  729. EXPECT_EQ("trailer\ntruck", ExecuteWithResults(&db, kViewSql, "|", "\n"));
  730. // Save aside a copy of the original schema, verifying that it has the created
  731. // items plus the sqlite_sequence table.
  732. const std::string original_schema = GetSchema(&db);
  733. ASSERT_EQ(4, std::count(original_schema.begin(), original_schema.end(), '\n'))
  734. << original_schema;
  735. // Database handle is valid before recovery, poisoned after.
  736. static constexpr char kTrivialSql[] = "SELECT COUNT(*) FROM sqlite_schema";
  737. EXPECT_TRUE(db.IsSQLValid(kTrivialSql));
  738. Recovery::RecoverDatabase(&db, db_path_);
  739. EXPECT_FALSE(db.IsSQLValid(kTrivialSql));
  740. // Since the database was not corrupt, the entire schema and all data should
  741. // be recovered.
  742. db.Close();
  743. ASSERT_TRUE(db.Open(db_path_));
  744. EXPECT_EQ("trailer\ntruck", ExecuteWithResults(&db, kViewSql, "|", "\n"));
  745. }
  746. // When RecoverDatabase() encounters SQLITE_NOTADB, the database is deleted.
  747. TEST_F(SQLRecoveryTest, RecoverDatabaseDelete) {
  748. // Create a valid database, then write junk over the header. This should lead
  749. // to SQLITE_NOTADB, which will cause ATTACH to fail.
  750. ASSERT_TRUE(db_.Execute("CREATE TABLE x (t TEXT)"));
  751. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('This is a test')"));
  752. db_.Close();
  753. ASSERT_TRUE(OverwriteDatabaseHeader());
  754. {
  755. sql::test::ScopedErrorExpecter expecter;
  756. expecter.ExpectError(SQLITE_NOTADB);
  757. // Reopen() here because it will see SQLITE_NOTADB.
  758. ASSERT_TRUE(Reopen());
  759. // This should "recover" the database by making it valid, but empty.
  760. Recovery::RecoverDatabase(&db_, db_path_);
  761. ASSERT_TRUE(expecter.SawExpectedErrors());
  762. }
  763. // Recovery poisoned the handle, must re-open.
  764. db_.Close();
  765. ASSERT_TRUE(Reopen());
  766. EXPECT_EQ("", GetSchema(&db_));
  767. }
  768. // Allow callers to validate the database between recovery and commit.
  769. TEST_F(SQLRecoveryTest, BeginRecoverDatabase) {
  770. static const char kCreateTable[] =
  771. "CREATE TABLE rows(indexed INTEGER NOT NULL, unindexed INTEGER NOT NULL)";
  772. ASSERT_TRUE(db_.Execute(kCreateTable));
  773. ASSERT_TRUE(db_.Execute("CREATE UNIQUE INDEX rows_index ON rows(indexed)"));
  774. // Populate the table with powers of two. These numbers make it easy to see if
  775. // SUM() missed a row.
  776. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(1, 1)"));
  777. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(2, 2)"));
  778. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(4, 4)"));
  779. ASSERT_TRUE(db_.Execute("INSERT INTO rows(indexed, unindexed) VALUES(8, 8)"));
  780. db_.Close();
  781. ASSERT_TRUE(sql::test::CorruptIndexRootPage(db_path_, "rows_index"));
  782. ASSERT_TRUE(Reopen());
  783. // Run recovery code, then rollback. Database remains the same.
  784. {
  785. std::unique_ptr<Recovery> recovery =
  786. Recovery::BeginRecoverDatabase(&db_, db_path_);
  787. ASSERT_TRUE(recovery);
  788. Recovery::Rollback(std::move(recovery));
  789. }
  790. db_.Close();
  791. ASSERT_TRUE(Reopen());
  792. static const char kIndexedCountSql[] =
  793. "SELECT SUM(indexed) FROM rows INDEXED BY rows_index";
  794. {
  795. sql::test::ScopedErrorExpecter expecter;
  796. expecter.ExpectError(SQLITE_CORRUPT);
  797. EXPECT_EQ("", ExecuteWithResult(&db_, kIndexedCountSql))
  798. << "Index should still be corrupted after recovery rollback";
  799. EXPECT_TRUE(expecter.SawExpectedErrors())
  800. << "Index should still be corrupted after recovery rollback";
  801. }
  802. // Run recovery code, then commit. The index is recovered.
  803. {
  804. std::unique_ptr<Recovery> recovery =
  805. Recovery::BeginRecoverDatabase(&db_, db_path_);
  806. ASSERT_TRUE(recovery);
  807. ASSERT_TRUE(Recovery::Recovered(std::move(recovery)));
  808. }
  809. db_.Close();
  810. ASSERT_TRUE(Reopen());
  811. EXPECT_EQ("15", ExecuteWithResult(&db_, kIndexedCountSql))
  812. << "Index should be reconstructed after database recovery";
  813. }
  814. TEST_F(SQLRecoveryTest, AttachFailure) {
  815. // Create a valid database, then write junk over the header. This should lead
  816. // to SQLITE_NOTADB, which will cause ATTACH to fail.
  817. ASSERT_TRUE(db_.Execute("CREATE TABLE x (t TEXT)"));
  818. ASSERT_TRUE(db_.Execute("INSERT INTO x VALUES ('This is a test')"));
  819. db_.Close();
  820. ASSERT_TRUE(OverwriteDatabaseHeader());
  821. {
  822. sql::test::ScopedErrorExpecter expecter;
  823. expecter.ExpectError(SQLITE_NOTADB);
  824. // Reopen() here because it will see SQLITE_NOTADB.
  825. ASSERT_TRUE(Reopen());
  826. // Begin() should fail.
  827. std::unique_ptr<Recovery> recovery = Recovery::Begin(&db_, db_path_);
  828. EXPECT_FALSE(recovery.get());
  829. ASSERT_TRUE(expecter.SawExpectedErrors());
  830. }
  831. }
  832. // Helper for SQLRecoveryTest.PageSize. Creates a fresh db based on db_prefix,
  833. // with the given initial page size, and verifies it against the expected size.
  834. // Then changes to the final page size and recovers, verifying that the
  835. // recovered database ends up with the expected final page size.
  836. void TestPageSize(const base::FilePath& db_prefix,
  837. int initial_page_size,
  838. const std::string& expected_initial_page_size,
  839. int final_page_size,
  840. const std::string& expected_final_page_size) {
  841. static const char kCreateSql[] = "CREATE TABLE x (t TEXT)";
  842. static const char kInsertSql1[] = "INSERT INTO x VALUES ('This is a test')";
  843. static const char kInsertSql2[] = "INSERT INTO x VALUES ('That was a test')";
  844. static const char kSelectSql[] = "SELECT * FROM x ORDER BY t";
  845. const base::FilePath db_path = db_prefix.InsertBeforeExtensionASCII(
  846. base::NumberToString(initial_page_size));
  847. Database::Delete(db_path);
  848. Database db({.page_size = initial_page_size});
  849. ASSERT_TRUE(db.Open(db_path));
  850. ASSERT_TRUE(db.Execute(kCreateSql));
  851. ASSERT_TRUE(db.Execute(kInsertSql1));
  852. ASSERT_TRUE(db.Execute(kInsertSql2));
  853. ASSERT_EQ(expected_initial_page_size,
  854. ExecuteWithResult(&db, "PRAGMA page_size"));
  855. db.Close();
  856. // Re-open the database while setting a new |options.page_size| in the object.
  857. Database recover_db({.page_size = final_page_size});
  858. ASSERT_TRUE(recover_db.Open(db_path));
  859. // Recovery will use the page size set in the database object, which may not
  860. // match the file's page size.
  861. Recovery::RecoverDatabase(&recover_db, db_path);
  862. // Recovery poisoned the handle, must re-open.
  863. recover_db.Close();
  864. // Make sure the page size is read from the file.
  865. Database recovered_db({.page_size = DatabaseOptions::kDefaultPageSize});
  866. ASSERT_TRUE(recovered_db.Open(db_path));
  867. ASSERT_EQ(expected_final_page_size,
  868. ExecuteWithResult(&recovered_db, "PRAGMA page_size"));
  869. EXPECT_EQ("That was a test\nThis is a test",
  870. ExecuteWithResults(&recovered_db, kSelectSql, "|", "\n"));
  871. }
  872. // Verify that Recovery maintains the page size, and the virtual table
  873. // works with page sizes other than SQLite's default. Also verify the case
  874. // where the default page size has changed.
  875. TEST_F(SQLRecoveryTest, PageSize) {
  876. const std::string default_page_size =
  877. ExecuteWithResult(&db_, "PRAGMA page_size");
  878. // Check the default page size first.
  879. EXPECT_NO_FATAL_FAILURE(TestPageSize(
  880. db_path_, DatabaseOptions::kDefaultPageSize, default_page_size,
  881. DatabaseOptions::kDefaultPageSize, default_page_size));
  882. // Sync uses 32k pages.
  883. EXPECT_NO_FATAL_FAILURE(
  884. TestPageSize(db_path_, 32768, "32768", 32768, "32768"));
  885. // Many clients use 4k pages. This is the SQLite default after 3.12.0.
  886. EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 4096, "4096", 4096, "4096"));
  887. // 1k is the default page size before 3.12.0.
  888. EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 1024, "1024", 1024, "1024"));
  889. // Databases with no page size specified should recover with the new default
  890. // page size. 2k has never been the default page size.
  891. ASSERT_NE("2048", default_page_size);
  892. EXPECT_NO_FATAL_FAILURE(TestPageSize(db_path_, 2048, "2048",
  893. DatabaseOptions::kDefaultPageSize,
  894. default_page_size));
  895. }
  896. } // namespace
  897. } // namespace sql