Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2018 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
Lalit Maganti | 737b376 | 2019-08-26 13:46:37 -0700 | [diff] [blame] | 17 | #ifndef SRC_TRACE_PROCESSOR_SQLITE_SQLITE_TABLE_H_ |
| 18 | #define SRC_TRACE_PROCESSOR_SQLITE_SQLITE_TABLE_H_ |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 19 | |
Primiano Tucci | 02c1176 | 2019-08-30 00:57:59 +0200 | [diff] [blame] | 20 | #include <sqlite3.h> |
| 21 | |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 22 | #include <functional> |
Lalit Maganti | 920f4f9 | 2020-02-19 13:45:05 +0000 | [diff] [blame] | 23 | #include <limits> |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 24 | #include <memory> |
Lalit Maganti | 4e2303c | 2023-03-29 15:28:36 +0100 | [diff] [blame] | 25 | #include <optional> |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 26 | #include <string> |
| 27 | #include <vector> |
| 28 | |
Lalit Maganti | 3927af8 | 2022-05-09 20:23:40 +0100 | [diff] [blame] | 29 | #include "perfetto/base/status.h" |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 30 | #include "perfetto/ext/base/flat_hash_map.h" |
| 31 | #include "perfetto/ext/base/status_or.h" |
Primiano Tucci | 2272792 | 2019-06-01 10:07:42 +0100 | [diff] [blame] | 32 | #include "perfetto/ext/base/utils.h" |
Lalit Maganti | 7ee6abb | 2019-05-09 17:57:32 +0100 | [diff] [blame] | 33 | #include "perfetto/trace_processor/basic_types.h" |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 34 | #include "src/trace_processor/db/table.h" |
Lalit Maganti | 737b376 | 2019-08-26 13:46:37 -0700 | [diff] [blame] | 35 | #include "src/trace_processor/sqlite/query_constraints.h" |
Primiano Tucci | 0e9bca4 | 2018-08-31 19:20:58 +0200 | [diff] [blame] | 36 | |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 37 | namespace perfetto { |
| 38 | namespace trace_processor { |
| 39 | |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 40 | class SqliteEngine; |
| 41 | class TypedSqliteTableBase; |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 42 | |
| 43 | // Abstract base class representing a SQLite virtual table. Implements the |
| 44 | // common bookeeping required across all tables and allows subclasses to |
| 45 | // implement a friendlier API than that required by SQLite. |
Lalit Maganti | 5132c65 | 2019-07-29 23:31:12 +0530 | [diff] [blame] | 46 | class SqliteTable : public sqlite3_vtab { |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 47 | public: |
Lalit Maganti | 9c60ce6 | 2022-11-11 19:18:50 +0000 | [diff] [blame] | 48 | // Custom opcodes used by subclasses of SqliteTable. |
| 49 | // Stored here as we need a central repository of opcodes to prevent clashes |
| 50 | // between different sub-classes. |
| 51 | enum CustomFilterOpcode { |
| 52 | kSourceGeqOpCode = SQLITE_INDEX_CONSTRAINT_FUNCTION + 1, |
| 53 | }; |
Lalit Maganti | a270b65 | 2018-09-26 11:54:33 +0100 | [diff] [blame] | 54 | // Describes a column of this table. |
| 55 | class Column { |
| 56 | public: |
Lalit Maganti | 58da68b | 2019-08-29 14:19:07 +0100 | [diff] [blame] | 57 | Column(size_t idx, |
| 58 | std::string name, |
| 59 | SqlValue::Type type, |
| 60 | bool hidden = false); |
Lalit Maganti | a270b65 | 2018-09-26 11:54:33 +0100 | [diff] [blame] | 61 | |
| 62 | size_t index() const { return index_; } |
| 63 | const std::string& name() const { return name_; } |
Lalit Maganti | 58da68b | 2019-08-29 14:19:07 +0100 | [diff] [blame] | 64 | SqlValue::Type type() const { return type_; } |
Lalit Maganti | 8a39fae | 2020-01-20 17:22:10 +0000 | [diff] [blame] | 65 | |
Lalit Maganti | a270b65 | 2018-09-26 11:54:33 +0100 | [diff] [blame] | 66 | bool hidden() const { return hidden_; } |
Lalit Maganti | 8a39fae | 2020-01-20 17:22:10 +0000 | [diff] [blame] | 67 | void set_hidden(bool hidden) { hidden_ = hidden; } |
Lalit Maganti | a270b65 | 2018-09-26 11:54:33 +0100 | [diff] [blame] | 68 | |
| 69 | private: |
| 70 | size_t index_ = 0; |
| 71 | std::string name_; |
Lalit Maganti | 58da68b | 2019-08-29 14:19:07 +0100 | [diff] [blame] | 72 | SqlValue::Type type_ = SqlValue::Type::kNull; |
Lalit Maganti | a270b65 | 2018-09-26 11:54:33 +0100 | [diff] [blame] | 73 | bool hidden_ = false; |
| 74 | }; |
| 75 | |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 76 | // Abstract base class representing an SQLite Cursor. Presents a friendlier |
| 77 | // API for subclasses to implement. |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 78 | class BaseCursor : public sqlite3_vtab_cursor { |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 79 | public: |
Lalit Maganti | a40168c | 2019-11-18 14:22:27 +0000 | [diff] [blame] | 80 | // Enum for the history of calls to Filter. |
| 81 | enum class FilterHistory : uint32_t { |
| 82 | // Indicates that constraint set passed is the different to the |
| 83 | // previous Filter call. |
| 84 | kDifferent = 0, |
| 85 | |
| 86 | // Indicates that the constraint set passed is the same as the previous |
| 87 | // Filter call. |
| 88 | // This can be useful for subclasses to perform optimizations on repeated |
| 89 | // nested subqueries. |
| 90 | kSame = 1, |
| 91 | }; |
| 92 | |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 93 | explicit BaseCursor(SqliteTable* table); |
| 94 | virtual ~BaseCursor(); |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 95 | |
| 96 | // Methods to be implemented by derived table classes. |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 97 | // Note: these methods are intentionally not virtual for performance |
| 98 | // reasons. As these methods are not defined, there will be compile errors |
| 99 | // thrown if any of these methods are missing. |
Lalit Maganti | f1a8d52 | 2019-04-26 11:05:15 +0100 | [diff] [blame] | 100 | |
| 101 | // Called to intialise the cursor with the constraints of the query. |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 102 | base::Status Filter(const QueryConstraints& qc, |
| 103 | sqlite3_value**, |
| 104 | FilterHistory); |
Lalit Maganti | f1a8d52 | 2019-04-26 11:05:15 +0100 | [diff] [blame] | 105 | |
| 106 | // Called to forward the cursor to the next row in the table. |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 107 | base::Status Next(); |
Lalit Maganti | f1a8d52 | 2019-04-26 11:05:15 +0100 | [diff] [blame] | 108 | |
| 109 | // Called to check if the cursor has reached eof. Column will be called iff |
| 110 | // this method returns true. |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 111 | bool Eof(); |
Lalit Maganti | f1a8d52 | 2019-04-26 11:05:15 +0100 | [diff] [blame] | 112 | |
| 113 | // Used to extract the value from the column at index |N|. |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 114 | base::Status Column(sqlite3_context* context, int N); |
| 115 | |
| 116 | SqliteTable* table() const { return table_; } |
Lalit Maganti | f0b4e17 | 2018-09-27 13:43:26 +0100 | [diff] [blame] | 117 | |
Lalit Maganti | f1a8d52 | 2019-04-26 11:05:15 +0100 | [diff] [blame] | 118 | protected: |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 119 | BaseCursor(BaseCursor&) = delete; |
| 120 | BaseCursor& operator=(const BaseCursor&) = delete; |
Lalit Maganti | f0b4e17 | 2018-09-27 13:43:26 +0100 | [diff] [blame] | 121 | |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 122 | BaseCursor(BaseCursor&&) noexcept = default; |
| 123 | BaseCursor& operator=(BaseCursor&&) = default; |
Lalit Maganti | f4588fc | 2018-09-24 14:14:49 +0100 | [diff] [blame] | 124 | |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 125 | private: |
Lalit Maganti | 5132c65 | 2019-07-29 23:31:12 +0530 | [diff] [blame] | 126 | SqliteTable* table_ = nullptr; |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 127 | }; |
| 128 | |
Lalit Maganti | a270b65 | 2018-09-26 11:54:33 +0100 | [diff] [blame] | 129 | // The schema of the table. Created by subclasses to allow the table class to |
| 130 | // do filtering and inform SQLite about the CREATE table statement. |
| 131 | class Schema { |
| 132 | public: |
| 133 | Schema(); |
| 134 | Schema(std::vector<Column>, std::vector<size_t> primary_keys); |
| 135 | |
| 136 | // This class is explicitly copiable. |
Lalit Maganti | 1ebebf1 | 2018-10-15 17:24:04 +0100 | [diff] [blame] | 137 | Schema(const Schema&); |
Lalit Maganti | a270b65 | 2018-09-26 11:54:33 +0100 | [diff] [blame] | 138 | Schema& operator=(const Schema& t); |
| 139 | |
Lalit Maganti | f45f8ad | 2018-12-06 12:58:15 +0000 | [diff] [blame] | 140 | std::string ToCreateTableStmt() const; |
Lalit Maganti | a270b65 | 2018-09-26 11:54:33 +0100 | [diff] [blame] | 141 | |
Lalit Maganti | acda68b | 2018-10-29 15:23:25 +0000 | [diff] [blame] | 142 | const std::vector<Column>& columns() const { return columns_; } |
Lalit Maganti | 8a39fae | 2020-01-20 17:22:10 +0000 | [diff] [blame] | 143 | std::vector<Column>* mutable_columns() { return &columns_; } |
| 144 | |
Lalit Maganti | a270b65 | 2018-09-26 11:54:33 +0100 | [diff] [blame] | 145 | const std::vector<size_t> primary_keys() { return primary_keys_; } |
| 146 | |
| 147 | private: |
| 148 | // The names and types of the columns of the table. |
| 149 | std::vector<Column> columns_; |
| 150 | |
| 151 | // The primary keys of the table given by an offset into |columns|. |
| 152 | std::vector<size_t> primary_keys_; |
| 153 | }; |
| 154 | |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 155 | enum TableType { |
| 156 | // A table which automatically exists in the main schema and cannot be |
| 157 | // created with CREATE VIRTUAL TABLE. |
| 158 | // Note: the name value here matches the naming in the vtable docs of |
| 159 | // SQLite. |
| 160 | kEponymousOnly, |
| 161 | |
| 162 | // A table which must be explicitly created using a CREATE VIRTUAL TABLE |
| 163 | // statement (i.e. does exist automatically). |
| 164 | kExplicitCreate, |
| 165 | }; |
| 166 | |
| 167 | // Public for unique_ptr destructor calls. |
| 168 | virtual ~SqliteTable(); |
| 169 | |
| 170 | // When set it logs all BestIndex and Filter actions on the console. |
| 171 | static bool debug; |
| 172 | |
Lalit Maganti | acda68b | 2018-10-29 15:23:25 +0000 | [diff] [blame] | 173 | protected: |
| 174 | // Populated by a BestIndex call to allow subclasses to tweak SQLite's |
| 175 | // handling of sets of constraints. |
| 176 | struct BestIndexInfo { |
Lalit Maganti | fb57462 | 2019-11-12 13:41:26 +0000 | [diff] [blame] | 177 | // Contains bools which indicate whether SQLite should omit double checking |
| 178 | // the constraint at that index. |
| 179 | // |
| 180 | // If there are no constraints, SQLite will be told it can omit checking for |
| 181 | // the whole query. |
| 182 | std::vector<bool> sqlite_omit_constraint; |
Lalit Maganti | 8706991 | 2019-11-07 18:23:46 +0000 | [diff] [blame] | 183 | |
| 184 | // Indicates that SQLite should not double check the result of the order by |
| 185 | // clause. |
| 186 | // |
Lalit Maganti | fb57462 | 2019-11-12 13:41:26 +0000 | [diff] [blame] | 187 | // If there are no order by clauses, this value will be ignored and SQLite |
Lalit Maganti | 8706991 | 2019-11-07 18:23:46 +0000 | [diff] [blame] | 188 | // will be told that it can omit double checking (i.e. this value will |
| 189 | // implicitly be taken to be true). |
| 190 | bool sqlite_omit_order_by = false; |
Lalit Maganti | fb57462 | 2019-11-12 13:41:26 +0000 | [diff] [blame] | 191 | |
| 192 | // Stores the estimated cost of this query. |
Lalit Maganti | 6585224 | 2019-11-22 17:33:23 +0000 | [diff] [blame] | 193 | double estimated_cost = 0; |
| 194 | |
Lalit Maganti | 820373f | 2019-12-11 13:47:59 +0000 | [diff] [blame] | 195 | // Estimated row count. |
| 196 | int64_t estimated_rows = 0; |
Lalit Maganti | acda68b | 2018-10-29 15:23:25 +0000 | [diff] [blame] | 197 | }; |
| 198 | |
Lalit Maganti | 5132c65 | 2019-07-29 23:31:12 +0530 | [diff] [blame] | 199 | SqliteTable(); |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 200 | |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 201 | // Methods to be implemented by derived table classes. |
Lalit Maganti | 3927af8 | 2022-05-09 20:23:40 +0100 | [diff] [blame] | 202 | virtual base::Status Init(int argc, const char* const* argv, Schema*) = 0; |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 203 | virtual std::unique_ptr<BaseCursor> CreateCursor() = 0; |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 204 | virtual int BestIndex(const QueryConstraints& qc, BestIndexInfo* info) = 0; |
| 205 | |
| 206 | // Optional metods to implement. |
Lalit Maganti | 8947447 | 2020-06-24 13:21:41 +0100 | [diff] [blame] | 207 | using FindFunctionFn = void (*)(sqlite3_context*, int, sqlite3_value**); |
Lalit Maganti | 116d74c | 2023-05-03 16:57:29 +0100 | [diff] [blame] | 208 | virtual base::Status ModifyConstraints(QueryConstraints* qc); |
Lalit Maganti | 8947447 | 2020-06-24 13:21:41 +0100 | [diff] [blame] | 209 | virtual int FindFunction(const char* name, FindFunctionFn* fn, void** args); |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 210 | |
Lalit Maganti | f4588fc | 2018-09-24 14:14:49 +0100 | [diff] [blame] | 211 | // At registration time, the function should also pass true for |read_write|. |
Lalit Maganti | 116d74c | 2023-05-03 16:57:29 +0100 | [diff] [blame] | 212 | virtual base::Status Update(int, sqlite3_value**, sqlite3_int64*); |
Lalit Maganti | 43d8f14 | 2018-11-12 14:58:15 +0000 | [diff] [blame] | 213 | |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 214 | bool ReadConstraints(int idxNum, const char* idxStr, int argc); |
| 215 | |
Lalit Maganti | 127479a | 2019-03-13 18:52:11 +0000 | [diff] [blame] | 216 | const Schema& schema() const { return schema_; } |
Lalit Maganti | 52b9dc7 | 2022-11-15 17:53:06 +0000 | [diff] [blame] | 217 | const std::string& module_name() const { return module_name_; } |
Lalit Maganti | 127479a | 2019-03-13 18:52:11 +0000 | [diff] [blame] | 218 | const std::string& name() const { return name_; } |
Lalit Maganti | acda68b | 2018-10-29 15:23:25 +0000 | [diff] [blame] | 219 | |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 220 | private: |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 221 | template <typename, typename> |
| 222 | friend class TypedSqliteTable; |
| 223 | friend class TypedSqliteTableBase; |
Lalit Maganti | 116d74c | 2023-05-03 16:57:29 +0100 | [diff] [blame] | 224 | |
Lalit Maganti | 5132c65 | 2019-07-29 23:31:12 +0530 | [diff] [blame] | 225 | SqliteTable(const SqliteTable&) = delete; |
| 226 | SqliteTable& operator=(const SqliteTable&) = delete; |
Primiano Tucci | b2ea4d4 | 2018-08-21 15:05:13 +0200 | [diff] [blame] | 227 | |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 228 | // The engine class this table is registered with. Used for restoring/saving |
| 229 | // the table. |
| 230 | SqliteEngine* engine_ = nullptr; |
| 231 | |
Lalit Maganti | 52b9dc7 | 2022-11-15 17:53:06 +0000 | [diff] [blame] | 232 | // This name of the table. For tables created using CREATE VIRTUAL TABLE, this |
| 233 | // will be the name of the table specified by the query. For automatically |
Anna Mayzner | 46ceee2 | 2023-07-31 10:50:00 +0000 | [diff] [blame] | 234 | // created tables, this will be the same as the module name registered. |
Primiano Tucci | b2ea4d4 | 2018-08-21 15:05:13 +0200 | [diff] [blame] | 235 | std::string name_; |
Lalit Maganti | 52b9dc7 | 2022-11-15 17:53:06 +0000 | [diff] [blame] | 236 | |
Anna Mayzner | 46ceee2 | 2023-07-31 10:50:00 +0000 | [diff] [blame] | 237 | // The module name is the name that will be registered. This is |
| 238 | // differs from the table name (|name_|) where the table was created using |
| 239 | // CREATE VIRTUAL TABLE. |
Lalit Maganti | 52b9dc7 | 2022-11-15 17:53:06 +0000 | [diff] [blame] | 240 | std::string module_name_; |
| 241 | |
Lalit Maganti | a270b65 | 2018-09-26 11:54:33 +0100 | [diff] [blame] | 242 | Schema schema_; |
| 243 | |
Primiano Tucci | 0e9bca4 | 2018-08-31 19:20:58 +0200 | [diff] [blame] | 244 | QueryConstraints qc_cache_; |
| 245 | int qc_hash_ = 0; |
| 246 | int best_index_num_ = 0; |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 247 | }; |
| 248 | |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 249 | class TypedSqliteTableBase : public SqliteTable { |
| 250 | protected: |
| 251 | struct BaseModuleArg { |
| 252 | sqlite3_module module; |
| 253 | SqliteEngine* engine; |
Lalit Maganti | 32c7b04 | 2023-06-22 23:00:57 +0100 | [diff] [blame] | 254 | TableType table_type; |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 255 | }; |
| 256 | |
| 257 | ~TypedSqliteTableBase() override; |
| 258 | |
| 259 | static int xDestroy(sqlite3_vtab*); |
| 260 | static int xDestroyFatal(sqlite3_vtab*); |
| 261 | |
| 262 | static int xConnectRestoreTable(sqlite3* xdb, |
| 263 | void* arg, |
| 264 | int argc, |
| 265 | const char* const* argv, |
| 266 | sqlite3_vtab** tab, |
| 267 | char** pzErr); |
| 268 | static int xDisconnectSaveTable(sqlite3_vtab*); |
| 269 | |
| 270 | static int xOpen(sqlite3_vtab*, sqlite3_vtab_cursor**); |
| 271 | static int xBestIndex(sqlite3_vtab*, sqlite3_index_info*); |
| 272 | |
| 273 | static base::Status DeclareAndAssignVtab(std::unique_ptr<SqliteTable> table, |
| 274 | sqlite3_vtab** tab); |
| 275 | |
| 276 | base::Status InitInternal(SqliteEngine* engine, |
| 277 | int argc, |
| 278 | const char* const* argv); |
| 279 | |
| 280 | int SetStatusAndReturn(base::Status status) { |
| 281 | if (!status.ok()) { |
| 282 | sqlite3_free(zErrMsg); |
| 283 | zErrMsg = sqlite3_mprintf("%s", status.c_message()); |
| 284 | return SQLITE_ERROR; |
| 285 | } |
| 286 | return SQLITE_OK; |
| 287 | } |
| 288 | }; |
| 289 | |
| 290 | template <typename SubTable, typename Context> |
| 291 | class TypedSqliteTable : public TypedSqliteTableBase { |
| 292 | public: |
Alexander Timin | 7b34356 | 2023-06-23 13:32:56 +0100 | [diff] [blame] | 293 | struct ModuleArg : public BaseModuleArg { |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 294 | Context context; |
| 295 | }; |
| 296 | |
| 297 | static std::unique_ptr<ModuleArg> CreateModuleArg(SqliteEngine* engine, |
| 298 | Context ctx, |
| 299 | TableType table_type, |
| 300 | bool updatable) { |
| 301 | auto arg = std::make_unique<ModuleArg>(); |
| 302 | arg->module = CreateModule(table_type, updatable); |
| 303 | arg->engine = engine; |
Alexander Timin | 7b34356 | 2023-06-23 13:32:56 +0100 | [diff] [blame] | 304 | arg->table_type = table_type; |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 305 | arg->context = std::move(ctx); |
| 306 | return arg; |
| 307 | } |
| 308 | |
| 309 | private: |
| 310 | static constexpr sqlite3_module CreateModule(TableType table_type, |
| 311 | bool updatable) { |
| 312 | sqlite3_module module; |
| 313 | memset(&module, 0, sizeof(sqlite3_module)); |
| 314 | switch (table_type) { |
| 315 | case TableType::kEponymousOnly: |
| 316 | // Neither xCreate nor xDestroy should ever be called for |
| 317 | // eponymous-only tables. |
| 318 | module.xCreate = nullptr; |
| 319 | module.xDestroy = &xDestroyFatal; |
| 320 | |
| 321 | // xConnect and xDisconnect will automatically be called with |
| 322 | // |module_name| == |name|. |
| 323 | module.xConnect = &xCreate; |
| 324 | module.xDisconnect = &xDestroy; |
| 325 | break; |
| 326 | case TableType::kExplicitCreate: |
Lalit Maganti | 204ecd7 | 2023-12-05 11:19:09 +0000 | [diff] [blame] | 327 | // xCreate and xDestroy will be called when the table is CREATE-ed and |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 328 | // DROP-ed respectively. |
| 329 | module.xCreate = &xCreate; |
| 330 | module.xDestroy = &xDestroy; |
| 331 | |
| 332 | // xConnect and xDisconnect can be called at any time. |
| 333 | module.xConnect = &xConnectRestoreTable; |
| 334 | module.xDisconnect = &xDisconnectSaveTable; |
| 335 | break; |
| 336 | } |
| 337 | module.xOpen = &xOpen; |
| 338 | module.xClose = &xClose; |
| 339 | module.xBestIndex = &xBestIndex; |
| 340 | module.xFindFunction = &xFindFunction; |
| 341 | module.xFilter = &xFilter; |
| 342 | module.xNext = &xNext; |
| 343 | module.xEof = &xEof; |
| 344 | module.xColumn = &xColumn; |
| 345 | module.xRowid = &xRowid; |
| 346 | if (updatable) { |
| 347 | module.xUpdate = &xUpdate; |
| 348 | } |
| 349 | return module; |
| 350 | } |
| 351 | |
| 352 | static int xCreate(sqlite3* xdb, |
| 353 | void* arg, |
| 354 | int argc, |
| 355 | const char* const* argv, |
| 356 | sqlite3_vtab** tab, |
| 357 | char** pzErr) { |
| 358 | auto* xdesc = static_cast<ModuleArg*>(arg); |
Lalit Maganti | 4b379ad | 2023-08-10 19:00:55 +0100 | [diff] [blame] | 359 | std::unique_ptr<SubTable> table(new SubTable(xdb, &*xdesc->context)); |
Lalit Maganti | 32c7b04 | 2023-06-22 23:00:57 +0100 | [diff] [blame] | 360 | SubTable* table_ptr = table.get(); |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 361 | base::Status status = table->InitInternal(xdesc->engine, argc, argv); |
| 362 | if (!status.ok()) { |
| 363 | *pzErr = sqlite3_mprintf("%s", status.c_message()); |
| 364 | return SQLITE_ERROR; |
| 365 | } |
| 366 | status = DeclareAndAssignVtab(std::move(table), tab); |
| 367 | if (!status.ok()) { |
| 368 | *pzErr = sqlite3_mprintf("%s", status.c_message()); |
| 369 | return SQLITE_ERROR; |
| 370 | } |
Lalit Maganti | 32c7b04 | 2023-06-22 23:00:57 +0100 | [diff] [blame] | 371 | xdesc->engine->OnSqliteTableCreated(table_ptr->name(), xdesc->table_type); |
Lalit Maganti | 9a2b96d | 2023-05-11 17:13:48 +0100 | [diff] [blame] | 372 | return SQLITE_OK; |
| 373 | } |
| 374 | static int xClose(sqlite3_vtab_cursor* c) { |
| 375 | delete static_cast<typename SubTable::Cursor*>(c); |
| 376 | return SQLITE_OK; |
| 377 | } |
| 378 | static int xFindFunction(sqlite3_vtab* t, |
| 379 | int, |
| 380 | const char* name, |
| 381 | void (**fn)(sqlite3_context*, int, sqlite3_value**), |
| 382 | void** args) { |
| 383 | return static_cast<SubTable*>(t)->FindFunction(name, fn, args); |
| 384 | } |
| 385 | static int xFilter(sqlite3_vtab_cursor* vc, |
| 386 | int i, |
| 387 | const char* s, |
| 388 | int a, |
| 389 | sqlite3_value** v) { |
| 390 | auto* cursor = static_cast<typename SubTable::Cursor*>(vc); |
| 391 | bool is_cached = cursor->table()->ReadConstraints(i, s, a); |
| 392 | auto history = is_cached ? BaseCursor::FilterHistory::kSame |
| 393 | : BaseCursor::FilterHistory::kDifferent; |
| 394 | auto* table = static_cast<SubTable*>(cursor->table()); |
| 395 | return table->SetStatusAndReturn( |
| 396 | cursor->Filter(cursor->table()->qc_cache_, v, history)); |
| 397 | } |
| 398 | static int xNext(sqlite3_vtab_cursor* c) { |
| 399 | auto* cursor = static_cast<typename SubTable::Cursor*>(c); |
| 400 | auto* table = static_cast<SubTable*>(cursor->table()); |
| 401 | return table->SetStatusAndReturn(cursor->Next()); |
| 402 | } |
| 403 | static int xEof(sqlite3_vtab_cursor* c) { |
| 404 | return static_cast<int>(static_cast<typename SubTable::Cursor*>(c)->Eof()); |
| 405 | } |
| 406 | static int xColumn(sqlite3_vtab_cursor* c, sqlite3_context* a, int b) { |
| 407 | auto* cursor = static_cast<typename SubTable::Cursor*>(c); |
| 408 | auto* table = static_cast<SubTable*>(cursor->table()); |
| 409 | return table->SetStatusAndReturn(cursor->Column(a, b)); |
| 410 | } |
| 411 | static int xRowid(sqlite3_vtab_cursor*, sqlite3_int64*) { |
| 412 | return SQLITE_ERROR; |
| 413 | } |
| 414 | static int xUpdate(sqlite3_vtab* t, |
| 415 | int a, |
| 416 | sqlite3_value** v, |
| 417 | sqlite3_int64* r) { |
| 418 | auto* table = static_cast<SubTable*>(t); |
| 419 | return table->SetStatusAndReturn(table->Update(a, v, r)); |
| 420 | } |
| 421 | }; |
| 422 | |
Primiano Tucci | 3bf99f3 | 2018-07-24 10:28:28 +0100 | [diff] [blame] | 423 | } // namespace trace_processor |
| 424 | } // namespace perfetto |
| 425 | |
Lalit Maganti | 737b376 | 2019-08-26 13:46:37 -0700 | [diff] [blame] | 426 | #endif // SRC_TRACE_PROCESSOR_SQLITE_SQLITE_TABLE_H_ |