1 /*
2 * Copyright (C) 2021 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 #include "src/trace_processor/sqlite/create_view_function.h"
18
19 #include <numeric>
20
21 #include "perfetto/base/status.h"
22 #include "perfetto/ext/base/string_utils.h"
23 #include "perfetto/ext/base/string_view.h"
24 #include "perfetto/trace_processor/basic_types.h"
25 #include "src/trace_processor/sqlite/create_function_internal.h"
26 #include "src/trace_processor/sqlite/scoped_db.h"
27 #include "src/trace_processor/sqlite/sqlite_table.h"
28 #include "src/trace_processor/sqlite/sqlite_utils.h"
29 #include "src/trace_processor/util/status_macros.h"
30
31 namespace perfetto {
32 namespace trace_processor {
33
34 namespace {
35
36 class CreatedViewFunction : public SqliteTable {
37 public:
38 class Cursor : public SqliteTable::Cursor {
39 public:
40 explicit Cursor(CreatedViewFunction* table);
41 ~Cursor() override;
42
43 int Filter(const QueryConstraints& qc,
44 sqlite3_value**,
45 FilterHistory) override;
46 int Next() override;
47 int Eof() override;
48 int Column(sqlite3_context* context, int N) override;
49
50 private:
51 sqlite3_stmt* stmt_ = nullptr;
52 CreatedViewFunction* table_ = nullptr;
53 bool is_eof_ = false;
54 };
55
56 CreatedViewFunction(sqlite3*, CreateViewFunction::State* state);
57 ~CreatedViewFunction() override;
58
59 base::Status Init(int argc, const char* const* argv, Schema*) override;
60 std::unique_ptr<SqliteTable::Cursor> CreateCursor() override;
61 int BestIndex(const QueryConstraints& qc, BestIndexInfo* info) override;
62
Register(sqlite3 * db,CreateViewFunction::State * state)63 static void Register(sqlite3* db, CreateViewFunction::State* state) {
64 SqliteTable::Register<CreatedViewFunction>(
65 db, state, "internal_view_function_impl", false, true);
66 }
67
68 private:
69 Schema CreateSchema();
70
71 sqlite3* db_ = nullptr;
72
73 Prototype prototype_;
74 std::vector<Prototype::Argument> return_values_;
75
76 std::string prototype_str_;
77 std::string sql_defn_str_;
78
79 CreateViewFunction::State* state_;
80 };
81
CreatedViewFunction(sqlite3 * db,CreateViewFunction::State * state)82 CreatedViewFunction::CreatedViewFunction(sqlite3* db,
83 CreateViewFunction::State* state)
84 : db_(db), state_(state) {}
85 CreatedViewFunction::~CreatedViewFunction() = default;
86
Init(int argc,const char * const * argv,Schema * schema)87 base::Status CreatedViewFunction::Init(int argc,
88 const char* const* argv,
89 Schema* schema) {
90 // The first three args are SQLite ones which we ignore.
91 PERFETTO_CHECK(argc == 6);
92
93 prototype_str_ = argv[3];
94 std::string return_prototype_str = argv[4];
95 sql_defn_str_ = argv[5];
96
97 // SQLite gives us strings with quotes included (i.e. 'string'). Strip these
98 // from the front and back.
99 prototype_str_ = prototype_str_.substr(1, prototype_str_.size() - 2);
100 return_prototype_str =
101 return_prototype_str.substr(1, return_prototype_str.size() - 2);
102 sql_defn_str_ = sql_defn_str_.substr(1, sql_defn_str_.size() - 2);
103
104 // Parse all the arguments into a more friendly form.
105 base::Status status =
106 ParsePrototype(base::StringView(prototype_str_), prototype_);
107 if (!status.ok()) {
108 return base::ErrStatus("CREATE_VIEW_FUNCTION[prototype=%s]: %s",
109 prototype_str_.c_str(), status.c_message());
110 }
111
112 // Parse the return type into a enum format.
113 status = ParseArgs(return_prototype_str, return_values_);
114 if (!status.ok()) {
115 return base::ErrStatus(
116 "CREATE_VIEW_FUNCTION[prototype=%s, return=%s]: unknown return type "
117 "specified",
118 prototype_str_.c_str(), return_prototype_str.c_str());
119 }
120
121 // Now we've parsed prototype and return values, create the schema.
122 *schema = CreateSchema();
123
124 return base::OkStatus();
125 }
126
CreateSchema()127 SqliteTable::Schema CreatedViewFunction::CreateSchema() {
128 std::vector<Column> columns;
129 for (size_t i = 0; i < return_values_.size(); ++i) {
130 const auto& ret = return_values_[i];
131 columns.push_back(Column(columns.size(), ret.name, ret.type, false));
132 }
133 for (size_t i = 0; i < prototype_.arguments.size(); ++i) {
134 const auto& arg = prototype_.arguments[i];
135 columns.push_back(Column(columns.size(), arg.name, arg.type, true));
136 }
137
138 std::vector<size_t> primary_keys(return_values_.size());
139 std::iota(primary_keys.begin(), primary_keys.end(), 0);
140
141 return SqliteTable::Schema(std::move(columns), std::move(primary_keys));
142 }
143
CreateCursor()144 std::unique_ptr<SqliteTable::Cursor> CreatedViewFunction::CreateCursor() {
145 return std::unique_ptr<Cursor>(new Cursor(this));
146 }
147
BestIndex(const QueryConstraints & qc,BestIndexInfo * info)148 int CreatedViewFunction::BestIndex(const QueryConstraints& qc,
149 BestIndexInfo* info) {
150 for (size_t i = 0; i < info->sqlite_omit_constraint.size(); ++i) {
151 size_t col = static_cast<size_t>(qc.constraints()[i].column);
152 if (schema().columns()[col].hidden()) {
153 info->sqlite_omit_constraint[i] = true;
154 }
155 }
156 return SQLITE_OK;
157 }
158
Cursor(CreatedViewFunction * table)159 CreatedViewFunction::Cursor::Cursor(CreatedViewFunction* table)
160 : SqliteTable::Cursor(table), table_(table) {}
161
162 CreatedViewFunction::Cursor::~Cursor() = default;
163
Filter(const QueryConstraints & qc,sqlite3_value ** argv,FilterHistory)164 int CreatedViewFunction::Cursor::Filter(const QueryConstraints& qc,
165 sqlite3_value** argv,
166 FilterHistory) {
167 auto col_to_arg_idx = [this](int col) {
168 return static_cast<size_t>(col) - table_->return_values_.size();
169 };
170
171 size_t seen_hidden_constraints = 0;
172 for (size_t i = 0; i < qc.constraints().size(); ++i) {
173 const auto& cs = qc.constraints()[i];
174
175 // Only consider hidden columns (i.e. input parameters) as we're delegating
176 // the rest to SQLite.
177 if (!table_->schema().columns()[static_cast<size_t>(cs.column)].hidden())
178 continue;
179
180 // We only support equality constraints as we're expecting "input arguments"
181 // to our "function".
182 if (!sqlite_utils::IsOpEq(cs.op)) {
183 table_->SetErrorMessage(
184 sqlite3_mprintf("%s: non-equality constraint passed",
185 table_->prototype_.function_name.c_str()));
186 return SQLITE_ERROR;
187 }
188
189 SqlValue::Type type =
190 sqlite_utils::SqliteTypeToSqlValueType(sqlite3_value_type(argv[i]));
191 if (type != table_->prototype_.arguments[col_to_arg_idx(cs.column)].type) {
192 table_->SetErrorMessage(
193 sqlite3_mprintf("%s: type of input argument does not match",
194 table_->prototype_.function_name.c_str()));
195 return SQLITE_ERROR;
196 }
197
198 seen_hidden_constraints++;
199 }
200
201 // Verify that we saw one valid constriant for every input argument.
202 if (seen_hidden_constraints < table_->prototype_.arguments.size()) {
203 table_->SetErrorMessage(
204 sqlite3_mprintf("%s: missing value for input argument",
205 table_->prototype_.function_name.c_str()));
206 return SQLITE_ERROR;
207 }
208
209 // Prepare the SQL definition as a statement using SQLite.
210 // TODO(lalitm): see if we can reuse this prepared statement rather than
211 // creating it very time.
212 // TODO(lalitm): measure and implement whether it would be a good idea to
213 // forward constraints here when we build the nested query.
214 ScopedStmt stmt;
215 int ret = sqlite3_prepare_v2(table_->db_, table_->sql_defn_str_.data(),
216 static_cast<int>(table_->sql_defn_str_.size()),
217 &stmt_, nullptr);
218 stmt.reset(stmt_);
219 if (ret != SQLITE_OK) {
220 table_->SetErrorMessage(sqlite3_mprintf(
221 "%s: SQLite error when preparing statement %s",
222 table_->prototype_.function_name.c_str(), sqlite3_errmsg(table_->db_)));
223 return SQLITE_ERROR;
224 }
225
226 // Bind all the arguments to the appropriate places in the function.
227 for (size_t i = 0; i < qc.constraints().size(); ++i) {
228 const auto& cs = qc.constraints()[i];
229 const auto& arg = table_->prototype_.arguments[col_to_arg_idx(cs.column)];
230 auto status = MaybeBindArgument(stmt_, table_->prototype_.function_name,
231 arg, argv[i]);
232 if (!status.ok()) {
233 table_->SetErrorMessage(sqlite3_mprintf("%s", status.c_message()));
234 return SQLITE_ERROR;
235 }
236 }
237
238 ret = Next();
239 if (ret != SQLITE_OK)
240 return ret;
241
242 // Keep track of the scoped statements in the stmts vector so we can clean
243 // all these up before destroying trace processor.
244 table_->state_->erase(table_->prototype_.function_name);
245 table_->state_->emplace(table_->prototype_.function_name, std::move(stmt));
246
247 return SQLITE_OK;
248 }
249
Next()250 int CreatedViewFunction::Cursor::Next() {
251 int ret = sqlite3_step(stmt_);
252 is_eof_ = ret == SQLITE_DONE;
253 if (ret != SQLITE_ROW && ret != SQLITE_DONE) {
254 table_->SetErrorMessage(sqlite3_mprintf(
255 "%s: SQLite error while stepping statement: %s",
256 table_->prototype_.function_name.c_str(), sqlite3_errmsg(table_->db_)));
257 return ret;
258 }
259 return SQLITE_OK;
260 }
261
Eof()262 int CreatedViewFunction::Cursor::Eof() {
263 return is_eof_;
264 }
265
Column(sqlite3_context * ctx,int i)266 int CreatedViewFunction::Cursor::Column(sqlite3_context* ctx, int i) {
267 size_t idx = static_cast<size_t>(i);
268 if (idx < table_->return_values_.size()) {
269 sqlite3_result_value(ctx, sqlite3_column_value(stmt_, i));
270 } else {
271 sqlite3_result_null(ctx);
272 }
273 return SQLITE_OK;
274 }
275
276 } // namespace
277
Run(CreateViewFunction::Context * ctx,size_t argc,sqlite3_value ** argv,SqlValue &,Destructors &)278 base::Status CreateViewFunction::Run(CreateViewFunction::Context* ctx,
279 size_t argc,
280 sqlite3_value** argv,
281 SqlValue&,
282 Destructors&) {
283 if (argc != 3) {
284 return base::ErrStatus(
285 "CREATE_VIEW_FUNCTION: invalid number of args; expected %u, received "
286 "%zu",
287 3u, argc);
288 }
289
290 sqlite3_value* prototype_value = argv[0];
291 sqlite3_value* return_prototype_value = argv[1];
292 sqlite3_value* sql_defn_value = argv[2];
293
294 // Type check all the arguments.
295 {
296 auto type_check = [prototype_value](sqlite3_value* value,
297 SqlValue::Type type, const char* desc) {
298 base::Status status = TypeCheckSqliteValue(value, type);
299 if (!status.ok()) {
300 return base::ErrStatus("CREATE_VIEW_FUNCTION[prototype=%s]: %s %s",
301 sqlite3_value_text(prototype_value), desc,
302 status.c_message());
303 }
304 return base::OkStatus();
305 };
306
307 RETURN_IF_ERROR(type_check(prototype_value, SqlValue::Type::kString,
308 "function prototype (first argument)"));
309 RETURN_IF_ERROR(type_check(return_prototype_value, SqlValue::Type::kString,
310 "return prototype (second argument)"));
311 RETURN_IF_ERROR(type_check(sql_defn_value, SqlValue::Type::kString,
312 "SQL definition (third argument)"));
313 }
314
315 // Extract the arguments from the value wrappers.
316 auto extract_string = [](sqlite3_value* value) -> const char* {
317 return reinterpret_cast<const char*>(sqlite3_value_text(value));
318 };
319 const char* prototype_str = extract_string(prototype_value);
320 const char* return_prototype_str = extract_string(return_prototype_value);
321 const char* sql_defn_str = extract_string(sql_defn_value);
322
323 base::StringView function_name;
324 RETURN_IF_ERROR(ParseFunctionName(prototype_str, function_name));
325
326 base::StackString<1024> sql(
327 "CREATE OR REPLACE VIRTUAL TABLE %s USING "
328 "INTERNAL_VIEW_FUNCTION_IMPL('%s', '%s', '%s');",
329 function_name.ToStdString().c_str(), prototype_str, return_prototype_str,
330 sql_defn_str);
331
332 ScopedSqliteString errmsg;
333 char* errmsg_raw = nullptr;
334 int ret = sqlite3_exec(ctx->db, sql.c_str(), nullptr, nullptr, &errmsg_raw);
335 errmsg.reset(errmsg_raw);
336 if (ret != SQLITE_OK)
337 return base::ErrStatus("%s", errmsg.get());
338
339 // CREATE_VIEW_FUNCTION doesn't have a return value so just don't sent |out|.
340 return base::OkStatus();
341 }
342
RegisterTable(sqlite3 * db,CreateViewFunction::State * state)343 void CreateViewFunction::RegisterTable(sqlite3* db,
344 CreateViewFunction::State* state) {
345 CreatedViewFunction::Register(db, state);
346 }
347
348 } // namespace trace_processor
349 } // namespace perfetto
350