xref: /aosp_15_r20/external/perfetto/src/trace_processor/sqlite/sqlite_engine.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2023 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 
17 #ifndef SRC_TRACE_PROCESSOR_SQLITE_SQLITE_ENGINE_H_
18 #define SRC_TRACE_PROCESSOR_SQLITE_SQLITE_ENGINE_H_
19 
20 #include <sqlite3.h>
21 #include <cstddef>
22 #include <cstdint>
23 #include <memory>
24 #include <optional>
25 #include <string>
26 #include <type_traits>
27 #include <utility>
28 
29 #include "perfetto/base/logging.h"
30 #include "perfetto/base/status.h"
31 #include "perfetto/ext/base/flat_hash_map.h"
32 #include "perfetto/ext/base/hash.h"
33 #include "src/trace_processor/sqlite/bindings/sqlite_module.h"
34 #include "src/trace_processor/sqlite/scoped_db.h"
35 #include "src/trace_processor/sqlite/sql_source.h"
36 
37 namespace perfetto::trace_processor {
38 
39 // Wrapper class around SQLite C API.
40 //
41 // The goal of this class is to provide a one-stop-shop mechanism to use SQLite.
42 // Benefits of this include:
43 // 1) It allows us to add code which intercepts registration of functions
44 //    and tables and keeps track of this for later lookup.
45 // 2) Allows easily auditing the SQLite APIs we use making it easy to determine
46 //    what functionality we rely on.
47 class SqliteEngine {
48  public:
49   using Fn = void(sqlite3_context* ctx, int argc, sqlite3_value** argv);
50   using AggregateFnStep = void(sqlite3_context* ctx,
51                                int argc,
52                                sqlite3_value** argv);
53   using AggregateFnFinal = void(sqlite3_context* ctx);
54   using WindowFnStep = void(sqlite3_context* ctx,
55                             int argc,
56                             sqlite3_value** argv);
57   using WindowFnInverse = void(sqlite3_context* ctx,
58                                int argc,
59                                sqlite3_value** argv);
60   using WindowFnValue = void(sqlite3_context* ctx);
61   using WindowFnFinal = void(sqlite3_context* ctx);
62   using FnCtxDestructor = void(void*);
63 
64   // Wrapper class for SQLite's |sqlite3_stmt| struct and associated functions.
65   struct PreparedStatement {
66    public:
67     bool Step();
68     bool IsDone() const;
69 
70     const char* original_sql() const;
71     const char* sql() const;
72 
statusPreparedStatement73     const base::Status& status() const { return status_; }
sqlite_stmtPreparedStatement74     sqlite3_stmt* sqlite_stmt() const { return stmt_.get(); }
75 
76    private:
77     friend class SqliteEngine;
78 
79     explicit PreparedStatement(ScopedStmt, SqlSource);
80 
81     ScopedStmt stmt_;
82     ScopedSqliteString expanded_sql_;
83     SqlSource sql_source_;
84     base::Status status_ = base::OkStatus();
85   };
86 
87   SqliteEngine();
88   ~SqliteEngine();
89 
90   SqliteEngine(SqliteEngine&&) noexcept = delete;
91   SqliteEngine& operator=(SqliteEngine&&) = delete;
92 
93   // Prepares a SQLite statement for the given SQL.
94   PreparedStatement PrepareStatement(SqlSource);
95 
96   // Registers a C++ function to be runnable from SQL.
97   base::Status RegisterFunction(const char* name,
98                                 int argc,
99                                 Fn* fn,
100                                 void* ctx,
101                                 FnCtxDestructor* ctx_destructor,
102                                 bool deterministic);
103 
104   // Registers a C++ aggregate function to be runnable from SQL.
105   base::Status RegisterAggregateFunction(const char* name,
106                                          int argc,
107                                          AggregateFnStep* step,
108                                          AggregateFnFinal* final,
109                                          void* ctx,
110                                          FnCtxDestructor* ctx_destructor,
111                                          bool deterministic);
112 
113   // Registers a C++ window function to be runnable from SQL.
114   base::Status RegisterWindowFunction(const char* name,
115                                       int argc,
116                                       WindowFnStep* step,
117                                       WindowFnInverse* inverse,
118                                       WindowFnValue* value,
119                                       WindowFnFinal* final,
120                                       void* ctx,
121                                       FnCtxDestructor* ctx_destructor,
122                                       bool deterministic);
123 
124   // Unregisters a C++ function from SQL.
125   base::Status UnregisterFunction(const char* name, int argc);
126 
127   // Registers a SQLite virtual table module with the given name.
128   template <typename Module>
129   void RegisterVirtualTableModule(const std::string& module_name,
130                                   typename Module::Context* ctx);
131 
132   // Registers a SQLite virtual table module with the given name.
133   template <typename Module>
134   void RegisterVirtualTableModule(const std::string& module_name,
135                                   std::unique_ptr<typename Module::Context>);
136 
137   // Declares a virtual table with SQLite.
138   base::Status DeclareVirtualTable(const std::string& create_stmt);
139 
140   // Gets the context for a registered SQL function.
141   void* GetFunctionContext(const std::string& name, int argc);
142 
db()143   sqlite3* db() const { return db_.get(); }
144 
145  private:
146   struct FnHasher {
operatorFnHasher147     size_t operator()(const std::pair<std::string, int>& x) const {
148       base::Hasher hasher;
149       hasher.Update(x.first);
150       hasher.Update(x.second);
151       return static_cast<size_t>(hasher.digest());
152     }
153   };
154 
155   std::optional<uint32_t> GetErrorOffset() const;
156 
157   base::FlatHashMap<std::pair<std::string, int>, void*, FnHasher> fn_ctx_;
158   ScopedDb db_;
159 };
160 
161 }  // namespace perfetto::trace_processor
162 
163 // The rest of this file is just implementation details which we need
164 // in the header file because it is templated code. We separate it out
165 // like this to keep the API people actually care about easy to read.
166 
167 namespace perfetto::trace_processor {
168 
169 template <typename Module>
RegisterVirtualTableModule(const std::string & module_name,typename Module::Context * ctx)170 void SqliteEngine::RegisterVirtualTableModule(const std::string& module_name,
171                                               typename Module::Context* ctx) {
172   static_assert(std::is_base_of_v<sqlite::Module<Module>, Module>,
173                 "Must subclass sqlite::Module");
174   int res = sqlite3_create_module_v2(db_.get(), module_name.c_str(),
175                                      &Module::kModule, ctx, nullptr);
176   PERFETTO_CHECK(res == SQLITE_OK);
177 }
178 
179 template <typename Module>
RegisterVirtualTableModule(const std::string & module_name,std::unique_ptr<typename Module::Context> ctx)180 void SqliteEngine::RegisterVirtualTableModule(
181     const std::string& module_name,
182     std::unique_ptr<typename Module::Context> ctx) {
183   static_assert(std::is_base_of_v<sqlite::Module<Module>, Module>,
184                 "Must subclass sqlite::Module");
185   int res = sqlite3_create_module_v2(
186       db_.get(), module_name.c_str(), &Module::kModule, ctx.release(),
187       [](void* arg) { delete static_cast<typename Module::Context*>(arg); });
188   PERFETTO_CHECK(res == SQLITE_OK);
189 }
190 
191 }  // namespace perfetto::trace_processor
192 
193 #endif  // SRC_TRACE_PROCESSOR_SQLITE_SQLITE_ENGINE_H_
194