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