module.cc 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  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 "sql/recover_module/module.h"
  5. #include <cstddef>
  6. #include <cstdint>
  7. #include <ostream>
  8. #include <string>
  9. #include <utility>
  10. #include <vector>
  11. #include "base/check_op.h"
  12. #include "base/strings/strcat.h"
  13. #include "base/strings/string_piece.h"
  14. #include "base/strings/string_util.h"
  15. #include "sql/recover_module/cursor.h"
  16. #include "sql/recover_module/parsing.h"
  17. #include "sql/recover_module/table.h"
  18. #include "third_party/sqlite/sqlite3.h"
  19. // https://sqlite.org/vtab.html documents SQLite's virtual table module API.
  20. namespace sql {
  21. namespace recover {
  22. namespace {
  23. // SQLite module argument constants.
  24. static constexpr int kModuleNameArgument = 0;
  25. static constexpr int kVirtualTableDbNameArgument = 1;
  26. static constexpr int kVirtualTableNameArgument = 2;
  27. static constexpr int kBackingTableSpecArgument = 3;
  28. static constexpr int kFirstColumnArgument = 4;
  29. // Returns an empty vector on parse errors.
  30. std::vector<RecoveredColumnSpec> ParseColumnSpecs(int argc,
  31. const char* const* argv) {
  32. std::vector<RecoveredColumnSpec> result;
  33. DCHECK_GE(argc, kFirstColumnArgument);
  34. result.reserve(argc - kFirstColumnArgument + 1);
  35. for (int i = kFirstColumnArgument; i < argc; ++i) {
  36. result.emplace_back(ParseColumnSpec(argv[i]));
  37. if (!result.back().IsValid()) {
  38. result.clear();
  39. break;
  40. }
  41. }
  42. return result;
  43. }
  44. int ModuleCreate(sqlite3* sqlite_db,
  45. void* /* client_data */,
  46. int argc,
  47. const char* const* argv,
  48. sqlite3_vtab** result_sqlite_table,
  49. char** /* error_string */) {
  50. DCHECK(sqlite_db != nullptr);
  51. if (argc <= kFirstColumnArgument) {
  52. // The recovery module needs at least one column specification.
  53. return SQLITE_ERROR;
  54. }
  55. DCHECK(argv != nullptr);
  56. DCHECK(result_sqlite_table != nullptr);
  57. // This module is always expected to be registered as "recover".
  58. DCHECK_EQ("recover", base::StringPiece(argv[kModuleNameArgument]));
  59. base::StringPiece db_name(argv[kVirtualTableDbNameArgument]);
  60. if (db_name != "temp") {
  61. // Refuse to create tables outside the "temp" database.
  62. //
  63. // This check is overly strict. The virtual table can be safely used on any
  64. // temporary database (ATTACH '' AS other_temp). However, there is no easy
  65. // way to determine if an attachment point corresponds to a temporary
  66. // database, and "temp" is sufficient for Chrome's purposes.
  67. return SQLITE_ERROR;
  68. }
  69. base::StringPiece table_name(argv[kVirtualTableNameArgument]);
  70. if (!base::StartsWith(table_name, "recover_")) {
  71. // In the future, we may deploy UMA metrics that use the virtual table name
  72. // to attribute recovery events to Chrome features. In preparation for that
  73. // future, require all recovery table names to start with "recover_".
  74. return SQLITE_ERROR;
  75. }
  76. TargetTableSpec backing_table_spec =
  77. ParseTableSpec(argv[kBackingTableSpecArgument]);
  78. if (!backing_table_spec.IsValid()) {
  79. // The parser concluded that the string specifying the backing table is
  80. // invalid. This is definitely an error in the SQL using the virtual table.
  81. return SQLITE_ERROR;
  82. }
  83. std::vector<RecoveredColumnSpec> column_specs = ParseColumnSpecs(argc, argv);
  84. if (column_specs.empty()) {
  85. // The column specifications were invalid.
  86. return SQLITE_ERROR;
  87. }
  88. auto [sqlite_status, table] = VirtualTable::Create(
  89. sqlite_db, std::move(backing_table_spec), std::move(column_specs));
  90. if (sqlite_status != SQLITE_OK)
  91. return sqlite_status;
  92. {
  93. std::string create_table_sql = table->ToCreateTableSql();
  94. sqlite3_declare_vtab(sqlite_db, create_table_sql.c_str());
  95. }
  96. *result_sqlite_table = table->SqliteTable();
  97. table.release(); // SQLite manages the lifetime of the table.
  98. return SQLITE_OK;
  99. }
  100. int ModuleConnect(sqlite3* sqlite_db,
  101. void* client_data,
  102. int argc,
  103. const char* const* argv,
  104. sqlite3_vtab** result_sqlite_table,
  105. char** error_string) {
  106. // TODO(pwnall): Figure out if it's acceptable to have "recover" be an
  107. // eponymous table. If so, use ModuleCreate instead of
  108. // ModuleConnect in the entry point table.
  109. return ModuleCreate(sqlite_db, client_data, argc, argv, result_sqlite_table,
  110. error_string);
  111. }
  112. int ModuleBestIndex(sqlite3_vtab* sqlite_table,
  113. sqlite3_index_info* index_info) {
  114. DCHECK(sqlite_table != nullptr);
  115. DCHECK(index_info != nullptr);
  116. // The sqlite3_index_info structure is also documented at
  117. // https://www.sqlite.org/draft/c3ref/index_info.html
  118. for (int i = 0; i < index_info->nConstraint; ++i) {
  119. if (index_info->aConstraint[i].usable == static_cast<char>(false))
  120. continue;
  121. // True asks SQLite to evaluate the constraint and pass the result to any
  122. // follow-up xFilter() calls, via argc/argv.
  123. index_info->aConstraintUsage[i].argvIndex = 0;
  124. // True indicates that the virtual table will check the constraint.
  125. index_info->aConstraintUsage[i].omit = false;
  126. }
  127. index_info->orderByConsumed = static_cast<int>(false);
  128. // SQLite saves the sqlite_idx_info fields set here and passes the values to
  129. // xFilter().
  130. index_info->idxStr = nullptr;
  131. index_info->idxNum = 0;
  132. index_info->needToFreeIdxStr = static_cast<int>(false);
  133. return SQLITE_OK;
  134. }
  135. int ModuleDisconnect(sqlite3_vtab* sqlite_table) {
  136. DCHECK(sqlite_table != nullptr);
  137. // SQLite takes ownership of the VirtualTable (which is passed around as a
  138. // sqlite_table) in ModuleCreate() / ModuleConnect(). SQLite then calls
  139. // ModuleDestroy() / ModuleDisconnect() to relinquish ownership of the
  140. // VirtualTable. At this point, the table will not be used again, and can be
  141. // destroyed.
  142. VirtualTable* const table = VirtualTable::FromSqliteTable(sqlite_table);
  143. delete table;
  144. return SQLITE_OK;
  145. }
  146. int ModuleDestroy(sqlite3_vtab* sqlite_table) {
  147. return ModuleDisconnect(sqlite_table);
  148. }
  149. int ModuleOpen(sqlite3_vtab* sqlite_table,
  150. sqlite3_vtab_cursor** result_sqlite_cursor) {
  151. DCHECK(sqlite_table != nullptr);
  152. DCHECK(result_sqlite_cursor != nullptr);
  153. VirtualTable* const table = VirtualTable::FromSqliteTable(sqlite_table);
  154. VirtualCursor* const cursor = table->CreateCursor();
  155. *result_sqlite_cursor = cursor->SqliteCursor();
  156. return SQLITE_OK;
  157. }
  158. int ModuleClose(sqlite3_vtab_cursor* sqlite_cursor) {
  159. DCHECK(sqlite_cursor != nullptr);
  160. // SQLite takes ownership of the VirtualCursor (which is passed around as a
  161. // sqlite_cursor) in ModuleOpen(). SQLite then calls ModuleClose() to
  162. // relinquish ownership of the VirtualCursor. At this point, the cursor will
  163. // not be used again, and can be destroyed.
  164. VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor);
  165. delete cursor;
  166. return SQLITE_OK;
  167. }
  168. int ModuleFilter(sqlite3_vtab_cursor* sqlite_cursor,
  169. int /* best_index_num */,
  170. const char* /* best_index_str */,
  171. int /* argc */,
  172. sqlite3_value** /* argv */) {
  173. DCHECK(sqlite_cursor != nullptr);
  174. VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor);
  175. return cursor->First();
  176. }
  177. int ModuleNext(sqlite3_vtab_cursor* sqlite_cursor) {
  178. DCHECK(sqlite_cursor != nullptr);
  179. VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor);
  180. return cursor->Next();
  181. }
  182. int ModuleEof(sqlite3_vtab_cursor* sqlite_cursor) {
  183. DCHECK(sqlite_cursor != nullptr);
  184. VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor);
  185. return cursor->IsValid() ? 0 : 1;
  186. }
  187. int ModuleColumn(sqlite3_vtab_cursor* sqlite_cursor,
  188. sqlite3_context* result_context,
  189. int column_index) {
  190. DCHECK(sqlite_cursor != nullptr);
  191. DCHECK(result_context != nullptr);
  192. VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor);
  193. DCHECK(cursor->IsValid()) << "SQLite called xRowid() without a valid cursor";
  194. return cursor->ReadColumn(column_index, result_context);
  195. }
  196. int ModuleRowid(sqlite3_vtab_cursor* sqlite_cursor,
  197. sqlite3_int64* result_rowid) {
  198. DCHECK(sqlite_cursor != nullptr);
  199. DCHECK(result_rowid != nullptr);
  200. VirtualCursor* const cursor = VirtualCursor::FromSqliteCursor(sqlite_cursor);
  201. DCHECK(cursor->IsValid()) << "SQLite called xRowid() without a valid cursor";
  202. *result_rowid = cursor->RowId();
  203. return SQLITE_OK;
  204. }
  205. // SQLite module API version supported by this implementation.
  206. constexpr int kSqliteModuleApiVersion = 1;
  207. // Entry points to the SQLite module.
  208. constexpr sqlite3_module kSqliteModule = {
  209. kSqliteModuleApiVersion,
  210. &ModuleCreate,
  211. &ModuleConnect,
  212. &ModuleBestIndex,
  213. &ModuleDisconnect,
  214. &ModuleDestroy,
  215. &ModuleOpen,
  216. &ModuleClose,
  217. &ModuleFilter,
  218. &ModuleNext,
  219. &ModuleEof,
  220. &ModuleColumn,
  221. &ModuleRowid,
  222. /* xUpdate= */ nullptr,
  223. /* xBegin= */ nullptr,
  224. /* xSync= */ nullptr,
  225. /* xCommit= */ nullptr,
  226. /* xRollback= */ nullptr,
  227. /* xFindFunction= */ nullptr,
  228. /* xRename= */ nullptr,
  229. };
  230. } // namespace
  231. int RegisterRecoverExtension(sqlite3* db) {
  232. return sqlite3_create_module_v2(db, "recover", &kSqliteModule,
  233. /* pClientData= */ nullptr,
  234. /* xDestroy= */ nullptr);
  235. }
  236. } // namespace recover
  237. } // namespace sql