module_unittest.cc 41 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126
  1. // Copyright 2019 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 <random>
  5. #include <string>
  6. #include <tuple>
  7. #include <vector>
  8. #include "base/files/scoped_temp_dir.h"
  9. #include "base/strings/stringprintf.h"
  10. #include "sql/database.h"
  11. #include "sql/statement.h"
  12. #include "sql/test/database_test_peer.h"
  13. #include "sql/test/scoped_error_expecter.h"
  14. #include "sql/test/test_helpers.h"
  15. #include "sql/transaction.h"
  16. #include "testing/gtest/include/gtest/gtest.h"
  17. #include "third_party/sqlite/sqlite3.h"
  18. namespace sql {
  19. namespace recover {
  20. class RecoverModuleTest : public testing::Test {
  21. public:
  22. ~RecoverModuleTest() override = default;
  23. void SetUp() override {
  24. ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  25. ASSERT_TRUE(
  26. db_.Open(temp_dir_.GetPath().AppendASCII("recovery_test.sqlite")));
  27. ASSERT_TRUE(DatabaseTestPeer::EnableRecoveryExtension(&db_));
  28. }
  29. protected:
  30. base::ScopedTempDir temp_dir_;
  31. sql::Database db_{sql::DatabaseOptions{
  32. .enable_virtual_tables_discouraged = true,
  33. }};
  34. };
  35. TEST_F(RecoverModuleTest, CreateVtable) {
  36. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  37. EXPECT_TRUE(
  38. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  39. "USING recover(backing, t TEXT)"));
  40. }
  41. TEST_F(RecoverModuleTest, CreateVtableWithDatabaseSpecifier) {
  42. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  43. EXPECT_TRUE(
  44. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  45. "USING recover(main.backing, t TEXT)"));
  46. }
  47. TEST_F(RecoverModuleTest, CreateVtableOnSqliteSchema) {
  48. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  49. EXPECT_TRUE(
  50. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing USING recover("
  51. "sqlite_schema, type TEXT, name TEXT, tbl_name TEXT, "
  52. "rootpage INTEGER, sql TEXT)"));
  53. }
  54. TEST_F(RecoverModuleTest, CreateVtableFailsOnNonTempTable) {
  55. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  56. {
  57. sql::test::ScopedErrorExpecter error_expecter;
  58. error_expecter.ExpectError(SQLITE_ERROR);
  59. EXPECT_FALSE(db_.Execute(
  60. "CREATE VIRTUAL TABLE recover_backing USING recover(backing, t TEXT)"));
  61. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  62. }
  63. }
  64. TEST_F(RecoverModuleTest, CreateVtableFailsOnMissingTable) {
  65. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  66. {
  67. sql::test::ScopedErrorExpecter error_expecter;
  68. error_expecter.ExpectError(SQLITE_CORRUPT);
  69. EXPECT_FALSE(
  70. db_.Execute("CREATE VIRTUAL TABLE temp.recover_missing "
  71. "USING recover(missing, t TEXT)"));
  72. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  73. }
  74. }
  75. TEST_F(RecoverModuleTest, CreateVtableFailsOnMissingDatabase) {
  76. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  77. {
  78. sql::test::ScopedErrorExpecter error_expecter;
  79. error_expecter.ExpectError(SQLITE_CORRUPT);
  80. EXPECT_FALSE(
  81. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  82. "USING recover(db.backing, t TEXT)"));
  83. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  84. }
  85. }
  86. TEST_F(RecoverModuleTest, CreateVtableFailsOnTableWithInvalidQualifier) {
  87. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  88. {
  89. sql::test::ScopedErrorExpecter error_expecter;
  90. error_expecter.ExpectError(SQLITE_CORRUPT);
  91. EXPECT_FALSE(
  92. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  93. "USING recover(backing invalid, t TEXT)"));
  94. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  95. }
  96. }
  97. TEST_F(RecoverModuleTest, CreateVtableFailsOnMissingTableName) {
  98. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  99. {
  100. sql::test::ScopedErrorExpecter error_expecter;
  101. error_expecter.ExpectError(SQLITE_ERROR);
  102. EXPECT_FALSE(
  103. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  104. "USING recover(main., t TEXT)"));
  105. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  106. }
  107. }
  108. TEST_F(RecoverModuleTest, CreateVtableFailsOnMissingSchemaSpec) {
  109. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  110. {
  111. sql::test::ScopedErrorExpecter error_expecter;
  112. error_expecter.ExpectError(SQLITE_ERROR);
  113. EXPECT_FALSE(
  114. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  115. "USING recover(backing)"));
  116. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  117. }
  118. }
  119. TEST_F(RecoverModuleTest, CreateVtableFailsOnMissingDbName) {
  120. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  121. {
  122. sql::test::ScopedErrorExpecter error_expecter;
  123. error_expecter.ExpectError(SQLITE_ERROR);
  124. EXPECT_FALSE(
  125. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  126. "USING recover(.backing)"));
  127. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  128. }
  129. }
  130. TEST_F(RecoverModuleTest, ColumnTypeMappingAny) {
  131. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  132. EXPECT_TRUE(
  133. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  134. "USING recover(backing, t ANY)"));
  135. sql::test::ColumnInfo column_info =
  136. sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "t");
  137. EXPECT_EQ("(nullptr)", column_info.data_type);
  138. EXPECT_EQ("BINARY", column_info.collation_sequence);
  139. EXPECT_FALSE(column_info.has_non_null_constraint);
  140. EXPECT_FALSE(column_info.is_in_primary_key);
  141. EXPECT_FALSE(column_info.is_auto_incremented);
  142. }
  143. TEST_F(RecoverModuleTest, ColumnTypeMappingAnyNotNull) {
  144. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  145. EXPECT_TRUE(
  146. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  147. "USING recover(backing, t ANY NOT NULL)"));
  148. sql::test::ColumnInfo column_info =
  149. sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "t");
  150. EXPECT_EQ("(nullptr)", column_info.data_type);
  151. EXPECT_EQ("BINARY", column_info.collation_sequence);
  152. EXPECT_TRUE(column_info.has_non_null_constraint);
  153. EXPECT_FALSE(column_info.is_in_primary_key);
  154. EXPECT_FALSE(column_info.is_auto_incremented);
  155. }
  156. TEST_F(RecoverModuleTest, ColumnTypeMappingAnyStrict) {
  157. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  158. {
  159. sql::test::ScopedErrorExpecter error_expecter;
  160. error_expecter.ExpectError(SQLITE_ERROR);
  161. EXPECT_FALSE(
  162. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  163. "USING recover(backing, t ANY STRICT)"));
  164. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  165. }
  166. }
  167. TEST_F(RecoverModuleTest, ColumnTypeExtraKeyword) {
  168. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  169. {
  170. sql::test::ScopedErrorExpecter error_expecter;
  171. error_expecter.ExpectError(SQLITE_ERROR);
  172. EXPECT_FALSE(
  173. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  174. "USING recover(backing, t INTEGER SOMETHING)"));
  175. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  176. }
  177. }
  178. TEST_F(RecoverModuleTest, ColumnTypeNotNullExtraKeyword) {
  179. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  180. {
  181. sql::test::ScopedErrorExpecter error_expecter;
  182. error_expecter.ExpectError(SQLITE_ERROR);
  183. EXPECT_FALSE(
  184. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  185. "USING recover(backing, t INTEGER NOT NULL SOMETHING)"));
  186. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  187. }
  188. }
  189. TEST_F(RecoverModuleTest, ColumnTypeDoubleTypes) {
  190. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  191. {
  192. sql::test::ScopedErrorExpecter error_expecter;
  193. error_expecter.ExpectError(SQLITE_ERROR);
  194. EXPECT_FALSE(
  195. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing "
  196. "USING recover(backing, t INTEGER FLOAT)"));
  197. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  198. }
  199. }
  200. TEST_F(RecoverModuleTest, ColumnTypeNotNullDoubleTypes) {
  201. ASSERT_TRUE(db_.Execute("CREATE TABLE backing(t TEXT)"));
  202. {
  203. sql::test::ScopedErrorExpecter error_expecter;
  204. error_expecter.ExpectError(SQLITE_ERROR);
  205. EXPECT_FALSE(
  206. db_.Execute("CREATE VIRTUAL TABLE temp.recover_backing USING recover("
  207. "backing, t INTEGER NOT NULL TEXT)"));
  208. EXPECT_TRUE(error_expecter.SawExpectedErrors());
  209. }
  210. }
  211. class RecoverModuleColumnTypeMappingTest
  212. : public RecoverModuleTest,
  213. public ::testing::WithParamInterface<
  214. std::tuple<const char*, const char*, bool>> {
  215. public:
  216. ~RecoverModuleColumnTypeMappingTest() override = default;
  217. void SetUp() override {
  218. ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
  219. ASSERT_TRUE(
  220. db_.Open(temp_dir_.GetPath().AppendASCII("recovery_test.sqlite")));
  221. ASSERT_TRUE(DatabaseTestPeer::EnableRecoveryExtension(&db_));
  222. std::string sql =
  223. base::StringPrintf("CREATE TABLE backing(data %s)", SchemaType());
  224. ASSERT_TRUE(db_.Execute(sql.c_str()));
  225. }
  226. void CreateRecoveryTable(const char* suffix) {
  227. std::string sql = base::StringPrintf(
  228. "CREATE VIRTUAL TABLE temp.recover_backing "
  229. "USING recover(backing, data %s%s)",
  230. SchemaType(), suffix);
  231. ASSERT_TRUE(db_.Execute(sql.c_str()));
  232. }
  233. const char* SchemaType() const { return std::get<0>(GetParam()); }
  234. const char* ExpectedType() const { return std::get<1>(GetParam()); }
  235. bool IsAlwaysNonNull() const { return std::get<2>(GetParam()); }
  236. protected:
  237. base::ScopedTempDir temp_dir_;
  238. sql::Database db_;
  239. };
  240. TEST_P(RecoverModuleColumnTypeMappingTest, Unqualified) {
  241. CreateRecoveryTable("");
  242. sql::test::ColumnInfo column_info =
  243. sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "data");
  244. EXPECT_EQ(ExpectedType(), column_info.data_type);
  245. EXPECT_EQ("BINARY", column_info.collation_sequence);
  246. EXPECT_EQ(IsAlwaysNonNull(), column_info.has_non_null_constraint);
  247. EXPECT_FALSE(column_info.is_in_primary_key);
  248. EXPECT_FALSE(column_info.is_auto_incremented);
  249. }
  250. TEST_P(RecoverModuleColumnTypeMappingTest, NotNull) {
  251. CreateRecoveryTable(" NOT NULL");
  252. sql::test::ColumnInfo column_info =
  253. sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "data");
  254. EXPECT_EQ(ExpectedType(), column_info.data_type);
  255. EXPECT_EQ("BINARY", column_info.collation_sequence);
  256. EXPECT_TRUE(column_info.has_non_null_constraint);
  257. EXPECT_FALSE(column_info.is_in_primary_key);
  258. EXPECT_FALSE(column_info.is_auto_incremented);
  259. }
  260. TEST_P(RecoverModuleColumnTypeMappingTest, Strict) {
  261. CreateRecoveryTable(" STRICT");
  262. sql::test::ColumnInfo column_info =
  263. sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "data");
  264. EXPECT_EQ(ExpectedType(), column_info.data_type);
  265. EXPECT_EQ("BINARY", column_info.collation_sequence);
  266. EXPECT_EQ(IsAlwaysNonNull(), column_info.has_non_null_constraint);
  267. EXPECT_FALSE(column_info.is_in_primary_key);
  268. EXPECT_FALSE(column_info.is_auto_incremented);
  269. }
  270. TEST_P(RecoverModuleColumnTypeMappingTest, StrictNotNull) {
  271. CreateRecoveryTable(" STRICT NOT NULL");
  272. sql::test::ColumnInfo column_info =
  273. sql::test::ColumnInfo::Create(&db_, "temp", "recover_backing", "data");
  274. EXPECT_EQ(ExpectedType(), column_info.data_type);
  275. EXPECT_EQ("BINARY", column_info.collation_sequence);
  276. EXPECT_TRUE(column_info.has_non_null_constraint);
  277. EXPECT_FALSE(column_info.is_in_primary_key);
  278. EXPECT_FALSE(column_info.is_auto_incremented);
  279. }
  280. INSTANTIATE_TEST_SUITE_P(
  281. All,
  282. RecoverModuleColumnTypeMappingTest,
  283. ::testing::Values(std::make_tuple("TEXT", "TEXT", false),
  284. std::make_tuple("INTEGER", "INTEGER", false),
  285. std::make_tuple("FLOAT", "FLOAT", false),
  286. std::make_tuple("BLOB", "BLOB", false),
  287. std::make_tuple("NUMERIC", "NUMERIC", false),
  288. std::make_tuple("ROWID", "INTEGER", true)));
  289. namespace {
  290. void GenerateAlteredTable(sql::Database* db) {
  291. ASSERT_TRUE(db->Execute("CREATE TABLE altered(t TEXT)"));
  292. ASSERT_TRUE(db->Execute("INSERT INTO altered VALUES('a')"));
  293. ASSERT_TRUE(db->Execute("INSERT INTO altered VALUES('b')"));
  294. ASSERT_TRUE(db->Execute("INSERT INTO altered VALUES('c')"));
  295. ASSERT_TRUE(db->Execute(
  296. "ALTER TABLE altered ADD COLUMN i INTEGER NOT NULL DEFAULT 10"));
  297. ASSERT_TRUE(db->Execute("INSERT INTO altered VALUES('d', 5)"));
  298. }
  299. } // namespace
  300. TEST_F(RecoverModuleTest, ReadFromAlteredTableNullDefaults) {
  301. GenerateAlteredTable(&db_);
  302. ASSERT_TRUE(
  303. db_.Execute("CREATE VIRTUAL TABLE temp.recover_altered "
  304. "USING recover(altered, t TEXT, i INTEGER)"));
  305. sql::Statement statement(db_.GetUniqueStatement(
  306. "SELECT t, i FROM recover_altered ORDER BY rowid"));
  307. ASSERT_TRUE(statement.Step());
  308. EXPECT_EQ("a", statement.ColumnString(0));
  309. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(1));
  310. ASSERT_TRUE(statement.Step());
  311. EXPECT_EQ("b", statement.ColumnString(0));
  312. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(1));
  313. ASSERT_TRUE(statement.Step());
  314. EXPECT_EQ("c", statement.ColumnString(0));
  315. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(1));
  316. ASSERT_TRUE(statement.Step());
  317. EXPECT_EQ("d", statement.ColumnString(0));
  318. EXPECT_EQ(5, statement.ColumnInt(1));
  319. EXPECT_FALSE(statement.Step());
  320. }
  321. TEST_F(RecoverModuleTest, ReadFromAlteredTableSkipsNulls) {
  322. GenerateAlteredTable(&db_);
  323. ASSERT_TRUE(
  324. db_.Execute("CREATE VIRTUAL TABLE temp.recover_altered "
  325. "USING recover(altered, t TEXT, i INTEGER NOT NULL)"));
  326. sql::Statement statement(db_.GetUniqueStatement(
  327. "SELECT t, i FROM recover_altered ORDER BY rowid"));
  328. ASSERT_TRUE(statement.Step());
  329. EXPECT_EQ("d", statement.ColumnString(0));
  330. EXPECT_EQ(5, statement.ColumnInt(1));
  331. EXPECT_FALSE(statement.Step());
  332. }
  333. namespace {
  334. void GenerateSizedTable(sql::Database* db,
  335. int row_count,
  336. const std::string& prefix) {
  337. ASSERT_TRUE(db->Execute("CREATE TABLE sized(t TEXT, i INTEGER)"));
  338. sql::Transaction transaction(db);
  339. ASSERT_TRUE(transaction.Begin());
  340. sql::Statement statement(
  341. db->GetUniqueStatement("INSERT INTO sized VALUES(?, ?)"));
  342. for (int i = 0; i < row_count; ++i) {
  343. statement.BindString(0, base::StringPrintf("%s%d", prefix.c_str(), i));
  344. statement.BindInt(1, i);
  345. ASSERT_TRUE(statement.Run());
  346. statement.Reset(/* clear_bound_vars= */ true);
  347. }
  348. ASSERT_TRUE(transaction.Commit());
  349. }
  350. } // namespace
  351. TEST_F(RecoverModuleTest, LeafNodes) {
  352. GenerateSizedTable(&db_, 10, "Leaf-node-generating line ");
  353. ASSERT_TRUE(
  354. db_.Execute("CREATE VIRTUAL TABLE temp.recover_sized "
  355. "USING recover(sized, t TEXT, i INTEGER NOT NULL)"));
  356. sql::Statement statement(
  357. db_.GetUniqueStatement("SELECT t, i FROM recover_sized ORDER BY rowid"));
  358. for (int i = 0; i < 10; ++i) {
  359. ASSERT_TRUE(statement.Step());
  360. EXPECT_EQ(base::StringPrintf("Leaf-node-generating line %d", i),
  361. statement.ColumnString(0));
  362. EXPECT_EQ(i, statement.ColumnInt(1));
  363. }
  364. EXPECT_FALSE(statement.Step());
  365. }
  366. TEST_F(RecoverModuleTest, EmptyTable) {
  367. GenerateSizedTable(&db_, 0, "");
  368. ASSERT_TRUE(
  369. db_.Execute("CREATE VIRTUAL TABLE temp.recover_sized "
  370. "USING recover(sized, t TEXT, i INTEGER NOT NULL)"));
  371. sql::Statement statement(db_.GetUniqueStatement(
  372. "SELECT rowid, t, i FROM recover_sized ORDER BY rowid"));
  373. EXPECT_FALSE(statement.Step());
  374. }
  375. TEST_F(RecoverModuleTest, SingleLevelInteriorNodes) {
  376. GenerateSizedTable(&db_, 100, "Interior-node-generating line ");
  377. ASSERT_TRUE(
  378. db_.Execute("CREATE VIRTUAL TABLE temp.recover_sized "
  379. "USING recover(sized, t TEXT, i INTEGER NOT NULL)"));
  380. sql::Statement statement(db_.GetUniqueStatement(
  381. "SELECT rowid, t, i FROM recover_sized ORDER BY rowid"));
  382. for (int i = 0; i < 100; ++i) {
  383. ASSERT_TRUE(statement.Step());
  384. EXPECT_EQ(i + 1, statement.ColumnInt(0));
  385. EXPECT_EQ(base::StringPrintf("Interior-node-generating line %d", i),
  386. statement.ColumnString(1));
  387. EXPECT_EQ(i, statement.ColumnInt(2));
  388. }
  389. EXPECT_FALSE(statement.Step());
  390. }
  391. TEST_F(RecoverModuleTest, MultiLevelInteriorNodes) {
  392. GenerateSizedTable(&db_, 5000, "Interior-node-generating line ");
  393. ASSERT_TRUE(
  394. db_.Execute("CREATE VIRTUAL TABLE temp.recover_sized "
  395. "USING recover(sized, t TEXT, i INTEGER NOT NULL)"));
  396. sql::Statement statement(db_.GetUniqueStatement(
  397. "SELECT rowid, t, i FROM recover_sized ORDER BY rowid"));
  398. for (int i = 0; i < 5000; ++i) {
  399. ASSERT_TRUE(statement.Step());
  400. EXPECT_EQ(i + 1, statement.ColumnInt(0));
  401. EXPECT_EQ(base::StringPrintf("Interior-node-generating line %d", i),
  402. statement.ColumnString(1));
  403. EXPECT_EQ(i, statement.ColumnInt(2));
  404. }
  405. EXPECT_FALSE(statement.Step());
  406. }
  407. namespace {
  408. void GenerateTypesTable(sql::Database* db) {
  409. ASSERT_TRUE(db->Execute("CREATE TABLE types(rowtype TEXT, value)"));
  410. ASSERT_TRUE(db->Execute("INSERT INTO types VALUES('NULL', NULL)"));
  411. ASSERT_TRUE(db->Execute("INSERT INTO types VALUES('INTEGER', 17)"));
  412. ASSERT_TRUE(db->Execute("INSERT INTO types VALUES('FLOAT', 3.1415927)"));
  413. ASSERT_TRUE(db->Execute("INSERT INTO types VALUES('TEXT', 'This is text')"));
  414. ASSERT_TRUE(db->Execute(
  415. "INSERT INTO types VALUES('BLOB', CAST('This is a blob' AS BLOB))"));
  416. }
  417. } // namespace
  418. TEST_F(RecoverModuleTest, Any) {
  419. GenerateTypesTable(&db_);
  420. ASSERT_TRUE(
  421. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  422. "USING recover(types, rowtype TEXT, value ANY)"));
  423. sql::Statement statement(db_.GetUniqueStatement(
  424. "SELECT rowid, rowtype, value FROM recover_types"));
  425. ASSERT_TRUE(statement.Step());
  426. EXPECT_EQ(1, statement.ColumnInt(0));
  427. EXPECT_EQ("NULL", statement.ColumnString(1));
  428. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(2));
  429. ASSERT_TRUE(statement.Step());
  430. EXPECT_EQ(2, statement.ColumnInt(0));
  431. EXPECT_EQ("INTEGER", statement.ColumnString(1));
  432. EXPECT_EQ(sql::ColumnType::kInteger, statement.GetColumnType(2));
  433. EXPECT_EQ(17, statement.ColumnInt(2));
  434. ASSERT_TRUE(statement.Step());
  435. EXPECT_EQ(3, statement.ColumnInt(0));
  436. EXPECT_EQ("FLOAT", statement.ColumnString(1));
  437. EXPECT_EQ(sql::ColumnType::kFloat, statement.GetColumnType(2));
  438. EXPECT_DOUBLE_EQ(3.1415927, statement.ColumnDouble(2));
  439. ASSERT_TRUE(statement.Step());
  440. EXPECT_EQ(4, statement.ColumnInt(0));
  441. EXPECT_EQ("TEXT", statement.ColumnString(1));
  442. EXPECT_EQ(sql::ColumnType::kText, statement.GetColumnType(2));
  443. EXPECT_EQ("This is text", statement.ColumnString(2));
  444. ASSERT_TRUE(statement.Step());
  445. EXPECT_EQ(5, statement.ColumnInt(0));
  446. EXPECT_EQ("BLOB", statement.ColumnString(1));
  447. EXPECT_EQ(sql::ColumnType::kBlob, statement.GetColumnType(2));
  448. std::string blob_text;
  449. ASSERT_TRUE(statement.ColumnBlobAsString(2, &blob_text));
  450. EXPECT_EQ("This is a blob", blob_text);
  451. EXPECT_FALSE(statement.Step());
  452. }
  453. TEST_F(RecoverModuleTest, Integers) {
  454. GenerateTypesTable(&db_);
  455. ASSERT_TRUE(
  456. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  457. "USING recover(types, rowtype TEXT, value INTEGER)"));
  458. sql::Statement statement(db_.GetUniqueStatement(
  459. "SELECT rowid, rowtype, value FROM recover_types"));
  460. ASSERT_TRUE(statement.Step());
  461. EXPECT_EQ(1, statement.ColumnInt(0));
  462. EXPECT_EQ("NULL", statement.ColumnString(1));
  463. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(2));
  464. ASSERT_TRUE(statement.Step());
  465. EXPECT_EQ(2, statement.ColumnInt(0));
  466. EXPECT_EQ("INTEGER", statement.ColumnString(1));
  467. EXPECT_EQ(sql::ColumnType::kInteger, statement.GetColumnType(2));
  468. EXPECT_EQ(17, statement.ColumnInt(2));
  469. EXPECT_FALSE(statement.Step());
  470. }
  471. TEST_F(RecoverModuleTest, NonNullIntegers) {
  472. GenerateTypesTable(&db_);
  473. ASSERT_TRUE(db_.Execute(
  474. "CREATE VIRTUAL TABLE temp.recover_types "
  475. "USING recover(types, rowtype TEXT, value INTEGER NOT NULL)"));
  476. sql::Statement statement(db_.GetUniqueStatement(
  477. "SELECT rowid, rowtype, value FROM recover_types"));
  478. ASSERT_TRUE(statement.Step());
  479. EXPECT_EQ(2, statement.ColumnInt(0));
  480. EXPECT_EQ("INTEGER", statement.ColumnString(1));
  481. EXPECT_EQ(sql::ColumnType::kInteger, statement.GetColumnType(2));
  482. EXPECT_EQ(17, statement.ColumnInt(2));
  483. EXPECT_FALSE(statement.Step());
  484. }
  485. TEST_F(RecoverModuleTest, Floats) {
  486. GenerateTypesTable(&db_);
  487. ASSERT_TRUE(
  488. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  489. "USING recover(types, rowtype TEXT, value FLOAT)"));
  490. sql::Statement statement(db_.GetUniqueStatement(
  491. "SELECT rowid, rowtype, value FROM recover_types"));
  492. ASSERT_TRUE(statement.Step());
  493. EXPECT_EQ(1, statement.ColumnInt(0));
  494. EXPECT_EQ("NULL", statement.ColumnString(1));
  495. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(2));
  496. ASSERT_TRUE(statement.Step());
  497. EXPECT_EQ(2, statement.ColumnInt(0));
  498. EXPECT_EQ("INTEGER", statement.ColumnString(1));
  499. EXPECT_EQ(sql::ColumnType::kInteger, statement.GetColumnType(2));
  500. EXPECT_EQ(17, statement.ColumnInt(2));
  501. ASSERT_TRUE(statement.Step());
  502. EXPECT_EQ(3, statement.ColumnInt(0));
  503. EXPECT_EQ("FLOAT", statement.ColumnString(1));
  504. EXPECT_EQ(sql::ColumnType::kFloat, statement.GetColumnType(2));
  505. EXPECT_DOUBLE_EQ(3.1415927, statement.ColumnDouble(2));
  506. EXPECT_FALSE(statement.Step());
  507. }
  508. TEST_F(RecoverModuleTest, NonNullFloats) {
  509. GenerateTypesTable(&db_);
  510. ASSERT_TRUE(
  511. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  512. "USING recover(types, rowtype TEXT, value FLOAT NOT NULL)"));
  513. sql::Statement statement(db_.GetUniqueStatement(
  514. "SELECT rowid, rowtype, value FROM recover_types"));
  515. ASSERT_TRUE(statement.Step());
  516. EXPECT_EQ(2, statement.ColumnInt(0));
  517. EXPECT_EQ("INTEGER", statement.ColumnString(1));
  518. EXPECT_EQ(sql::ColumnType::kInteger, statement.GetColumnType(2));
  519. EXPECT_EQ(17, statement.ColumnInt(2));
  520. ASSERT_TRUE(statement.Step());
  521. EXPECT_EQ(3, statement.ColumnInt(0));
  522. EXPECT_EQ("FLOAT", statement.ColumnString(1));
  523. EXPECT_EQ(sql::ColumnType::kFloat, statement.GetColumnType(2));
  524. EXPECT_DOUBLE_EQ(3.1415927, statement.ColumnDouble(2));
  525. EXPECT_FALSE(statement.Step());
  526. }
  527. TEST_F(RecoverModuleTest, FloatsStrict) {
  528. GenerateTypesTable(&db_);
  529. ASSERT_TRUE(
  530. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  531. "USING recover(types, rowtype TEXT, value FLOAT STRICT)"));
  532. sql::Statement statement(db_.GetUniqueStatement(
  533. "SELECT rowid, rowtype, value FROM recover_types"));
  534. ASSERT_TRUE(statement.Step());
  535. EXPECT_EQ(1, statement.ColumnInt(0));
  536. EXPECT_EQ("NULL", statement.ColumnString(1));
  537. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(2));
  538. ASSERT_TRUE(statement.Step());
  539. EXPECT_EQ(3, statement.ColumnInt(0));
  540. EXPECT_EQ("FLOAT", statement.ColumnString(1));
  541. EXPECT_EQ(sql::ColumnType::kFloat, statement.GetColumnType(2));
  542. EXPECT_DOUBLE_EQ(3.1415927, statement.ColumnDouble(2));
  543. EXPECT_FALSE(statement.Step());
  544. }
  545. TEST_F(RecoverModuleTest, NonNullFloatsStrict) {
  546. GenerateTypesTable(&db_);
  547. ASSERT_TRUE(db_.Execute(
  548. "CREATE VIRTUAL TABLE temp.recover_types "
  549. "USING recover(types, rowtype TEXT, value FLOAT STRICT NOT NULL)"));
  550. sql::Statement statement(db_.GetUniqueStatement(
  551. "SELECT rowid, rowtype, value FROM recover_types"));
  552. ASSERT_TRUE(statement.Step());
  553. EXPECT_EQ(3, statement.ColumnInt(0));
  554. EXPECT_EQ("FLOAT", statement.ColumnString(1));
  555. EXPECT_EQ(sql::ColumnType::kFloat, statement.GetColumnType(2));
  556. EXPECT_DOUBLE_EQ(3.1415927, statement.ColumnDouble(2));
  557. EXPECT_FALSE(statement.Step());
  558. }
  559. TEST_F(RecoverModuleTest, Texts) {
  560. GenerateTypesTable(&db_);
  561. ASSERT_TRUE(
  562. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  563. "USING recover(types, rowtype TEXT, value TEXT)"));
  564. sql::Statement statement(db_.GetUniqueStatement(
  565. "SELECT rowid, rowtype, value FROM recover_types"));
  566. ASSERT_TRUE(statement.Step());
  567. EXPECT_EQ(1, statement.ColumnInt(0));
  568. EXPECT_EQ("NULL", statement.ColumnString(1));
  569. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(2));
  570. ASSERT_TRUE(statement.Step());
  571. EXPECT_EQ(4, statement.ColumnInt(0));
  572. EXPECT_EQ("TEXT", statement.ColumnString(1));
  573. EXPECT_EQ(sql::ColumnType::kText, statement.GetColumnType(2));
  574. EXPECT_EQ("This is text", statement.ColumnString(2));
  575. ASSERT_TRUE(statement.Step());
  576. EXPECT_EQ(5, statement.ColumnInt(0));
  577. EXPECT_EQ("BLOB", statement.ColumnString(1));
  578. EXPECT_EQ(sql::ColumnType::kBlob, statement.GetColumnType(2));
  579. std::string blob_text;
  580. ASSERT_TRUE(statement.ColumnBlobAsString(2, &blob_text));
  581. EXPECT_EQ("This is a blob", blob_text);
  582. EXPECT_FALSE(statement.Step());
  583. }
  584. TEST_F(RecoverModuleTest, NonNullTexts) {
  585. GenerateTypesTable(&db_);
  586. ASSERT_TRUE(
  587. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  588. "USING recover(types, rowtype TEXT, value TEXT NOT NULL)"));
  589. sql::Statement statement(db_.GetUniqueStatement(
  590. "SELECT rowid, rowtype, value FROM recover_types"));
  591. ASSERT_TRUE(statement.Step());
  592. EXPECT_EQ(4, statement.ColumnInt(0));
  593. EXPECT_EQ("TEXT", statement.ColumnString(1));
  594. EXPECT_EQ(sql::ColumnType::kText, statement.GetColumnType(2));
  595. EXPECT_EQ("This is text", statement.ColumnString(2));
  596. ASSERT_TRUE(statement.Step());
  597. EXPECT_EQ(5, statement.ColumnInt(0));
  598. EXPECT_EQ("BLOB", statement.ColumnString(1));
  599. EXPECT_EQ(sql::ColumnType::kBlob, statement.GetColumnType(2));
  600. std::string blob_text;
  601. ASSERT_TRUE(statement.ColumnBlobAsString(2, &blob_text));
  602. EXPECT_EQ("This is a blob", blob_text);
  603. EXPECT_FALSE(statement.Step());
  604. }
  605. TEST_F(RecoverModuleTest, TextsStrict) {
  606. GenerateTypesTable(&db_);
  607. ASSERT_TRUE(
  608. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  609. "USING recover(types, rowtype TEXT, value TEXT STRICT)"));
  610. sql::Statement statement(db_.GetUniqueStatement(
  611. "SELECT rowid, rowtype, value FROM recover_types"));
  612. ASSERT_TRUE(statement.Step());
  613. EXPECT_EQ(1, statement.ColumnInt(0));
  614. EXPECT_EQ("NULL", statement.ColumnString(1));
  615. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(2));
  616. ASSERT_TRUE(statement.Step());
  617. EXPECT_EQ(4, statement.ColumnInt(0));
  618. EXPECT_EQ("TEXT", statement.ColumnString(1));
  619. EXPECT_EQ(sql::ColumnType::kText, statement.GetColumnType(2));
  620. EXPECT_EQ("This is text", statement.ColumnString(2));
  621. EXPECT_FALSE(statement.Step());
  622. }
  623. TEST_F(RecoverModuleTest, NonNullTextsStrict) {
  624. GenerateTypesTable(&db_);
  625. ASSERT_TRUE(db_.Execute(
  626. "CREATE VIRTUAL TABLE temp.recover_types "
  627. "USING recover(types, rowtype TEXT, value TEXT STRICT NOT NULL)"));
  628. sql::Statement statement(db_.GetUniqueStatement(
  629. "SELECT rowid, rowtype, value FROM recover_types"));
  630. ASSERT_TRUE(statement.Step());
  631. EXPECT_EQ(4, statement.ColumnInt(0));
  632. EXPECT_EQ("TEXT", statement.ColumnString(1));
  633. EXPECT_EQ(sql::ColumnType::kText, statement.GetColumnType(2));
  634. EXPECT_EQ("This is text", statement.ColumnString(2));
  635. EXPECT_FALSE(statement.Step());
  636. }
  637. TEST_F(RecoverModuleTest, Blobs) {
  638. GenerateTypesTable(&db_);
  639. ASSERT_TRUE(
  640. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  641. "USING recover(types, rowtype TEXT, value BLOB)"));
  642. sql::Statement statement(db_.GetUniqueStatement(
  643. "SELECT rowid, rowtype, value FROM recover_types"));
  644. ASSERT_TRUE(statement.Step());
  645. EXPECT_EQ(1, statement.ColumnInt(0));
  646. EXPECT_EQ("NULL", statement.ColumnString(1));
  647. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(2));
  648. ASSERT_TRUE(statement.Step());
  649. EXPECT_EQ(5, statement.ColumnInt(0));
  650. EXPECT_EQ("BLOB", statement.ColumnString(1));
  651. EXPECT_EQ(sql::ColumnType::kBlob, statement.GetColumnType(2));
  652. std::string blob_text;
  653. ASSERT_TRUE(statement.ColumnBlobAsString(2, &blob_text));
  654. EXPECT_EQ("This is a blob", blob_text);
  655. EXPECT_FALSE(statement.Step());
  656. }
  657. TEST_F(RecoverModuleTest, NonNullBlobs) {
  658. GenerateTypesTable(&db_);
  659. ASSERT_TRUE(
  660. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  661. "USING recover(types, rowtype TEXT, value BLOB NOT NULL)"));
  662. sql::Statement statement(db_.GetUniqueStatement(
  663. "SELECT rowid, rowtype, value FROM recover_types"));
  664. ASSERT_TRUE(statement.Step());
  665. EXPECT_EQ(5, statement.ColumnInt(0));
  666. EXPECT_EQ("BLOB", statement.ColumnString(1));
  667. EXPECT_EQ(sql::ColumnType::kBlob, statement.GetColumnType(2));
  668. std::string blob_text;
  669. ASSERT_TRUE(statement.ColumnBlobAsString(2, &blob_text));
  670. EXPECT_EQ("This is a blob", blob_text);
  671. EXPECT_FALSE(statement.Step());
  672. }
  673. TEST_F(RecoverModuleTest, AnyNonNull) {
  674. GenerateTypesTable(&db_);
  675. ASSERT_TRUE(
  676. db_.Execute("CREATE VIRTUAL TABLE temp.recover_types "
  677. "USING recover(types, rowtype TEXT, value ANY NOT NULL)"));
  678. sql::Statement statement(db_.GetUniqueStatement(
  679. "SELECT rowid, rowtype, value FROM recover_types"));
  680. ASSERT_TRUE(statement.Step());
  681. EXPECT_EQ(2, statement.ColumnInt(0));
  682. EXPECT_EQ("INTEGER", statement.ColumnString(1));
  683. EXPECT_EQ(sql::ColumnType::kInteger, statement.GetColumnType(2));
  684. EXPECT_EQ(17, statement.ColumnInt(2));
  685. ASSERT_TRUE(statement.Step());
  686. EXPECT_EQ(3, statement.ColumnInt(0));
  687. EXPECT_EQ("FLOAT", statement.ColumnString(1));
  688. EXPECT_EQ(sql::ColumnType::kFloat, statement.GetColumnType(2));
  689. EXPECT_DOUBLE_EQ(3.1415927, statement.ColumnDouble(2));
  690. ASSERT_TRUE(statement.Step());
  691. EXPECT_EQ(4, statement.ColumnInt(0));
  692. EXPECT_EQ("TEXT", statement.ColumnString(1));
  693. EXPECT_EQ(sql::ColumnType::kText, statement.GetColumnType(2));
  694. EXPECT_EQ("This is text", statement.ColumnString(2));
  695. ASSERT_TRUE(statement.Step());
  696. EXPECT_EQ(5, statement.ColumnInt(0));
  697. EXPECT_EQ("BLOB", statement.ColumnString(1));
  698. EXPECT_EQ(sql::ColumnType::kBlob, statement.GetColumnType(2));
  699. std::string blob_text;
  700. ASSERT_TRUE(statement.ColumnBlobAsString(2, &blob_text));
  701. EXPECT_EQ("This is a blob", blob_text);
  702. EXPECT_FALSE(statement.Step());
  703. }
  704. TEST_F(RecoverModuleTest, RowidAlias) {
  705. GenerateTypesTable(&db_);
  706. // The id column is an alias for rowid, and its values get serialized as NULL.
  707. ASSERT_TRUE(db_.Execute(
  708. "CREATE TABLE types2(id INTEGER PRIMARY KEY, rowtype TEXT, value)"));
  709. ASSERT_TRUE(
  710. db_.Execute("INSERT INTO types2(id, rowtype, value) "
  711. "SELECT rowid, rowtype, value FROM types WHERE true"));
  712. ASSERT_TRUE(db_.Execute(
  713. "CREATE VIRTUAL TABLE temp.recover_types2 "
  714. "USING recover(types2, id ROWID NOT NULL, rowtype TEXT, value ANY)"));
  715. sql::Statement statement(
  716. db_.GetUniqueStatement("SELECT id, rowid, rowtype, value FROM types2"));
  717. ASSERT_TRUE(statement.Step());
  718. EXPECT_EQ(1, statement.ColumnInt(0));
  719. EXPECT_EQ(1, statement.ColumnInt(1));
  720. EXPECT_EQ("NULL", statement.ColumnString(2));
  721. EXPECT_EQ(sql::ColumnType::kNull, statement.GetColumnType(3));
  722. ASSERT_TRUE(statement.Step());
  723. EXPECT_EQ(2, statement.ColumnInt(0));
  724. EXPECT_EQ(2, statement.ColumnInt(1));
  725. EXPECT_EQ("INTEGER", statement.ColumnString(2));
  726. EXPECT_EQ(17, statement.ColumnInt(3));
  727. ASSERT_TRUE(statement.Step());
  728. EXPECT_EQ(3, statement.ColumnInt(0));
  729. EXPECT_EQ(3, statement.ColumnInt(1));
  730. EXPECT_EQ("FLOAT", statement.ColumnString(2));
  731. EXPECT_DOUBLE_EQ(3.1415927, statement.ColumnDouble(3));
  732. ASSERT_TRUE(statement.Step());
  733. EXPECT_EQ(4, statement.ColumnInt(0));
  734. EXPECT_EQ(4, statement.ColumnInt(1));
  735. EXPECT_EQ("TEXT", statement.ColumnString(2));
  736. EXPECT_EQ("This is text", statement.ColumnString(3));
  737. ASSERT_TRUE(statement.Step());
  738. EXPECT_EQ(5, statement.ColumnInt(0));
  739. EXPECT_EQ(5, statement.ColumnInt(1));
  740. EXPECT_EQ("BLOB", statement.ColumnString(2));
  741. std::string blob_text;
  742. ASSERT_TRUE(statement.ColumnBlobAsString(3, &blob_text));
  743. EXPECT_EQ("This is a blob", blob_text);
  744. EXPECT_FALSE(statement.Step());
  745. }
  746. TEST_F(RecoverModuleTest, IntegerEncodings) {
  747. ASSERT_TRUE(db_.Execute("CREATE TABLE integers(value)"));
  748. const std::vector<int64_t> values = {
  749. // Encoded directly in type info.
  750. 0,
  751. 1,
  752. // 8-bit signed.
  753. 2,
  754. -2,
  755. 127,
  756. -128,
  757. // 16-bit signed.
  758. 12345,
  759. -12345,
  760. 32767,
  761. -32768,
  762. // 24-bit signed.
  763. 1234567,
  764. -1234567,
  765. 8388607,
  766. -8388608,
  767. // 32-bit signed.
  768. 1234567890,
  769. -1234567890,
  770. 2147483647,
  771. -2147483647,
  772. // 48-bit signed.
  773. 123456789012345,
  774. -123456789012345,
  775. 140737488355327,
  776. -140737488355327,
  777. // 64-bit signed.
  778. 1234567890123456789,
  779. -1234567890123456789,
  780. 9223372036854775807,
  781. -9223372036854775807,
  782. };
  783. sql::Statement insert(
  784. db_.GetUniqueStatement("INSERT INTO integers VALUES(?)"));
  785. for (int64_t value : values) {
  786. insert.BindInt64(0, value);
  787. ASSERT_TRUE(insert.Run());
  788. insert.Reset(/* clear_bound_vars= */ true);
  789. }
  790. ASSERT_TRUE(
  791. db_.Execute("CREATE VIRTUAL TABLE temp.recover_integers "
  792. "USING recover(integers, value INTEGER)"));
  793. sql::Statement select(
  794. db_.GetUniqueStatement("SELECT rowid, value FROM recover_integers"));
  795. for (size_t i = 0; i < values.size(); ++i) {
  796. ASSERT_TRUE(select.Step()) << "Was attemping to read " << values[i];
  797. EXPECT_EQ(static_cast<int>(i + 1), select.ColumnInt(0));
  798. EXPECT_EQ(values[i], select.ColumnInt64(1));
  799. }
  800. EXPECT_FALSE(select.Step());
  801. }
  802. TEST_F(RecoverModuleTest, VarintEncodings) {
  803. const std::vector<int64_t> values = {
  804. // 1-byte varints.
  805. 0x00, 0x01, 0x02, 0x7e, 0x7f,
  806. // 2-byte varints
  807. 0x80, 0x81, 0xff, 0x0100, 0x0101, 0x1234, 0x1ffe, 0x1fff, 0x3ffe, 0x3fff,
  808. // 3-byte varints
  809. 0x4000, 0x4001, 0x0ffffe, 0x0fffff, 0x123456, 0x1fedcb, 0x1ffffe,
  810. 0x1fffff,
  811. // 4-byte varints
  812. 0x200000, 0x200001, 0x123456, 0xfedcba, 0xfffffe, 0xffffff, 0x01234567,
  813. 0x0fedcba9, 0x0ffffffe, 0x0fffffff,
  814. // 5-byte varints
  815. 0x10000000, 0x10000001, 0x12345678, 0xfedcba98, 0x01'23456789,
  816. 0x07'fffffffe, 0x07'ffffffff,
  817. // 6-byte varints
  818. 0x08'00000000, 0x08'00000001, 0x12'3456789a, 0xfe'dcba9876,
  819. 0x0123'456789ab, 0x03ff'fffffffe, 0x03ff'ffffffff,
  820. // 7-byte varints
  821. 0x0400'00000000, 0x0400'00000001, 0xfedc'ba987654, 0x012345'6789abcd,
  822. 0x01ffff'fffffffe, 0x01ffff'ffffffff,
  823. // 8-byte varints
  824. 0x020000'00000000, 0x020000'00000001, 0x0fedcb'a9876543,
  825. 0x123456'789abcde, 0xfedcba'98765432, 0xffffff'fffffffe,
  826. 0xffffff'ffffffff,
  827. // 9-byte positive varints
  828. 0x01000000'00000000, 0x01000000'00000001, 0x12345678'9abcdef0,
  829. 0x7fedcba9'87654321, 0x7fffffff'fffffffe, 0x7fffffff'ffffffff,
  830. // 9-byte negative varints
  831. -0x01, -0x02, -0x7e, -0x7f, -0x80, -0x81, -0x12345678'9abcdef0,
  832. -0x7fedcba9'87654321, -0x7fffffff'ffffffff,
  833. -0x7fffffff'ffffffff - 1, // -0x80000000'00000000 is not a valid literal
  834. };
  835. ASSERT_TRUE(db_.Execute("CREATE TABLE varints(value INTEGER PRIMARY KEY)"));
  836. ASSERT_TRUE(
  837. db_.Execute("CREATE VIRTUAL TABLE temp.recover_varints "
  838. "USING recover(varints, value ROWID)"));
  839. for (int64_t value : values) {
  840. sql::Statement insert(
  841. db_.GetUniqueStatement("INSERT INTO varints VALUES(?)"));
  842. insert.BindInt64(0, value);
  843. ASSERT_TRUE(insert.Run());
  844. sql::Statement select(
  845. db_.GetUniqueStatement("SELECT rowid, value FROM recover_varints"));
  846. ASSERT_TRUE(select.Step()) << "Was attemping to read " << value;
  847. EXPECT_EQ(value, select.ColumnInt64(0));
  848. EXPECT_EQ(value, select.ColumnInt64(1));
  849. EXPECT_FALSE(select.Step());
  850. ASSERT_TRUE(db_.Execute("DELETE FROM varints"));
  851. }
  852. }
  853. TEST_F(RecoverModuleTest, TextEncodings) {
  854. ASSERT_TRUE(db_.Execute("CREATE TABLE encodings(t TEXT)"));
  855. const std::vector<std::string> values = {
  856. "", "a", "ö", "Mjollnir", "Mjölnir", "Mjǫlnir",
  857. "Mjölner", "Mjølner", "ハンマー",
  858. };
  859. sql::Statement insert(
  860. db_.GetUniqueStatement("INSERT INTO encodings VALUES(?)"));
  861. for (const std::string& value : values) {
  862. insert.BindString(0, value);
  863. ASSERT_TRUE(insert.Run());
  864. insert.Reset(/* clear_bound_vars= */ true);
  865. }
  866. ASSERT_TRUE(
  867. db_.Execute("CREATE VIRTUAL TABLE temp.recover_encodings "
  868. "USING recover(encodings, t TEXT)"));
  869. sql::Statement select(
  870. db_.GetUniqueStatement("SELECT rowid, t FROM recover_encodings"));
  871. for (size_t i = 0; i < values.size(); ++i) {
  872. ASSERT_TRUE(select.Step());
  873. EXPECT_EQ(static_cast<int>(i + 1), select.ColumnInt(0));
  874. EXPECT_EQ(values[i], select.ColumnString(1));
  875. }
  876. EXPECT_FALSE(select.Step());
  877. }
  878. TEST_F(RecoverModuleTest, BlobEncodings) {
  879. ASSERT_TRUE(db_.Execute("CREATE TABLE blob_encodings(t BLOB)"));
  880. const std::vector<std::vector<uint8_t>> values = {
  881. {}, {0x00}, {0x01},
  882. {0x42}, {0xff}, {0x00, 0x00},
  883. {0x00, 0x01}, {0x00, 0xff}, {0x42, 0x43, 0x44, 0x45, 0x46},
  884. };
  885. sql::Statement insert(
  886. db_.GetUniqueStatement("INSERT INTO blob_encodings VALUES(?)"));
  887. for (const std::vector<uint8_t>& value : values) {
  888. insert.BindBlob(0, value);
  889. ASSERT_TRUE(insert.Run());
  890. insert.Reset(/* clear_bound_vars= */ true);
  891. }
  892. ASSERT_TRUE(
  893. db_.Execute("CREATE VIRTUAL TABLE temp.recover_blob_encodings "
  894. "USING recover(blob_encodings, t BLOB)"));
  895. sql::Statement select(
  896. db_.GetUniqueStatement("SELECT rowid, t FROM recover_blob_encodings"));
  897. for (size_t i = 0; i < values.size(); ++i) {
  898. ASSERT_TRUE(select.Step());
  899. EXPECT_EQ(static_cast<int>(i + 1), select.ColumnInt(0));
  900. std::vector<uint8_t> column_value;
  901. EXPECT_TRUE(select.ColumnBlobAsVector(1, &column_value));
  902. EXPECT_EQ(values[i], column_value);
  903. }
  904. EXPECT_FALSE(select.Step());
  905. }
  906. namespace {
  907. std::string RandomString(int size) {
  908. std::mt19937 rng;
  909. std::uniform_int_distribution<int> random_char(32, 127);
  910. std::string large_value;
  911. large_value.reserve(size);
  912. for (int i = 0; i < size; ++i)
  913. large_value.push_back(random_char(rng));
  914. return large_value;
  915. }
  916. void CheckLargeValueRecovery(sql::Database* db, int value_size) {
  917. const std::string large_value = RandomString(value_size);
  918. ASSERT_TRUE(db->Execute("CREATE TABLE overflow(t TEXT)"));
  919. sql::Statement insert(
  920. db->GetUniqueStatement("INSERT INTO overflow VALUES(?)"));
  921. insert.BindString(0, large_value);
  922. ASSERT_TRUE(insert.Run());
  923. ASSERT_TRUE(db->Execute("VACUUM"));
  924. ASSERT_TRUE(
  925. db->Execute("CREATE VIRTUAL TABLE temp.recover_overflow "
  926. "USING recover(overflow, t TEXT)"));
  927. sql::Statement select(
  928. db->GetUniqueStatement("SELECT rowid, t FROM recover_overflow"));
  929. ASSERT_TRUE(select.Step());
  930. EXPECT_EQ(1, select.ColumnInt(0));
  931. EXPECT_EQ(large_value, select.ColumnString(1));
  932. }
  933. bool HasEnabledAutoVacuum(sql::Database* db) {
  934. sql::Statement pragma(db->GetUniqueStatement("PRAGMA auto_vacuum"));
  935. EXPECT_TRUE(pragma.Step());
  936. return pragma.ColumnInt(0) != 0;
  937. }
  938. // The overhead in the table page is:
  939. // * 35 bytes - the cell size cutoff that causes a cell's payload to overflow
  940. // * 1 byte - record header size
  941. // * 2-3 bytes - type ID for the text column
  942. // - texts of 58-8185 bytes use 2 bytes
  943. // - texts of 8186-1048569 bytes use 3 bytes
  944. //
  945. // The overhead below assumes a 2-byte string type ID.
  946. constexpr int kRecordOverhead = 38;
  947. // Each overflow page uses 4 bytes to store the pointer to the next page.
  948. constexpr int kOverflowOverhead = 4;
  949. } // namespace
  950. TEST_F(RecoverModuleTest, ValueWithoutOverflow) {
  951. CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead);
  952. int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0;
  953. ASSERT_EQ(2 + auto_vacuum_pages, sql::test::GetPageCount(&db_))
  954. << "Database should have a root page and a leaf page";
  955. }
  956. TEST_F(RecoverModuleTest, ValueWithOneByteOverflow) {
  957. CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead + 1);
  958. int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0;
  959. ASSERT_EQ(3 + auto_vacuum_pages, sql::test::GetPageCount(&db_))
  960. << "Database should have a root page, a leaf page, and 1 overflow page";
  961. }
  962. TEST_F(RecoverModuleTest, ValueWithOneOverflowPage) {
  963. CheckLargeValueRecovery(
  964. &db_, db_.page_size() - kRecordOverhead + db_.page_size() / 2);
  965. int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0;
  966. ASSERT_EQ(3 + auto_vacuum_pages, sql::test::GetPageCount(&db_))
  967. << "Database should have a root page, a leaf page, and 1 overflow page";
  968. }
  969. TEST_F(RecoverModuleTest, ValueWithOneFullOverflowPage) {
  970. CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead +
  971. db_.page_size() - kOverflowOverhead);
  972. int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0;
  973. ASSERT_EQ(3 + auto_vacuum_pages, sql::test::GetPageCount(&db_))
  974. << "Database should have a root page, a leaf page, and 1 overflow page";
  975. }
  976. TEST_F(RecoverModuleTest, ValueWithOneByteSecondOverflowPage) {
  977. CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead +
  978. db_.page_size() - kOverflowOverhead + 1);
  979. int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0;
  980. ASSERT_EQ(4 + auto_vacuum_pages, sql::test::GetPageCount(&db_))
  981. << "Database should have a root page, a leaf page, and 2 overflow pages";
  982. }
  983. TEST_F(RecoverModuleTest, ValueWithTwoOverflowPages) {
  984. CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead +
  985. db_.page_size() - kOverflowOverhead +
  986. db_.page_size() / 2);
  987. int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0;
  988. ASSERT_EQ(4 + auto_vacuum_pages, sql::test::GetPageCount(&db_))
  989. << "Database should have a root page, a leaf page, and 2 overflow pages";
  990. }
  991. TEST_F(RecoverModuleTest, ValueWithTwoFullOverflowPages) {
  992. // This value is large enough that the varint encoding of its type ID takes up
  993. // 3 bytes, instead of 2.
  994. CheckLargeValueRecovery(&db_, db_.page_size() - kRecordOverhead +
  995. (db_.page_size() - kOverflowOverhead) * 2 -
  996. 1);
  997. int auto_vacuum_pages = HasEnabledAutoVacuum(&db_) ? 1 : 0;
  998. ASSERT_EQ(4 + auto_vacuum_pages, sql::test::GetPageCount(&db_))
  999. << "Database should have a root page, a leaf page, and 2 overflow pages";
  1000. }
  1001. } // namespace recover
  1002. } // namespace sql