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 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
18
19 #include <algorithm>
20 #include <array>
21 #include <cctype>
22 #include <cstddef>
23 #include <cstdint>
24 #include <cstring>
25 #include <memory>
26 #include <optional>
27 #include <string>
28 #include <string_view>
29 #include <utility>
30 #include <variant>
31 #include <vector>
32
33 #include "perfetto/base/logging.h"
34 #include "perfetto/base/status.h"
35 #include "perfetto/ext/base/flat_hash_map.h"
36 #include "perfetto/ext/base/status_or.h"
37 #include "perfetto/ext/base/string_utils.h"
38 #include "perfetto/ext/base/string_view.h"
39 #include "src/trace_processor/containers/string_pool.h"
40 #include "src/trace_processor/db/runtime_table.h"
41 #include "src/trace_processor/db/table.h"
42 #include "src/trace_processor/perfetto_sql/engine/created_function.h"
43 #include "src/trace_processor/perfetto_sql/engine/function_util.h"
44 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_parser.h"
45 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_preprocessor.h"
46 #include "src/trace_processor/perfetto_sql/engine/runtime_table_function.h"
47 #include "src/trace_processor/perfetto_sql/intrinsics/table_functions/static_table_function.h"
48 #include "src/trace_processor/sqlite/db_sqlite_table.h"
49 #include "src/trace_processor/sqlite/scoped_db.h"
50 #include "src/trace_processor/sqlite/sql_source.h"
51 #include "src/trace_processor/sqlite/sqlite_engine.h"
52 #include "src/trace_processor/tp_metatrace.h"
53 #include "src/trace_processor/util/sql_argument.h"
54 #include "src/trace_processor/util/sql_modules.h"
55 #include "src/trace_processor/util/status_macros.h"
56
57 #include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
58
59 // Implementation details
60 // ----------------------
61 //
62 // The execution of PerfettoSQL statements is the joint responsibility of
63 // several classes which all are linked together in the following way:
64 //
65 // PerfettoSqlEngine -> PerfettoSqlParser -> PerfettoSqlPreprocessor
66 //
67 // The responsibility of each of these classes is as follows:
68 //
69 // * PerfettoSqlEngine: this class is responsible for the end-to-end processing
70 // of statements. It calls into PerfettoSqlParser to incrementally receive
71 // parsed SQL statements and then executes them. If the statement is a
72 // PerfettoSQL-only statement, the execution happens entirely in this class.
73 // Otherwise, if the statement is a valid SQLite statement, SQLite is called
74 // into to perform the execution.
75 // * PerfettoSqlParser: this class is responsible for taking a chunk of SQL and
76 // incrementally converting them into parsed SQL statement. The parser calls
77 // into the PerfettoSqlPreprocessor to split the SQL chunk into a statement
78 // and perform any macro expansion. It then tries to parse any
79 // PerfettoSQL-only statements into their component parts and leaves SQLite
80 // statements as-is for execution by SQLite.
81 // * PerfettoSqlPreprocessor: this class is responsible for taking a chunk of
82 // SQL and breaking them into statements, while also expanding any macros
83 // which might be present inside.
84 namespace perfetto::trace_processor {
85 namespace {
86
IncrementCountForStmt(const SqliteEngine::PreparedStatement & p_stmt,PerfettoSqlEngine::ExecutionStats * res)87 void IncrementCountForStmt(const SqliteEngine::PreparedStatement& p_stmt,
88 PerfettoSqlEngine::ExecutionStats* res) {
89 res->statement_count++;
90
91 // If the stmt is already done, it clearly didn't have any output.
92 if (p_stmt.IsDone())
93 return;
94
95 sqlite3_stmt* stmt = p_stmt.sqlite_stmt();
96 if (sqlite3_column_count(stmt) == 1) {
97 sqlite3_value* value = sqlite3_column_value(stmt, 0);
98
99 // If the "VOID" pointer associated to the return value is not null,
100 // that means this is a function which is forced to return a value
101 // (because all functions in SQLite have to) but doesn't actually
102 // wait to (i.e. it wants to be treated like CREATE TABLE or similar).
103 // Because of this, ignore the return value of this function.
104 // See |WrapSqlFunction| for where this is set.
105 if (sqlite3_value_pointer(value, "VOID") != nullptr) {
106 return;
107 }
108
109 // If the statement only has a single column and that column is named
110 // "suppress_query_output", treat it as a statement without output for
111 // accounting purposes. This allows an escape hatch for cases where the
112 // user explicitly wants to ignore functions as having output.
113 if (strcmp(sqlite3_column_name(stmt, 0), "suppress_query_output") == 0) {
114 return;
115 }
116 }
117
118 // Otherwise, the statement has output and so increment the count.
119 res->statement_count_with_output++;
120 }
121
AddTracebackIfNeeded(base::Status status,const SqlSource & source)122 base::Status AddTracebackIfNeeded(base::Status status,
123 const SqlSource& source) {
124 if (status.ok()) {
125 return status;
126 }
127 if (status.GetPayload("perfetto.dev/has_traceback") == "true") {
128 return status;
129 }
130 // Since the error is with the statement as a whole, just pass zero so the
131 // traceback points to the start of the statement.
132 std::string traceback = source.AsTraceback(0);
133 status = base::ErrStatus("%s%s", traceback.c_str(), status.c_message());
134 status.SetPayload("perfetto.dev/has_traceback", "true");
135 return status;
136 }
137
138 // This function is used when the PerfettoSQL has been fully executed by the
139 // PerfettoSqlEngine and a SqlSoruce is needed for SQLite to execute.
RewriteToDummySql(const SqlSource & source)140 SqlSource RewriteToDummySql(const SqlSource& source) {
141 return source.RewriteAllIgnoreExisting(
142 SqlSource::FromTraceProcessorImplementation("SELECT 0 WHERE 0"));
143 }
144
145 constexpr std::array<const char*, 3> kTokensAllowedInMacro({
146 "ColumnName",
147 "Expr",
148 "TableOrSubquery",
149 });
150
IsTokenAllowedInMacro(const std::string & view)151 bool IsTokenAllowedInMacro(const std::string& view) {
152 std::string lower = base::ToLower(view);
153 return std::any_of(kTokensAllowedInMacro.begin(), kTokensAllowedInMacro.end(),
154 [&lower](const std::string& allowed_token) {
155 return lower == base::ToLower(allowed_token);
156 });
157 }
158
GetTokenNamesAllowedInMacro()159 std::string GetTokenNamesAllowedInMacro() {
160 std::vector<std::string> result;
161 result.reserve(kTokensAllowedInMacro.size());
162 for (const char* token : kTokensAllowedInMacro) {
163 result.emplace_back(token);
164 }
165 return base::Join(result, ", ");
166 }
167
168 } // namespace
169
PerfettoSqlEngine(StringPool * pool)170 PerfettoSqlEngine::PerfettoSqlEngine(StringPool* pool)
171 : pool_(pool), engine_(new SqliteEngine()) {
172 // Initialize `perfetto_tables` table, which will contain the names of all of
173 // the registered tables.
174 char* errmsg_raw = nullptr;
175 int err =
176 sqlite3_exec(engine_->db(), "CREATE TABLE perfetto_tables(name STRING);",
177 nullptr, nullptr, &errmsg_raw);
178 ScopedSqliteString errmsg(errmsg_raw);
179 if (err != SQLITE_OK) {
180 PERFETTO_FATAL("Failed to initialize perfetto_tables: %s", errmsg_raw);
181 }
182
183 {
184 auto ctx = std::make_unique<RuntimeTableFunctionModule::Context>();
185 runtime_table_fn_context_ = ctx.get();
186 engine_->RegisterVirtualTableModule<RuntimeTableFunctionModule>(
187 "runtime_table_function", std::move(ctx));
188 }
189 {
190 auto ctx = std::make_unique<DbSqliteModule::Context>();
191 runtime_table_context_ = ctx.get();
192 engine_->RegisterVirtualTableModule<DbSqliteModule>("runtime_table",
193 std::move(ctx));
194 }
195 {
196 auto ctx = std::make_unique<DbSqliteModule::Context>();
197 static_table_context_ = ctx.get();
198 engine_->RegisterVirtualTableModule<DbSqliteModule>("static_table",
199 std::move(ctx));
200 }
201 {
202 auto ctx = std::make_unique<DbSqliteModule::Context>();
203 static_table_fn_context_ = ctx.get();
204 engine_->RegisterVirtualTableModule<DbSqliteModule>("static_table_function",
205 std::move(ctx));
206 }
207 }
208
RegisterStaticTable(const Table & table,const std::string & table_name,Table::Schema schema)209 void PerfettoSqlEngine::RegisterStaticTable(const Table& table,
210 const std::string& table_name,
211 Table::Schema schema) {
212 // Make sure we didn't accidentally leak a state from a previous table
213 // creation.
214 PERFETTO_CHECK(!static_table_context_->temporary_create_state);
215 static_table_context_->temporary_create_state =
216 std::make_unique<DbSqliteModule::State>(&table, std::move(schema));
217
218 base::StackString<1024> sql(
219 R"(
220 CREATE VIRTUAL TABLE %s USING static_table;
221 INSERT INTO perfetto_tables(name) VALUES('%s');
222 )",
223 table_name.c_str(), table_name.c_str());
224 auto status =
225 Execute(SqlSource::FromTraceProcessorImplementation(sql.ToStdString()));
226 if (!status.ok()) {
227 PERFETTO_FATAL("%s", status.status().c_message());
228 }
229
230 PERFETTO_CHECK(!static_table_context_->temporary_create_state);
231 }
232
RegisterStaticTableFunction(std::unique_ptr<StaticTableFunction> fn)233 void PerfettoSqlEngine::RegisterStaticTableFunction(
234 std::unique_ptr<StaticTableFunction> fn) {
235 std::string name = fn->TableName();
236
237 // Make sure we didn't accidentally leak a state from a previous table
238 // creation.
239 PERFETTO_CHECK(!static_table_fn_context_->temporary_create_state);
240 static_table_fn_context_->temporary_create_state =
241 std::make_unique<DbSqliteModule::State>(std::move(fn));
242
243 base::StackString<1024> sql(
244 "CREATE VIRTUAL TABLE %s USING static_table_function;", name.c_str());
245 auto status =
246 Execute(SqlSource::FromTraceProcessorImplementation(sql.ToStdString()));
247 if (!status.ok()) {
248 PERFETTO_FATAL("%s", status.status().c_message());
249 }
250
251 PERFETTO_CHECK(!static_table_fn_context_->temporary_create_state);
252 }
253
Execute(SqlSource sql)254 base::StatusOr<PerfettoSqlEngine::ExecutionStats> PerfettoSqlEngine::Execute(
255 SqlSource sql) {
256 auto res = ExecuteUntilLastStatement(std::move(sql));
257 RETURN_IF_ERROR(res.status());
258 if (res->stmt.IsDone()) {
259 return res->stats;
260 }
261 while (res->stmt.Step()) {
262 }
263 RETURN_IF_ERROR(res->stmt.status());
264 return res->stats;
265 }
266
267 base::StatusOr<PerfettoSqlEngine::ExecutionResult>
ExecuteUntilLastStatement(SqlSource sql_source)268 PerfettoSqlEngine::ExecuteUntilLastStatement(SqlSource sql_source) {
269 // A SQL string can contain several statements. Some of them might be comment
270 // only, e.g. "SELECT 1; /* comment */; SELECT 2;". Some statements can also
271 // be PerfettoSQL statements which we need to transpile before execution or
272 // execute without delegating to SQLite.
273 //
274 // The logic here is the following:
275 // - We parse the statement as a PerfettoSQL statement.
276 // - If the statement is something we can execute, execute it instantly and
277 // prepare a dummy SQLite statement so the rest of the code continues to
278 // work correctly.
279 // - If the statement is actually an SQLite statement, we invoke PrepareStmt.
280 // - We step once to make sure side effects take effect (e.g. for CREATE
281 // TABLE statements, tables are created).
282 // - If we encounter a valid statement afterwards, we step internally through
283 // all rows of the previous one. This ensures that any further side effects
284 // take hold *before* we step into the next statement.
285 // - Once no further statements are encountered, we return the prepared
286 // statement for the last valid statement.
287 std::optional<SqliteEngine::PreparedStatement> res;
288 ExecutionStats stats;
289 PerfettoSqlParser parser(std::move(sql_source), macros_);
290 while (parser.Next()) {
291 std::optional<SqlSource> source;
292 if (auto* cf = std::get_if<PerfettoSqlParser::CreateFunction>(
293 &parser.statement())) {
294 RETURN_IF_ERROR(AddTracebackIfNeeded(ExecuteCreateFunction(*cf),
295 parser.statement_sql()));
296 source = RewriteToDummySql(parser.statement_sql());
297 } else if (auto* cst = std::get_if<PerfettoSqlParser::CreateTable>(
298 &parser.statement())) {
299 RETURN_IF_ERROR(AddTracebackIfNeeded(ExecuteCreateTable(*cst),
300 parser.statement_sql()));
301 source = RewriteToDummySql(parser.statement_sql());
302 } else if (auto* create_view = std::get_if<PerfettoSqlParser::CreateView>(
303 &parser.statement())) {
304 RETURN_IF_ERROR(AddTracebackIfNeeded(ExecuteCreateView(*create_view),
305 parser.statement_sql()));
306 source = RewriteToDummySql(parser.statement_sql());
307 } else if (auto* include = std::get_if<PerfettoSqlParser::Include>(
308 &parser.statement())) {
309 RETURN_IF_ERROR(ExecuteInclude(*include, parser));
310 source = RewriteToDummySql(parser.statement_sql());
311 } else if (auto* macro = std::get_if<PerfettoSqlParser::CreateMacro>(
312 &parser.statement())) {
313 auto sql = macro->sql;
314 RETURN_IF_ERROR(ExecuteCreateMacro(*macro));
315 source = RewriteToDummySql(sql);
316 } else {
317 // If none of the above matched, this must just be an SQL statement
318 // directly executable by SQLite.
319 auto* sql =
320 std::get_if<PerfettoSqlParser::SqliteSql>(&parser.statement());
321 PERFETTO_CHECK(sql);
322 source = parser.statement_sql();
323 }
324
325 // Try to get SQLite to prepare the statement.
326 std::optional<SqliteEngine::PreparedStatement> cur_stmt;
327 {
328 PERFETTO_TP_TRACE(metatrace::Category::QUERY_TIMELINE, "QUERY_PREPARE");
329 auto stmt = engine_->PrepareStatement(std::move(*source));
330 RETURN_IF_ERROR(stmt.status());
331 cur_stmt = std::move(stmt);
332 }
333
334 // The only situation where we'd have an ok status but also no prepared
335 // statement is if the SQL was a pure comment. However, the PerfettoSQL
336 // parser should filter out such statements so this should never happen.
337 PERFETTO_DCHECK(cur_stmt->sqlite_stmt());
338
339 // Before stepping into |cur_stmt|, we need to finish iterating through
340 // the previous statement so we don't have two clashing statements (e.g.
341 // SELECT * FROM v and DROP VIEW v) partially stepped into.
342 if (res && !res->IsDone()) {
343 PERFETTO_TP_TRACE(metatrace::Category::QUERY_TIMELINE,
344 "STMT_STEP_UNTIL_DONE",
345 [&res](metatrace::Record* record) {
346 record->AddArg("Original SQL", res->original_sql());
347 record->AddArg("Executed SQL", res->sql());
348 });
349 while (res->Step()) {
350 }
351 RETURN_IF_ERROR(res->status());
352 }
353
354 // Propogate the current statement to the next iteration.
355 res = std::move(cur_stmt);
356
357 // Step the newly prepared statement once. This is considered to be
358 // "executing" the statement.
359 {
360 PERFETTO_TP_TRACE(metatrace::Category::QUERY_TIMELINE, "STMT_FIRST_STEP",
361 [&res](metatrace::Record* record) {
362 record->AddArg("Original SQL", res->original_sql());
363 record->AddArg("Executed SQL", res->sql());
364 });
365 PERFETTO_DLOG("Executing statement");
366 PERFETTO_DLOG("Original SQL: %s", res->original_sql());
367 PERFETTO_DLOG("Executed SQL: %s", res->sql());
368 res->Step();
369 RETURN_IF_ERROR(res->status());
370 }
371
372 // Increment the neecessary counts for the statement.
373 IncrementCountForStmt(*res, &stats);
374 }
375 RETURN_IF_ERROR(parser.status());
376
377 // If we didn't manage to prepare a single statement, that means everything
378 // in the SQL was treated as a comment.
379 if (!res)
380 return base::ErrStatus("No valid SQL to run");
381
382 // Update the output statement and column count.
383 stats.column_count =
384 static_cast<uint32_t>(sqlite3_column_count(res->sqlite_stmt()));
385 return ExecutionResult{std::move(*res), stats};
386 }
387
RegisterRuntimeFunction(bool replace,const FunctionPrototype & prototype,const std::string & return_type_str,SqlSource sql)388 base::Status PerfettoSqlEngine::RegisterRuntimeFunction(
389 bool replace,
390 const FunctionPrototype& prototype,
391 const std::string& return_type_str,
392 SqlSource sql) {
393 // Parse the return type into a enum format.
394 auto opt_return_type =
395 sql_argument::ParseType(base::StringView(return_type_str));
396 if (!opt_return_type) {
397 return base::ErrStatus(
398 "CREATE PERFETTO FUNCTION[prototype=%s, return=%s]: unknown return "
399 "type specified",
400 prototype.ToString().c_str(), return_type_str.c_str());
401 }
402
403 int created_argc = static_cast<int>(prototype.arguments.size());
404 auto* ctx = static_cast<CreatedFunction::Context*>(
405 sqlite_engine()->GetFunctionContext(prototype.function_name,
406 created_argc));
407 if (ctx) {
408 if (CreatedFunction::IsValid(ctx) && !replace) {
409 return base::ErrStatus(
410 "CREATE PERFETTO FUNCTION[prototype=%s]: function already exists",
411 prototype.ToString().c_str());
412 }
413 CreatedFunction::Reset(ctx, this);
414 } else {
415 // We register the function with SQLite before we prepare the statement so
416 // the statement can reference the function itself, enabling recursive
417 // calls.
418 std::unique_ptr<CreatedFunction::Context> created_fn_ctx =
419 CreatedFunction::MakeContext(this);
420 ctx = created_fn_ctx.get();
421 RETURN_IF_ERROR(RegisterFunctionWithSqlite<CreatedFunction>(
422 prototype.function_name.c_str(), created_argc,
423 std::move(created_fn_ctx)));
424 runtime_function_count_++;
425 }
426 return CreatedFunction::Prepare(ctx, prototype, *opt_return_type,
427 std::move(sql));
428 }
429
ExecuteCreateTable(const PerfettoSqlParser::CreateTable & create_table)430 base::Status PerfettoSqlEngine::ExecuteCreateTable(
431 const PerfettoSqlParser::CreateTable& create_table) {
432 PERFETTO_TP_TRACE(metatrace::Category::QUERY_TIMELINE,
433 "CREATE_PERFETTO_TABLE",
434 [&create_table](metatrace::Record* record) {
435 record->AddArg("Table", create_table.name);
436 });
437 auto stmt_or = engine_->PrepareStatement(create_table.sql);
438 RETURN_IF_ERROR(stmt_or.status());
439 SqliteEngine::PreparedStatement stmt = std::move(stmt_or);
440
441 base::StatusOr<std::vector<std::string>> maybe_column_names =
442 GetColumnNamesFromSelectStatement(stmt, "CREATE PERFETTO TABLE");
443 RETURN_IF_ERROR(maybe_column_names.status());
444 std::vector<std::string> column_names = *maybe_column_names;
445
446 RETURN_IF_ERROR(ValidateColumnNames(column_names, create_table.schema,
447 "CREATE PERFETTO TABLE"));
448
449 size_t column_count = column_names.size();
450 RuntimeTable::Builder builder(pool_, std::move(column_names));
451 uint32_t rows = 0;
452 int res;
453 for (res = sqlite3_step(stmt.sqlite_stmt()); res == SQLITE_ROW;
454 ++rows, res = sqlite3_step(stmt.sqlite_stmt())) {
455 for (uint32_t i = 0; i < column_count; ++i) {
456 int int_i = static_cast<int>(i);
457 switch (sqlite3_column_type(stmt.sqlite_stmt(), int_i)) {
458 case SQLITE_NULL:
459 RETURN_IF_ERROR(builder.AddNull(i));
460 break;
461 case SQLITE_INTEGER:
462 RETURN_IF_ERROR(builder.AddInteger(
463 i, sqlite3_column_int64(stmt.sqlite_stmt(), int_i)));
464 break;
465 case SQLITE_FLOAT:
466 RETURN_IF_ERROR(builder.AddFloat(
467 i, sqlite3_column_double(stmt.sqlite_stmt(), int_i)));
468 break;
469 case SQLITE_TEXT: {
470 RETURN_IF_ERROR(builder.AddText(
471 i, reinterpret_cast<const char*>(
472 sqlite3_column_text(stmt.sqlite_stmt(), int_i))));
473 break;
474 }
475 case SQLITE_BLOB:
476 return base::ErrStatus(
477 "CREATE PERFETTO TABLE on column '%s' in table '%s': bytes "
478 "columns are not supported",
479 sqlite3_column_name(stmt.sqlite_stmt(), int_i),
480 create_table.name.c_str());
481 }
482 }
483 }
484 if (res != SQLITE_DONE) {
485 return base::ErrStatus("%s: SQLite error while creating table body: %s",
486 create_table.name.c_str(),
487 sqlite3_errmsg(engine_->db()));
488 }
489 ASSIGN_OR_RETURN(auto table, std::move(builder).Build(rows));
490
491 // TODO(lalitm): unfortunately, in the (very unlikely) event that there is a
492 // sqlite3_interrupt call between the DROP and CREATE, we can end up with the
493 // non-atomic query execution. Fixing this is extremely difficult as it
494 // involves telling SQLite that we want the drop/create to be atomic.
495 //
496 // We would need to do with the transaction API but given we have no usage of
497 // this until now, investigating that needs some proper work.
498 if (create_table.replace) {
499 base::StackString<1024> drop("DROP TABLE IF EXISTS %s",
500 create_table.name.c_str());
501 auto drop_res = Execute(
502 SqlSource::FromTraceProcessorImplementation(drop.ToStdString()));
503 RETURN_IF_ERROR(drop_res.status());
504 }
505
506 base::StackString<1024> create("CREATE VIRTUAL TABLE %s USING runtime_table",
507 create_table.name.c_str());
508
509 // Make sure we didn't accidentally leak a state from a previous function
510 // creation.
511 PERFETTO_CHECK(!runtime_table_context_->temporary_create_state);
512
513 // Move the state into the context so that it will be picked up in xCreate
514 // of RuntimeTableFunctionModule.
515 runtime_table_context_->temporary_create_state =
516 std::make_unique<DbSqliteModule::State>(std::move(table));
517 auto status =
518 Execute(SqlSource::FromTraceProcessorImplementation(create.ToStdString()))
519 .status();
520
521 // If an error happened, it's possible that the state was not picked up.
522 // Therefore, always reset the state just in case. OTOH if the creation
523 // succeeded, the state should always have been captured.
524 if (status.ok()) {
525 PERFETTO_CHECK(!runtime_table_context_->temporary_create_state);
526 } else {
527 runtime_table_context_->temporary_create_state.reset();
528 }
529 return status;
530 }
531
ExecuteCreateView(const PerfettoSqlParser::CreateView & create_view)532 base::Status PerfettoSqlEngine::ExecuteCreateView(
533 const PerfettoSqlParser::CreateView& create_view) {
534 // Verify that the underlying SQL statement is valid.
535 auto stmt = sqlite_engine()->PrepareStatement(create_view.select_sql);
536 RETURN_IF_ERROR(stmt.status());
537
538 if (create_view.replace) {
539 base::StackString<1024> drop_if_exists("DROP VIEW IF EXISTS %s",
540 create_view.name.c_str());
541 RETURN_IF_ERROR(Execute(SqlSource::FromTraceProcessorImplementation(
542 drop_if_exists.ToStdString()))
543 .status());
544 }
545
546 // If the schema is specified, verify that the column names match it.
547 if (!create_view.schema.empty()) {
548 base::StatusOr<std::vector<std::string>> maybe_column_names =
549 GetColumnNamesFromSelectStatement(stmt, "CREATE PERFETTO VIEW");
550 RETURN_IF_ERROR(maybe_column_names.status());
551 std::vector<std::string> column_names = *maybe_column_names;
552
553 RETURN_IF_ERROR(ValidateColumnNames(column_names, create_view.schema,
554 "CREATE PERFETTO VIEW"));
555 }
556
557 RETURN_IF_ERROR(Execute(create_view.create_view_sql).status());
558 return base::OkStatus();
559 }
560
EnableSqlFunctionMemoization(const std::string & name)561 base::Status PerfettoSqlEngine::EnableSqlFunctionMemoization(
562 const std::string& name) {
563 constexpr size_t kSupportedArgCount = 1;
564 auto* ctx = static_cast<CreatedFunction::Context*>(
565 sqlite_engine()->GetFunctionContext(name, kSupportedArgCount));
566 if (!ctx) {
567 return base::ErrStatus(
568 "EXPERIMENTAL_MEMOIZE: Function %s(INT) does not exist", name.c_str());
569 }
570 return CreatedFunction::EnableMemoization(ctx);
571 }
572
ExecuteInclude(const PerfettoSqlParser::Include & include,const PerfettoSqlParser & parser)573 base::Status PerfettoSqlEngine::ExecuteInclude(
574 const PerfettoSqlParser::Include& include,
575 const PerfettoSqlParser& parser) {
576 std::string key = include.key;
577 PERFETTO_TP_TRACE(metatrace::Category::QUERY_TIMELINE, "Include",
578 [key](metatrace::Record* r) { r->AddArg("Module", key); });
579
580 if (key == "*") {
581 for (auto moduleIt = modules_.GetIterator(); moduleIt; ++moduleIt) {
582 RETURN_IF_ERROR(IncludeModuleImpl(moduleIt.value(), key, parser));
583 }
584 return base::OkStatus();
585 }
586
587 std::string module_name = sql_modules::GetModuleName(key);
588 auto* module = FindModule(module_name);
589 if (!module) {
590 return base::ErrStatus("INCLUDE: Unknown module name provided - %s",
591 key.c_str());
592 }
593 return IncludeModuleImpl(*module, key, parser);
594 }
595
IncludeModuleImpl(sql_modules::RegisteredModule & module,const std::string & key,const PerfettoSqlParser & parser)596 base::Status PerfettoSqlEngine::IncludeModuleImpl(
597 sql_modules::RegisteredModule& module,
598 const std::string& key,
599 const PerfettoSqlParser& parser) {
600 if (!key.empty() && key.back() == '*') {
601 // If the key ends with a wildcard, iterate through all the keys in the
602 // module and include matching ones.
603 std::string prefix = key.substr(0, key.size() - 1);
604 for (auto fileIt = module.include_key_to_file.GetIterator(); fileIt;
605 ++fileIt) {
606 if (!base::StartsWith(fileIt.key(), prefix))
607 continue;
608 PERFETTO_TP_TRACE(
609 metatrace::Category::QUERY_TIMELINE,
610 "Include (expanded from wildcard)",
611 [&](metatrace::Record* r) { r->AddArg("Module", fileIt.key()); });
612 RETURN_IF_ERROR(IncludeFileImpl(fileIt.value(), fileIt.key(), parser));
613 }
614 return base::OkStatus();
615 }
616 auto* module_file = module.include_key_to_file.Find(key);
617 if (!module_file) {
618 return base::ErrStatus("INCLUDE: unknown module '%s'", key.c_str());
619 }
620 return IncludeFileImpl(*module_file, key, parser);
621 }
622
IncludeFileImpl(sql_modules::RegisteredModule::ModuleFile & file,const std::string & key,const PerfettoSqlParser & parser)623 base::Status PerfettoSqlEngine::IncludeFileImpl(
624 sql_modules::RegisteredModule::ModuleFile& file,
625 const std::string& key,
626 const PerfettoSqlParser& parser) {
627 // INCLUDE is noop for already included files.
628 if (file.included) {
629 return base::OkStatus();
630 }
631
632 auto it = Execute(SqlSource::FromModuleInclude(file.sql, key));
633 if (!it.status().ok()) {
634 return base::ErrStatus("%s%s",
635 parser.statement_sql().AsTraceback(0).c_str(),
636 it.status().c_message());
637 }
638 if (it->statement_count_with_output > 0)
639 return base::ErrStatus("INCLUDE: Included module returning values.");
640 file.included = true;
641 return base::OkStatus();
642 }
643
ExecuteCreateFunction(const PerfettoSqlParser::CreateFunction & cf)644 base::Status PerfettoSqlEngine::ExecuteCreateFunction(
645 const PerfettoSqlParser::CreateFunction& cf) {
646 if (!cf.is_table) {
647 return RegisterRuntimeFunction(cf.replace, cf.prototype, cf.returns,
648 cf.sql);
649 }
650
651 auto state = std::make_unique<RuntimeTableFunctionModule::State>(
652 RuntimeTableFunctionModule::State{
653 this, cf.sql, cf.prototype, {}, std::nullopt});
654
655 // Parse the return type into a enum format.
656 {
657 base::Status status = sql_argument::ParseArgumentDefinitions(
658 cf.returns, state->return_values);
659 if (!status.ok()) {
660 return base::ErrStatus(
661 "CREATE PERFETTO FUNCTION[prototype=%s, return=%s]: unknown return "
662 "type specified",
663 state->prototype.ToString().c_str(), cf.returns.c_str());
664 }
665 }
666
667 // Verify that the provided SQL prepares to a statement correctly.
668 auto stmt = sqlite_engine()->PrepareStatement(cf.sql);
669 RETURN_IF_ERROR(stmt.status());
670
671 // Verify that every argument name in the function appears in the
672 // argument list.
673 //
674 // We intentionally loop from 1 to |used_param_count| because SQL
675 // parameters are 1-indexed *not* 0-indexed.
676 int used_param_count = sqlite3_bind_parameter_count(stmt.sqlite_stmt());
677 for (int i = 1; i <= used_param_count; ++i) {
678 const char* name = sqlite3_bind_parameter_name(stmt.sqlite_stmt(), i);
679
680 if (!name) {
681 return base::ErrStatus(
682 "%s: \"Nameless\" SQL parameters cannot be used in the SQL "
683 "statements of view functions.",
684 state->prototype.function_name.c_str());
685 }
686
687 if (!base::StringView(name).StartsWith("$")) {
688 return base::ErrStatus(
689 "%s: invalid parameter name %s used in the SQL definition of "
690 "the view function: all parameters must be prefixed with '$' not "
691 "':' or '@'.",
692 state->prototype.function_name.c_str(), name);
693 }
694
695 auto it = std::find_if(state->prototype.arguments.begin(),
696 state->prototype.arguments.end(),
697 [name](const sql_argument::ArgumentDefinition& arg) {
698 return arg.dollar_name() == name;
699 });
700 if (it == state->prototype.arguments.end()) {
701 return base::ErrStatus(
702 "%s: parameter %s does not appear in the list of arguments in the "
703 "prototype of the view function.",
704 state->prototype.function_name.c_str(), name);
705 }
706 }
707
708 // Verify that the prepared statement column count matches the return
709 // count.
710 auto col_count =
711 static_cast<uint32_t>(sqlite3_column_count(stmt.sqlite_stmt()));
712 if (col_count != state->return_values.size()) {
713 return base::ErrStatus(
714 "%s: number of return values %u does not match SQL statement column "
715 "count %zu.",
716 state->prototype.function_name.c_str(), col_count,
717 state->return_values.size());
718 }
719
720 // Verify that the return names matches the prepared statment column names.
721 for (uint32_t i = 0; i < col_count; ++i) {
722 const char* name =
723 sqlite3_column_name(stmt.sqlite_stmt(), static_cast<int>(i));
724 if (name != state->return_values[i].name()) {
725 return base::ErrStatus(
726 "%s: column %s at index %u does not match return value name %s.",
727 state->prototype.function_name.c_str(), name, i,
728 state->return_values[i].name().c_str());
729 }
730 }
731 state->temporary_create_stmt = std::move(stmt);
732
733 // TODO(lalitm): this suffers the same non-atomic DROP/CREATE problem as
734 // CREATE PERFETTO TABLE implementation above: see the comment there for
735 // more info on this.
736 if (cf.replace) {
737 base::StackString<1024> drop("DROP TABLE IF EXISTS %s",
738 state->prototype.function_name.c_str());
739 auto res = Execute(
740 SqlSource::FromTraceProcessorImplementation(drop.ToStdString()));
741 RETURN_IF_ERROR(res.status());
742 }
743
744 base::StackString<1024> create(
745 "CREATE VIRTUAL TABLE %s USING runtime_table_function",
746 state->prototype.function_name.c_str());
747
748 // Make sure we didn't accidentally leak a state from a previous function
749 // creation.
750 PERFETTO_CHECK(!runtime_table_fn_context_->temporary_create_state);
751
752 // Move the state into the context so that it will be picked up in xCreate
753 // of RuntimeTableFunctionModule.
754 runtime_table_fn_context_->temporary_create_state = std::move(state);
755 auto status = Execute(cf.sql.RewriteAllIgnoreExisting(
756 SqlSource::FromTraceProcessorImplementation(
757 create.ToStdString())))
758 .status();
759
760 // If an error happened, it's possible that the state was not picked up.
761 // Therefore, always reset the state just in case. OTOH if the creation
762 // succeeded, the state should always have been captured.
763 if (status.ok()) {
764 PERFETTO_CHECK(!runtime_table_fn_context_->temporary_create_state);
765 } else {
766 runtime_table_fn_context_->temporary_create_state.reset();
767 }
768 return status;
769 }
770
ExecuteCreateMacro(const PerfettoSqlParser::CreateMacro & create_macro)771 base::Status PerfettoSqlEngine::ExecuteCreateMacro(
772 const PerfettoSqlParser::CreateMacro& create_macro) {
773 // Check that the argument types is one of the allowed types.
774 for (const auto& [name, type] : create_macro.args) {
775 if (!IsTokenAllowedInMacro(type.sql())) {
776 // TODO(lalitm): add a link to create macro documentation.
777 return base::ErrStatus(
778 "%sMacro '%s' argument '%s' is unknown type '%s'. Allowed types: %s",
779 type.AsTraceback(0).c_str(), create_macro.name.sql().c_str(),
780 name.sql().c_str(), type.sql().c_str(),
781 GetTokenNamesAllowedInMacro().c_str());
782 }
783 }
784 if (!IsTokenAllowedInMacro(create_macro.returns.sql())) {
785 // TODO(lalitm): add a link to create macro documentation.
786 return base::ErrStatus(
787 "%sMacro %s return type %s is unknown. Allowed types: %s",
788 create_macro.returns.AsTraceback(0).c_str(),
789 create_macro.name.sql().c_str(), create_macro.returns.sql().c_str(),
790 GetTokenNamesAllowedInMacro().c_str());
791 }
792
793 std::vector<std::string> args;
794 args.reserve(create_macro.args.size());
795 for (const auto& arg : create_macro.args) {
796 args.push_back(arg.first.sql());
797 }
798 PerfettoSqlPreprocessor::Macro macro{
799 create_macro.replace,
800 create_macro.name.sql(),
801 std::move(args),
802 create_macro.sql,
803 };
804 if (auto* it = macros_.Find(create_macro.name.sql()); it) {
805 if (!create_macro.replace) {
806 // TODO(lalitm): add a link to create macro documentation.
807 return base::ErrStatus("%sMacro already exists",
808 create_macro.name.AsTraceback(0).c_str());
809 }
810 *it = std::move(macro);
811 return base::OkStatus();
812 }
813 std::string name = macro.name;
814 auto it_and_inserted = macros_.Insert(std::move(name), std::move(macro));
815 PERFETTO_CHECK(it_and_inserted.second);
816 return base::OkStatus();
817 }
818
819 base::StatusOr<std::vector<std::string>>
GetColumnNamesFromSelectStatement(const SqliteEngine::PreparedStatement & stmt,const char * tag)820 PerfettoSqlEngine::GetColumnNamesFromSelectStatement(
821 const SqliteEngine::PreparedStatement& stmt,
822 const char* tag) {
823 auto columns =
824 static_cast<uint32_t>(sqlite3_column_count(stmt.sqlite_stmt()));
825 std::vector<std::string> column_names;
826 for (uint32_t i = 0; i < columns; ++i) {
827 std::string col_name =
828 sqlite3_column_name(stmt.sqlite_stmt(), static_cast<int>(i));
829 if (col_name.empty()) {
830 return base::ErrStatus("%s: column %d: name must not be empty", tag, i);
831 }
832 if (!std::isalpha(col_name.front())) {
833 return base::ErrStatus(
834 "%s: Column %i: name '%s' has to start with a letter.", tag, i,
835 col_name.c_str());
836 }
837 if (!sql_argument::IsValidName(base::StringView(col_name))) {
838 return base::ErrStatus(
839 "%s: Column %i: name '%s' has to contain only alphanumeric "
840 "characters and underscores.",
841 tag, i, col_name.c_str());
842 }
843 column_names.push_back(col_name);
844 }
845 return column_names;
846 }
847
ValidateColumnNames(const std::vector<std::string> & column_names,const std::vector<sql_argument::ArgumentDefinition> & schema,const char * tag)848 base::Status PerfettoSqlEngine::ValidateColumnNames(
849 const std::vector<std::string>& column_names,
850 const std::vector<sql_argument::ArgumentDefinition>& schema,
851 const char* tag) {
852 std::vector<std::string> duplicate_columns;
853 for (auto it = column_names.begin(); it != column_names.end(); ++it) {
854 if (std::count(it + 1, column_names.end(), *it) > 0) {
855 duplicate_columns.push_back(*it);
856 }
857 }
858 if (!duplicate_columns.empty()) {
859 return base::ErrStatus("%s: multiple columns are named: %s", tag,
860 base::Join(duplicate_columns, ", ").c_str());
861 }
862
863 // If the user has not provided a schema, we have nothing further to validate.
864 if (schema.empty()) {
865 return base::OkStatus();
866 }
867
868 std::vector<std::string> columns_missing_from_query;
869 std::vector<std::string> columns_missing_from_schema;
870
871 for (const std::string& name : column_names) {
872 bool present =
873 std::find_if(schema.begin(), schema.end(), [&name](const auto& arg) {
874 return arg.name() == base::StringView(name);
875 }) != schema.end();
876 if (!present) {
877 columns_missing_from_schema.push_back(name);
878 }
879 }
880
881 for (const auto& arg : schema) {
882 bool present = std::find_if(column_names.begin(), column_names.end(),
883 [&arg](const std::string& name) {
884 return arg.name() == base::StringView(name);
885 }) != column_names.end();
886 if (!present) {
887 columns_missing_from_query.push_back(arg.name().ToStdString());
888 }
889 }
890
891 if (columns_missing_from_query.empty() &&
892 columns_missing_from_schema.empty()) {
893 return base::OkStatus();
894 }
895
896 if (columns_missing_from_query.empty()) {
897 return base::ErrStatus(
898 "%s: the following columns are missing from the schema: %s", tag,
899 base::Join(columns_missing_from_schema, ", ").c_str());
900 }
901
902 if (columns_missing_from_schema.empty()) {
903 return base::ErrStatus(
904 "%s: the following columns are declared in the schema, but do not "
905 "exist: %s",
906 tag, base::Join(columns_missing_from_query, ", ").c_str());
907 }
908
909 return base::ErrStatus(
910 "%s: the following columns are declared in the schema, but do not exist: "
911 "%s; and the folowing columns exist, but are not declared: %s",
912 tag, base::Join(columns_missing_from_query, ", ").c_str(),
913 base::Join(columns_missing_from_schema, ", ").c_str());
914 }
915
GetRuntimeTableOrNull(std::string_view name) const916 const RuntimeTable* PerfettoSqlEngine::GetRuntimeTableOrNull(
917 std::string_view name) const {
918 auto* state = runtime_table_context_->manager.FindStateByName(name);
919 return state ? state->runtime_table.get() : nullptr;
920 }
921
GetStaticTableOrNull(std::string_view name) const922 const Table* PerfettoSqlEngine::GetStaticTableOrNull(
923 std::string_view name) const {
924 auto* state = static_table_context_->manager.FindStateByName(name);
925 return state ? state->static_table : nullptr;
926 }
927
928 } // namespace perfetto::trace_processor
929