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 5 #ifndef SQL_RECOVER_MODULE_TABLE_H_ 6 #define SQL_RECOVER_MODULE_TABLE_H_ 7 8 #include <atomic> 9 #include <memory> 10 #include <string> 11 #include <utility> 12 #include <vector> 13 14 #include "base/logging.h" 15 #include "base/optional.h" 16 #include "sql/recover_module/parsing.h" 17 #include "third_party/sqlite/sqlite3.h" 18 19 namespace sql { 20 namespace recover { 21 22 class VirtualCursor; 23 24 // Represents a virtual table created by CREATE VIRTUAL TABLE recover(...). 25 // 26 // Instances are allocated on the heap using the C++ new operator, and passed to 27 // SQLite via pointers to the sqlite_vtab members. SQLite is responsible for 28 // managing the instances' lifetimes. SQLite will call xDisconnect() for every 29 // successful xConnect(), and xDestroy() for every successful xCreate(). 30 // 31 // Instances are thread-safe. 32 class VirtualTable { 33 public: 34 // Returns a SQLite status and a VirtualTable instance. 35 // 36 // The VirtualTable is non-null iff the status is SQLITE_OK. 37 // 38 // SQLite is trusted to keep |sqlite_db| alive for as long as this instance 39 // lives. 40 static std::pair<int, std::unique_ptr<VirtualTable>> Create( 41 sqlite3* sqlite_db, 42 TargetTableSpec backing_table_spec, 43 std::vector<RecoveredColumnSpec> column_specs); 44 45 // Use Create() instead of calling the constructor directly. 46 explicit VirtualTable(sqlite3* sqlite_db, 47 sqlite3_file* sqlite_file, 48 int root_page, 49 int page_size, 50 std::vector<RecoveredColumnSpec> column_specs); 51 ~VirtualTable(); 52 53 VirtualTable(const VirtualTable&) = delete; 54 VirtualTable& operator=(const VirtualTable&) = delete; 55 56 // Returns the embedded SQLite virtual table. 57 // 58 // This getter is not const because SQLite wants a non-const pointer to the 59 // structure. SqliteTable()60 sqlite3_vtab* SqliteTable() { return &sqlite_table_; } 61 62 // Returns SQLite VFS file used to access the backing table's database. 63 // 64 // This getter is not const because it must return a non-const pointer. SqliteFile()65 sqlite3_file* SqliteFile() { return sqlite_file_; } 66 67 // Returns the page number of the root page for the table's B-tree. root_page_id()68 int root_page_id() const { return root_page_id_; } 69 70 // Returns the page size used by the backing table's database. page_size()71 int page_size() const { return page_size_; } 72 73 // Returns the schema of the corrupted table being recovered. column_specs()74 const std::vector<RecoveredColumnSpec> column_specs() const { 75 return column_specs_; 76 } 77 78 // Returns a SQL statement describing the virtual table's schema. 79 // 80 // The return value is suitable to be passed to sqlite3_declare_vtab(). 81 std::string ToCreateTableSql() const; 82 83 // The VirtualTable instance that embeds a given SQLite virtual table. 84 // 85 // |sqlite_table| must have been returned by VirtualTable::SqliteTable(). FromSqliteTable(sqlite3_vtab * sqlite_table)86 static inline VirtualTable* FromSqliteTable(sqlite3_vtab* sqlite_table) { 87 #if 0 88 static_assert(std::is_standard_layout<VirtualTable>::value, 89 "needed for the reinterpret_cast below"); 90 #endif 91 static_assert(offsetof(VirtualTable, sqlite_table_) == 0, 92 "sqlite_table_ must be the first member of the class"); 93 VirtualTable* const result = reinterpret_cast<VirtualTable*>(sqlite_table); 94 DCHECK_EQ(sqlite_table, &result->sqlite_table_); 95 return result; 96 } 97 98 // Creates a new cursor for iterating over this table. 99 VirtualCursor* CreateCursor(); 100 101 // Called right before a cursor belonging to this table will be destroyed. 102 void WillDeleteCursor(VirtualCursor* cursor); 103 104 private: 105 // SQLite handle for this table. The struct is populated and used by SQLite. 106 sqlite3_vtab sqlite_table_; 107 108 // See the corresponding getters for these members' purpose. 109 sqlite3_file* const sqlite_file_; 110 const int root_page_id_; 111 const int page_size_; 112 const std::vector<RecoveredColumnSpec> column_specs_; 113 114 #if DCHECK_IS_ON() 115 // Number of cursors that are still opened. 116 std::atomic<int> open_cursor_count_{0}; 117 #endif // DCHECK_IS_ON() 118 }; 119 120 } // namespace recover 121 } // namespace sql 122 123 #endif // SQL_RECOVER_MODULE_TABLE_H_ 124