1 /*
2 * Copyright (C) 2019 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/db_sqlite_table.h"
18
19 #include <sqlite3.h>
20 #include <algorithm>
21 #include <cmath>
22 #include <cstddef>
23 #include <cstdint>
24 #include <iterator>
25 #include <memory>
26 #include <numeric>
27 #include <optional>
28 #include <string>
29 #include <utility>
30 #include <vector>
31
32 #include "perfetto/base/compiler.h"
33 #include "perfetto/base/logging.h"
34 #include "perfetto/base/status.h"
35 #include "perfetto/ext/base/small_vector.h"
36 #include "perfetto/ext/base/status_or.h"
37 #include "perfetto/ext/base/string_splitter.h"
38 #include "perfetto/ext/base/string_utils.h"
39 #include "perfetto/ext/base/string_view.h"
40 #include "perfetto/public/compiler.h"
41 #include "perfetto/trace_processor/basic_types.h"
42 #include "src/trace_processor/containers/row_map.h"
43 #include "src/trace_processor/db/column/types.h"
44 #include "src/trace_processor/db/runtime_table.h"
45 #include "src/trace_processor/db/table.h"
46 #include "src/trace_processor/perfetto_sql/intrinsics/table_functions/static_table_function.h"
47 #include "src/trace_processor/sqlite/module_lifecycle_manager.h"
48 #include "src/trace_processor/sqlite/sqlite_utils.h"
49 #include "src/trace_processor/tp_metatrace.h"
50 #include "src/trace_processor/util/regex.h"
51
52 #include "protos/perfetto/trace_processor/metatrace_categories.pbzero.h"
53
54 namespace perfetto::trace_processor {
55 namespace {
56
SqliteOpToFilterOp(int sqlite_op)57 std::optional<FilterOp> SqliteOpToFilterOp(int sqlite_op) {
58 switch (sqlite_op) {
59 case SQLITE_INDEX_CONSTRAINT_EQ:
60 return FilterOp::kEq;
61 case SQLITE_INDEX_CONSTRAINT_GT:
62 return FilterOp::kGt;
63 case SQLITE_INDEX_CONSTRAINT_LT:
64 return FilterOp::kLt;
65 case SQLITE_INDEX_CONSTRAINT_NE:
66 return FilterOp::kNe;
67 case SQLITE_INDEX_CONSTRAINT_GE:
68 return FilterOp::kGe;
69 case SQLITE_INDEX_CONSTRAINT_LE:
70 return FilterOp::kLe;
71 case SQLITE_INDEX_CONSTRAINT_ISNULL:
72 return FilterOp::kIsNull;
73 case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
74 return FilterOp::kIsNotNull;
75 case SQLITE_INDEX_CONSTRAINT_GLOB:
76 return FilterOp::kGlob;
77 case SQLITE_INDEX_CONSTRAINT_REGEXP:
78 if constexpr (regex::IsRegexSupported()) {
79 return FilterOp::kRegex;
80 }
81 return std::nullopt;
82 case SQLITE_INDEX_CONSTRAINT_LIKE:
83 // TODO(lalitm): start supporting these constraints.
84 case SQLITE_INDEX_CONSTRAINT_LIMIT:
85 case SQLITE_INDEX_CONSTRAINT_OFFSET:
86 case SQLITE_INDEX_CONSTRAINT_IS:
87 case SQLITE_INDEX_CONSTRAINT_ISNOT:
88 return std::nullopt;
89 default:
90 PERFETTO_FATAL("Currently unsupported constraint");
91 }
92 }
93
94 class SafeStringWriter {
95 public:
AppendString(const char * s)96 void AppendString(const char* s) {
97 for (const char* c = s; *c; ++c) {
98 buffer_.emplace_back(*c);
99 }
100 }
101
AppendString(const std::string & s)102 void AppendString(const std::string& s) {
103 for (char c : s) {
104 buffer_.emplace_back(c);
105 }
106 }
107
GetStringView() const108 base::StringView GetStringView() const {
109 return {buffer_.data(), buffer_.size()};
110 }
111
112 private:
113 base::SmallVector<char, 2048> buffer_;
114 };
115
CreateTableStatementFromSchema(const Table::Schema & schema,const char * table_name)116 std::string CreateTableStatementFromSchema(const Table::Schema& schema,
117 const char* table_name) {
118 std::string stmt = "CREATE TABLE x(";
119 for (const auto& col : schema.columns) {
120 std::string c =
121 col.name + " " + sqlite::utils::SqlValueTypeToSqliteTypeName(col.type);
122 if (col.is_hidden) {
123 c += " HIDDEN";
124 }
125 stmt += c + ",";
126 }
127
128 auto it =
129 std::find_if(schema.columns.begin(), schema.columns.end(),
130 [](const Table::Schema::Column& c) { return c.is_id; });
131 if (it == schema.columns.end()) {
132 PERFETTO_FATAL(
133 "id column not found in %s. All tables need to contain an id column;",
134 table_name);
135 }
136 stmt += "PRIMARY KEY(" + it->name + ")";
137 stmt += ") WITHOUT ROWID;";
138 return stmt;
139 }
140
SqliteValueToSqlValueChecked(SqlValue * sql_val,sqlite3_value * value,const Constraint & cs,sqlite3_vtab * vtab)141 int SqliteValueToSqlValueChecked(SqlValue* sql_val,
142 sqlite3_value* value,
143 const Constraint& cs,
144 sqlite3_vtab* vtab) {
145 *sql_val = sqlite::utils::SqliteValueToSqlValue(value);
146 if constexpr (regex::IsRegexSupported()) {
147 if (cs.op == FilterOp::kRegex) {
148 if (cs.value.type != SqlValue::kString) {
149 return sqlite::utils::SetError(vtab, "Value has to be a string");
150 }
151 if (auto st = regex::Regex::Create(cs.value.AsString()); !st.ok()) {
152 return sqlite::utils::SetError(vtab, st.status().c_message());
153 }
154 }
155 }
156 return SQLITE_OK;
157 }
158
ReadLetterAndInt(char letter,base::StringSplitter * splitter)159 inline uint32_t ReadLetterAndInt(char letter, base::StringSplitter* splitter) {
160 PERFETTO_CHECK(splitter->Next());
161 PERFETTO_DCHECK(splitter->cur_token_size() >= 2);
162 PERFETTO_DCHECK(splitter->cur_token()[0] == letter);
163 return *base::CStringToUInt32(splitter->cur_token() + 1);
164 }
165
ReadLetterAndLong(char letter,base::StringSplitter * splitter)166 inline uint64_t ReadLetterAndLong(char letter, base::StringSplitter* splitter) {
167 PERFETTO_CHECK(splitter->Next());
168 PERFETTO_DCHECK(splitter->cur_token_size() >= 2);
169 PERFETTO_DCHECK(splitter->cur_token()[0] == letter);
170 return *base::CStringToUInt64(splitter->cur_token() + 1);
171 }
172
ReadIdxStrAndUpdateCursor(DbSqliteModule::Cursor * cursor,const char * idx_str,sqlite3_value ** argv)173 int ReadIdxStrAndUpdateCursor(DbSqliteModule::Cursor* cursor,
174 const char* idx_str,
175 sqlite3_value** argv) {
176 base::StringSplitter splitter(idx_str, ',');
177
178 uint32_t cs_count = ReadLetterAndInt('C', &splitter);
179
180 Query q;
181 q.constraints.resize(cs_count);
182
183 uint32_t c_offset = 0;
184 for (auto& cs : q.constraints) {
185 PERFETTO_CHECK(splitter.Next());
186 cs.col_idx = *base::CStringToUInt32(splitter.cur_token());
187 PERFETTO_CHECK(splitter.Next());
188 cs.op = static_cast<FilterOp>(*base::CStringToUInt32(splitter.cur_token()));
189
190 if (int ret = SqliteValueToSqlValueChecked(&cs.value, argv[c_offset++], cs,
191 cursor->pVtab);
192 ret != SQLITE_OK) {
193 return ret;
194 }
195 }
196
197 uint32_t ob_count = ReadLetterAndInt('O', &splitter);
198
199 q.orders.resize(ob_count);
200 for (auto& ob : q.orders) {
201 PERFETTO_CHECK(splitter.Next());
202 ob.col_idx = *base::CStringToUInt32(splitter.cur_token());
203 PERFETTO_CHECK(splitter.Next());
204 ob.desc = *base::CStringToUInt32(splitter.cur_token());
205 }
206
207 // DISTINCT
208 q.order_type =
209 static_cast<Query::OrderType>(ReadLetterAndInt('D', &splitter));
210
211 // Cols used
212 q.cols_used = ReadLetterAndLong('U', &splitter);
213
214 // LIMIT
215 if (ReadLetterAndInt('L', &splitter)) {
216 auto val_op = sqlite::utils::SqliteValueToSqlValue(argv[c_offset++]);
217 if (val_op.type != SqlValue::kLong) {
218 return sqlite::utils::SetError(cursor->pVtab,
219 "LIMIT value has to be an INT");
220 }
221 q.limit = val_op.AsLong();
222 }
223
224 // OFFSET
225 if (ReadLetterAndInt('F', &splitter)) {
226 auto val_op = sqlite::utils::SqliteValueToSqlValue(argv[c_offset++]);
227 if (val_op.type != SqlValue::kLong) {
228 return sqlite::utils::SetError(cursor->pVtab,
229 "OFFSET value has to be an INT");
230 }
231 q.offset = static_cast<uint32_t>(val_op.AsLong());
232 }
233
234 cursor->query = std::move(q);
235 return SQLITE_OK;
236 }
237
TryCacheCreateSortedTable(DbSqliteModule::Cursor * cursor,const Table::Schema & schema,bool is_same_idx)238 PERFETTO_ALWAYS_INLINE void TryCacheCreateSortedTable(
239 DbSqliteModule::Cursor* cursor,
240 const Table::Schema& schema,
241 bool is_same_idx) {
242 if (!is_same_idx) {
243 cursor->repeated_cache_count = 0;
244 return;
245 }
246
247 // Only try and create the cached table on exactly the third time we see
248 // this constraint set.
249 constexpr uint32_t kRepeatedThreshold = 3;
250 if (cursor->sorted_cache_table ||
251 cursor->repeated_cache_count++ != kRepeatedThreshold) {
252 return;
253 }
254
255 // If we have more than one constraint, we can't cache the table using
256 // this method.
257 if (cursor->query.constraints.size() != 1) {
258 return;
259 }
260
261 // If the constraing is not an equality constraint, there's little
262 // benefit to caching
263 const auto& c = cursor->query.constraints.front();
264 if (c.op != FilterOp::kEq) {
265 return;
266 }
267
268 // If the column is already sorted, we don't need to cache at all.
269 if (schema.columns[c.col_idx].is_sorted) {
270 return;
271 }
272
273 // Try again to get the result or start caching it.
274 cursor->sorted_cache_table =
275 cursor->upstream_table->Sort({Order{c.col_idx, false}});
276 }
277
FilterAndSortMetatrace(const std::string & table_name,const Table::Schema & schema,DbSqliteModule::Cursor * cursor,metatrace::Record * r)278 void FilterAndSortMetatrace(const std::string& table_name,
279 const Table::Schema& schema,
280 DbSqliteModule::Cursor* cursor,
281 metatrace::Record* r) {
282 r->AddArg("Table", table_name);
283 for (const Constraint& c : cursor->query.constraints) {
284 SafeStringWriter writer;
285 writer.AppendString(schema.columns[c.col_idx].name);
286
287 writer.AppendString(" ");
288 switch (c.op) {
289 case FilterOp::kEq:
290 writer.AppendString("=");
291 break;
292 case FilterOp::kGe:
293 writer.AppendString(">=");
294 break;
295 case FilterOp::kGt:
296 writer.AppendString(">");
297 break;
298 case FilterOp::kLe:
299 writer.AppendString("<=");
300 break;
301 case FilterOp::kLt:
302 writer.AppendString("<");
303 break;
304 case FilterOp::kNe:
305 writer.AppendString("!=");
306 break;
307 case FilterOp::kIsNull:
308 writer.AppendString("IS");
309 break;
310 case FilterOp::kIsNotNull:
311 writer.AppendString("IS NOT");
312 break;
313 case FilterOp::kGlob:
314 writer.AppendString("GLOB");
315 break;
316 case FilterOp::kRegex:
317 writer.AppendString("REGEXP");
318 break;
319 }
320 writer.AppendString(" ");
321
322 switch (c.value.type) {
323 case SqlValue::kString:
324 writer.AppendString(c.value.AsString());
325 break;
326 case SqlValue::kBytes:
327 writer.AppendString("<bytes>");
328 break;
329 case SqlValue::kNull:
330 writer.AppendString("<null>");
331 break;
332 case SqlValue::kDouble: {
333 writer.AppendString(std::to_string(c.value.AsDouble()));
334 break;
335 }
336 case SqlValue::kLong: {
337 writer.AppendString(std::to_string(c.value.AsLong()));
338 break;
339 }
340 }
341 r->AddArg("Constraint", writer.GetStringView());
342 }
343
344 for (const auto& o : cursor->query.orders) {
345 SafeStringWriter writer;
346 writer.AppendString(schema.columns[o.col_idx].name);
347 if (o.desc)
348 writer.AppendString(" desc");
349 r->AddArg("Order by", writer.GetStringView());
350 }
351 }
352
353 } // namespace
354
Create(sqlite3 * db,void * ctx,int argc,const char * const * argv,sqlite3_vtab ** vtab,char **)355 int DbSqliteModule::Create(sqlite3* db,
356 void* ctx,
357 int argc,
358 const char* const* argv,
359 sqlite3_vtab** vtab,
360 char**) {
361 PERFETTO_CHECK(argc == 3);
362 auto* context = GetContext(ctx);
363 auto state = std::move(context->temporary_create_state);
364 PERFETTO_CHECK(state);
365
366 std::string sql = CreateTableStatementFromSchema(state->schema, argv[2]);
367 if (int ret = sqlite3_declare_vtab(db, sql.c_str()); ret != SQLITE_OK) {
368 return ret;
369 }
370 std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
371 res->state = context->manager.OnCreate(argv, std::move(state));
372 res->table_name = argv[2];
373 *vtab = res.release();
374 return SQLITE_OK;
375 }
376
Destroy(sqlite3_vtab * vtab)377 int DbSqliteModule::Destroy(sqlite3_vtab* vtab) {
378 auto* t = GetVtab(vtab);
379 auto* s = sqlite::ModuleStateManager<DbSqliteModule>::GetState(t->state);
380 if (s->computation == TableComputation::kStatic) {
381 // SQLite does not read error messages returned from xDestroy so just pick
382 // the closest appropriate error code.
383 return SQLITE_READONLY;
384 }
385 std::unique_ptr<Vtab> tab(GetVtab(vtab));
386 sqlite::ModuleStateManager<DbSqliteModule>::OnDestroy(tab->state);
387 return SQLITE_OK;
388 }
389
Connect(sqlite3 * db,void * ctx,int argc,const char * const * argv,sqlite3_vtab ** vtab,char **)390 int DbSqliteModule::Connect(sqlite3* db,
391 void* ctx,
392 int argc,
393 const char* const* argv,
394 sqlite3_vtab** vtab,
395 char**) {
396 PERFETTO_CHECK(argc == 3);
397 auto* context = GetContext(ctx);
398
399 std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
400 res->state = context->manager.OnConnect(argv);
401 res->table_name = argv[2];
402
403 auto* state =
404 sqlite::ModuleStateManager<DbSqliteModule>::GetState(res->state);
405 std::string sql = CreateTableStatementFromSchema(state->schema, argv[2]);
406 if (int ret = sqlite3_declare_vtab(db, sql.c_str()); ret != SQLITE_OK) {
407 // If the registration happens to fail, make sure to disconnect the state
408 // again.
409 sqlite::ModuleStateManager<DbSqliteModule>::OnDisconnect(res->state);
410 return ret;
411 }
412 *vtab = res.release();
413 return SQLITE_OK;
414 }
415
Disconnect(sqlite3_vtab * vtab)416 int DbSqliteModule::Disconnect(sqlite3_vtab* vtab) {
417 std::unique_ptr<Vtab> tab(GetVtab(vtab));
418 sqlite::ModuleStateManager<DbSqliteModule>::OnDisconnect(tab->state);
419 return SQLITE_OK;
420 }
421
BestIndex(sqlite3_vtab * vtab,sqlite3_index_info * info)422 int DbSqliteModule::BestIndex(sqlite3_vtab* vtab, sqlite3_index_info* info) {
423 auto* t = GetVtab(vtab);
424 auto* s = sqlite::ModuleStateManager<DbSqliteModule>::GetState(t->state);
425
426 const Table* table = nullptr;
427 switch (s->computation) {
428 case TableComputation::kStatic:
429 table = s->static_table;
430 break;
431 case TableComputation::kRuntime:
432 table = s->runtime_table.get();
433 break;
434 case TableComputation::kTableFunction:
435 break;
436 }
437
438 uint32_t row_count;
439 int argv_index;
440 switch (s->computation) {
441 case TableComputation::kStatic:
442 case TableComputation::kRuntime:
443 row_count = table->row_count();
444 argv_index = 1;
445 break;
446 case TableComputation::kTableFunction:
447 base::Status status = sqlite::utils::ValidateFunctionArguments(
448 info, static_cast<size_t>(s->argument_count),
449 [s](uint32_t i) { return s->schema.columns[i].is_hidden; });
450 if (!status.ok()) {
451 // TODO(lalitm): instead of returning SQLITE_CONSTRAINT which shows the
452 // user a very cryptic error message, consider instead SQLITE_OK but
453 // with a very high (~infinite) cost. If SQLite still chose the query
454 // plan after that, we can throw a proper error message in xFilter.
455 return SQLITE_CONSTRAINT;
456 }
457 row_count = s->static_table_function->EstimateRowCount();
458 argv_index = 1 + s->argument_count;
459 break;
460 }
461
462 std::vector<int> cs_idxes;
463
464 // Limit and offset are a nonstandard type of constraint. We can check if they
465 // are present in the query here, but we won't save them as standard
466 // constraints and only add them to `idx_str` later.
467 int limit = -1;
468 int offset = -1;
469 bool has_unknown_constraint = false;
470
471 cs_idxes.reserve(static_cast<uint32_t>(info->nConstraint));
472 for (int i = 0; i < info->nConstraint; ++i) {
473 const auto& c = info->aConstraint[i];
474 if (!c.usable || info->aConstraintUsage[i].omit) {
475 continue;
476 }
477 if (std::optional<FilterOp> opt_op = SqliteOpToFilterOp(c.op); !opt_op) {
478 if (c.op == SQLITE_INDEX_CONSTRAINT_LIMIT) {
479 limit = i;
480 } else if (c.op == SQLITE_INDEX_CONSTRAINT_OFFSET) {
481 offset = i;
482 } else {
483 has_unknown_constraint = true;
484 }
485 continue;
486 }
487 cs_idxes.push_back(i);
488 }
489
490 std::vector<int> ob_idxes(static_cast<uint32_t>(info->nOrderBy));
491 std::iota(ob_idxes.begin(), ob_idxes.end(), 0);
492
493 // Reorder constraints to consider the constraints on columns which are
494 // cheaper to filter first.
495 {
496 std::sort(
497 cs_idxes.begin(), cs_idxes.end(), [s, info, &table](int a, int b) {
498 auto a_idx = static_cast<uint32_t>(info->aConstraint[a].iColumn);
499 auto b_idx = static_cast<uint32_t>(info->aConstraint[b].iColumn);
500 const auto& a_col = s->schema.columns[a_idx];
501 const auto& b_col = s->schema.columns[b_idx];
502
503 // Id columns are the most efficient to filter, as they don't have a
504 // support in real data.
505 if (a_col.is_id || b_col.is_id)
506 return a_col.is_id && !b_col.is_id;
507
508 // Set id columns are inherently sorted and have fast filtering
509 // operations.
510 if (a_col.is_set_id || b_col.is_set_id)
511 return a_col.is_set_id && !b_col.is_set_id;
512
513 // Intrinsically sorted column is more efficient to sort than
514 // extrinsically sorted column.
515 if (a_col.is_sorted || b_col.is_sorted)
516 return a_col.is_sorted && !b_col.is_sorted;
517
518 // Extrinsically sorted column is more efficient to sort than unsorted
519 // column.
520 if (table) {
521 auto a_has_idx = table->GetIndex({a_idx});
522 auto b_has_idx = table->GetIndex({b_idx});
523 if (a_has_idx || b_has_idx)
524 return a_has_idx && !b_has_idx;
525 }
526
527 bool a_is_eq = sqlite::utils::IsOpEq(info->aConstraint[a].op);
528 bool b_is_eq = sqlite::utils::IsOpEq(info->aConstraint[a].op);
529 if (a_is_eq || b_is_eq) {
530 return a_is_eq && !b_is_eq;
531 }
532
533 // TODO(lalitm): introduce more orderings here based on empirical
534 // data.
535 return false;
536 });
537 }
538
539 // Remove any order by constraints which also have an equality constraint.
540 {
541 auto p = [info, &cs_idxes](int o_idx) {
542 auto& o = info->aOrderBy[o_idx];
543 auto inner_p = [info, &o](int c_idx) {
544 auto& c = info->aConstraint[c_idx];
545 return c.iColumn == o.iColumn && sqlite::utils::IsOpEq(c.op);
546 };
547 return std::any_of(cs_idxes.begin(), cs_idxes.end(), inner_p);
548 };
549 ob_idxes.erase(std::remove_if(ob_idxes.begin(), ob_idxes.end(), p),
550 ob_idxes.end());
551 }
552
553 // Go through the order by constraints in reverse order and eliminate
554 // constraints until the first non-sorted column or the first order by in
555 // descending order.
556 {
557 auto p = [info, s](int o_idx) {
558 auto& o = info->aOrderBy[o_idx];
559 const auto& col = s->schema.columns[static_cast<uint32_t>(o.iColumn)];
560 return o.desc || !col.is_sorted;
561 };
562 auto first_non_sorted_it =
563 std::find_if(ob_idxes.rbegin(), ob_idxes.rend(), p);
564 auto pop_count = std::distance(ob_idxes.rbegin(), first_non_sorted_it);
565 ob_idxes.resize(ob_idxes.size() - static_cast<uint32_t>(pop_count));
566 }
567
568 // Create index string. It contains information query Trace Processor will
569 // have to run. It can be split into 6 segments: C (constraints), O (orders),
570 // D (distinct), U (used), L (limit) and F (offset). It can be directly mapped
571 // into `Query` type. The number after C and O signifies how many
572 // constraints/orders there are. The number after D maps to the
573 // Query::Distinct enum value.
574 //
575 // "C2,0,0,2,1,O1,0,1,D1,U5,L0,F1" maps to:
576 // - "C2,0,0,2,1" - two constraints: kEq on first column and kNe on third
577 // column.
578 // - "O1,0,1" - one order by: descending on first column.
579 // - "D1" - kUnsorted distinct.
580 // - "U5" - Columns 0 and 2 used.
581 // - "L1" - LIMIT set. "L0" if no limit.
582 // - "F1" - OFFSET set. Can only be set if "L1".
583
584 // Constraints:
585 std::string idx_str = "C";
586 idx_str += std::to_string(cs_idxes.size());
587 for (int i : cs_idxes) {
588 const auto& c = info->aConstraint[i];
589 auto& o = info->aConstraintUsage[i];
590 o.omit = true;
591 o.argvIndex = argv_index++;
592
593 auto op = SqliteOpToFilterOp(c.op);
594 PERFETTO_DCHECK(op);
595
596 idx_str += ',';
597 idx_str += std::to_string(c.iColumn);
598 idx_str += ',';
599 idx_str += std::to_string(static_cast<uint32_t>(*op));
600 }
601 idx_str += ",";
602
603 // Orders:
604 idx_str += "O";
605 idx_str += std::to_string(ob_idxes.size());
606 for (int i : ob_idxes) {
607 idx_str += ',';
608 idx_str += std::to_string(info->aOrderBy[i].iColumn);
609 idx_str += ',';
610 idx_str += std::to_string(info->aOrderBy[i].desc);
611 }
612 idx_str += ",";
613
614 // Distinct:
615 idx_str += "D";
616 if (ob_idxes.size() == 1 && PERFETTO_POPCOUNT(info->colUsed) == 1) {
617 switch (sqlite3_vtab_distinct(info)) {
618 case 0:
619 case 1:
620 idx_str += std::to_string(static_cast<int>(Query::OrderType::kSort));
621 break;
622 case 2:
623 idx_str +=
624 std::to_string(static_cast<int>(Query::OrderType::kDistinct));
625 break;
626 case 3:
627 idx_str += std::to_string(
628 static_cast<int>(Query::OrderType::kDistinctAndSort));
629 break;
630 default:
631 PERFETTO_FATAL("Invalid sqlite3_vtab_distinct result");
632 }
633 } else {
634 // TODO(mayzner): Remove this if condition after implementing multicolumn
635 // distinct.
636 idx_str += std::to_string(static_cast<int>(Query::OrderType::kSort));
637 }
638 idx_str += ",";
639
640 // Columns used.
641 idx_str += "U";
642 idx_str += std::to_string(info->colUsed);
643 idx_str += ",";
644
645 // LIMIT. Save as "L1" if limit is present and "L0" if not.
646 idx_str += "L";
647 if (limit == -1 || has_unknown_constraint) {
648 idx_str += "0";
649 } else {
650 auto& o = info->aConstraintUsage[limit];
651 o.omit = true;
652 o.argvIndex = argv_index++;
653 idx_str += "1";
654 }
655 idx_str += ",";
656
657 // OFFSET. Save as "F1" if offset is present and "F0" if not.
658 idx_str += "F";
659 if (offset == -1 || has_unknown_constraint) {
660 idx_str += "0";
661 } else {
662 auto& o = info->aConstraintUsage[offset];
663 o.omit = true;
664 o.argvIndex = argv_index++;
665 idx_str += "1";
666 }
667
668 info->idxStr = sqlite3_mprintf("%s", idx_str.c_str());
669
670 info->idxNum = t->best_index_num++;
671 info->needToFreeIdxStr = true;
672
673 // We can sort on any column correctly.
674 info->orderByConsumed = true;
675
676 auto cost_and_rows =
677 EstimateCost(s->schema, row_count, info, cs_idxes, ob_idxes);
678 info->estimatedCost = cost_and_rows.cost;
679 info->estimatedRows = cost_and_rows.rows;
680
681 return SQLITE_OK;
682 }
683
Open(sqlite3_vtab * tab,sqlite3_vtab_cursor ** cursor)684 int DbSqliteModule::Open(sqlite3_vtab* tab, sqlite3_vtab_cursor** cursor) {
685 auto* t = GetVtab(tab);
686 auto* s = sqlite::ModuleStateManager<DbSqliteModule>::GetState(t->state);
687 std::unique_ptr<Cursor> c = std::make_unique<Cursor>();
688 switch (s->computation) {
689 case TableComputation::kStatic:
690 c->upstream_table = s->static_table;
691 break;
692 case TableComputation::kRuntime:
693 c->upstream_table = s->runtime_table.get();
694 break;
695 case TableComputation::kTableFunction:
696 c->table_function_arguments.resize(
697 static_cast<size_t>(s->argument_count));
698 break;
699 }
700 *cursor = c.release();
701 return SQLITE_OK;
702 }
703
Close(sqlite3_vtab_cursor * cursor)704 int DbSqliteModule::Close(sqlite3_vtab_cursor* cursor) {
705 std::unique_ptr<Cursor> c(GetCursor(cursor));
706 return SQLITE_OK;
707 }
708
Filter(sqlite3_vtab_cursor * cursor,int idx_num,const char * idx_str,int,sqlite3_value ** argv)709 int DbSqliteModule::Filter(sqlite3_vtab_cursor* cursor,
710 int idx_num,
711 const char* idx_str,
712 int,
713 sqlite3_value** argv) {
714 auto* c = GetCursor(cursor);
715 auto* t = GetVtab(cursor->pVtab);
716 auto* s = sqlite::ModuleStateManager<DbSqliteModule>::GetState(t->state);
717
718 // Clear out the iterator before filtering to ensure the destructor is run
719 // before the table's destructor.
720 c->iterator = std::nullopt;
721
722 size_t offset = c->table_function_arguments.size();
723 bool is_same_idx = idx_num == c->last_idx_num;
724 if (PERFETTO_LIKELY(is_same_idx)) {
725 for (auto& cs : c->query.constraints) {
726 if (int ret = SqliteValueToSqlValueChecked(&cs.value, argv[offset++], cs,
727 c->pVtab);
728 ret != SQLITE_OK) {
729 return ret;
730 }
731 }
732 } else {
733 if (int r = ReadIdxStrAndUpdateCursor(c, idx_str, argv + offset);
734 r != SQLITE_OK) {
735 return r;
736 }
737 c->last_idx_num = idx_num;
738 }
739
740 // Setup the upstream table based on the computation state.
741 switch (s->computation) {
742 case TableComputation::kStatic:
743 case TableComputation::kRuntime:
744 // Tries to create a sorted cached table which can be used to speed up
745 // filters below.
746 TryCacheCreateSortedTable(c, s->schema, is_same_idx);
747 break;
748 case TableComputation::kTableFunction: {
749 PERFETTO_TP_TRACE(
750 metatrace::Category::QUERY_DETAILED, "TABLE_FUNCTION_CALL",
751 [t](metatrace::Record* r) { r->AddArg("Name", t->table_name); });
752 for (uint32_t i = 0; i < c->table_function_arguments.size(); ++i) {
753 c->table_function_arguments[i] =
754 sqlite::utils::SqliteValueToSqlValue(argv[i]);
755 }
756 base::StatusOr<std::unique_ptr<Table>> table =
757 s->static_table_function->ComputeTable(c->table_function_arguments);
758 if (!table.ok()) {
759 base::StackString<1024> err("%s: %s", t->table_name.c_str(),
760 table.status().c_message());
761 return sqlite::utils::SetError(t, err.c_str());
762 }
763 c->dynamic_table = std::move(*table);
764 c->upstream_table = c->dynamic_table.get();
765 break;
766 }
767 }
768
769 PERFETTO_TP_TRACE(metatrace::Category::QUERY_DETAILED,
770 "DB_TABLE_FILTER_AND_SORT",
771 [s, t, c](metatrace::Record* r) {
772 FilterAndSortMetatrace(t->table_name, s->schema, c, r);
773 });
774
775 const auto* source_table =
776 c->sorted_cache_table ? &*c->sorted_cache_table : c->upstream_table;
777 RowMap filter_map = source_table->QueryToRowMap(c->query);
778 if (filter_map.IsRange() && filter_map.size() <= 1) {
779 // Currently, our criteria where we have a special fast path is if it's
780 // a single ranged row. We have this fast path for joins on id columns
781 // where we get repeated queries filtering down to a single row. The
782 // other path performs allocations when creating the new table as well
783 // as the iterator on the new table whereas this path only uses a single
784 // number and lives entirely on the stack.
785
786 // TODO(lalitm): investigate some other criteria where it is beneficial
787 // to have a fast path and expand to them.
788 c->mode = Cursor::Mode::kSingleRow;
789 c->single_row = filter_map.size() == 1
790 ? std::make_optional(filter_map.Get(0))
791 : std::nullopt;
792 c->eof = !c->single_row.has_value();
793 } else {
794 c->mode = Cursor::Mode::kTable;
795 c->iterator = source_table->ApplyAndIterateRows(std::move(filter_map));
796 c->eof = !*c->iterator;
797 }
798 return SQLITE_OK;
799 }
800
Next(sqlite3_vtab_cursor * cursor)801 int DbSqliteModule::Next(sqlite3_vtab_cursor* cursor) {
802 auto* c = GetCursor(cursor);
803 if (c->mode == Cursor::Mode::kSingleRow) {
804 c->eof = true;
805 } else {
806 c->eof = !++*c->iterator;
807 }
808 return SQLITE_OK;
809 }
810
Eof(sqlite3_vtab_cursor * cursor)811 int DbSqliteModule::Eof(sqlite3_vtab_cursor* cursor) {
812 return GetCursor(cursor)->eof;
813 }
814
Column(sqlite3_vtab_cursor * cursor,sqlite3_context * ctx,int N)815 int DbSqliteModule::Column(sqlite3_vtab_cursor* cursor,
816 sqlite3_context* ctx,
817 int N) {
818 Cursor* c = GetCursor(cursor);
819 auto idx = static_cast<uint32_t>(N);
820 const auto* source_table =
821 c->sorted_cache_table ? &*c->sorted_cache_table : c->upstream_table;
822 SqlValue value = c->mode == Cursor::Mode::kSingleRow
823 ? source_table->columns()[idx].Get(*c->single_row)
824 : c->iterator->Get(idx);
825
826 // We can say kSqliteStatic for strings because all strings are expected
827 // to come from the string pool. Thus they will be valid for the lifetime
828 // of trace processor. Similarily, for bytes, we can also use
829 // kSqliteStatic because for our iterator will hold onto the pointer as
830 // long as we don't call Next(). However, that only happens when Next() is
831 // called on the Cursor itself, at which point SQLite no longer cares
832 // about the bytes pointer.
833 sqlite::utils::ReportSqlValue(ctx, value, sqlite::utils::kSqliteStatic,
834 sqlite::utils::kSqliteStatic);
835 return SQLITE_OK;
836 }
837
Rowid(sqlite3_vtab_cursor *,sqlite_int64 *)838 int DbSqliteModule::Rowid(sqlite3_vtab_cursor*, sqlite_int64*) {
839 return SQLITE_ERROR;
840 }
841
EstimateCost(const Table::Schema & schema,uint32_t row_count,sqlite3_index_info * info,const std::vector<int> & cs_idxes,const std::vector<int> & ob_idxes)842 DbSqliteModule::QueryCost DbSqliteModule::EstimateCost(
843 const Table::Schema& schema,
844 uint32_t row_count,
845 sqlite3_index_info* info,
846 const std::vector<int>& cs_idxes,
847 const std::vector<int>& ob_idxes) {
848 // Currently our cost estimation algorithm is quite simplistic but is good
849 // enough for the simplest cases.
850 // TODO(lalitm): replace hardcoded constants with either more heuristics
851 // based on the exact type of constraint or profiling the queries
852 // themselves.
853
854 // We estimate the fixed cost of set-up and tear-down of a query in terms of
855 // the number of rows scanned.
856 constexpr double kFixedQueryCost = 1000.0;
857
858 // Setup the variables for estimating the number of rows we will have at the
859 // end of filtering. Note that |current_row_count| should always be at least
860 // 1 unless we are absolutely certain that we will return no rows as
861 // otherwise SQLite can make some bad choices.
862 uint32_t current_row_count = row_count;
863
864 // If the table is empty, any constraint set only pays the fixed cost. Also
865 // we can return 0 as the row count as we are certain that we will return no
866 // rows.
867 if (current_row_count == 0) {
868 return QueryCost{kFixedQueryCost, 0};
869 }
870
871 // Setup the variables for estimating the cost of filtering.
872 double filter_cost = 0.0;
873 for (int i : cs_idxes) {
874 if (current_row_count < 2) {
875 break;
876 }
877 const auto& c = info->aConstraint[i];
878 PERFETTO_DCHECK(c.usable);
879 PERFETTO_DCHECK(info->aConstraintUsage[i].omit);
880 PERFETTO_DCHECK(info->aConstraintUsage[i].argvIndex > 0);
881 const auto& col_schema = schema.columns[static_cast<uint32_t>(c.iColumn)];
882 if (sqlite::utils::IsOpEq(c.op) && col_schema.is_id) {
883 // If we have an id equality constraint, we can very efficiently filter
884 // down to a single row in C++. However, if we're joining with another
885 // table, SQLite will do this once per row which can be extremely
886 // expensive because of all the virtual table (which is implemented
887 // using virtual function calls) machinery. Indicate this by saying that
888 // an entire filter call is ~10x the cost of iterating a single row.
889 filter_cost += 10;
890 current_row_count = 1;
891 } else if (sqlite::utils::IsOpEq(c.op)) {
892 // If there is only a single equality constraint, we have special logic
893 // to sort by that column and then binary search if we see the
894 // constraint set often. Model this by dividing by the log of the number
895 // of rows as a good approximation. Otherwise, we'll need to do a full
896 // table scan. Alternatively, if the column is sorted, we can use the
897 // same binary search logic so we have the same low cost (even
898 // better because we don't // have to sort at all).
899 filter_cost += cs_idxes.size() == 1 || col_schema.is_sorted
900 ? log2(current_row_count)
901 : current_row_count;
902
903 // As an extremely rough heuristic, assume that an equalty constraint
904 // will cut down the number of rows by approximately double log of the
905 // number of rows.
906 double estimated_rows = current_row_count / (2 * log2(current_row_count));
907 current_row_count = std::max(static_cast<uint32_t>(estimated_rows), 1u);
908 } else if (col_schema.is_sorted &&
909 (sqlite::utils::IsOpLe(c.op) || sqlite::utils::IsOpLt(c.op) ||
910 sqlite::utils::IsOpGt(c.op) || sqlite::utils::IsOpGe(c.op))) {
911 // On a sorted column, if we see any partition constraints, we can do
912 // this filter very efficiently. Model this using the log of the number
913 // of rows as a good approximation.
914 filter_cost += log2(current_row_count);
915
916 // As an extremely rough heuristic, assume that an partition constraint
917 // will cut down the number of rows by approximately double log of the
918 // number of rows.
919 double estimated_rows = current_row_count / (2 * log2(current_row_count));
920 current_row_count = std::max(static_cast<uint32_t>(estimated_rows), 1u);
921 } else {
922 // Otherwise, we will need to do a full table scan and we estimate we
923 // will maybe (at best) halve the number of rows.
924 filter_cost += current_row_count;
925 current_row_count = std::max(current_row_count / 2u, 1u);
926 }
927 }
928
929 // Now, to figure out the cost of sorting, multiply the final row count
930 // by |qc.order_by().size()| * log(row count). This should act as a crude
931 // estimation of the cost.
932 double sort_cost =
933 static_cast<double>(static_cast<uint32_t>(ob_idxes.size()) *
934 current_row_count) *
935 log2(current_row_count);
936
937 // The cost of iterating rows is more expensive than just filtering the rows
938 // so multiply by an appropriate factor.
939 double iteration_cost = current_row_count * 2.0;
940
941 // To get the final cost, add up all the individual components.
942 double final_cost =
943 kFixedQueryCost + filter_cost + sort_cost + iteration_cost;
944 return QueryCost{final_cost, current_row_count};
945 }
946
State(Table * _table,Table::Schema _schema)947 DbSqliteModule::State::State(Table* _table, Table::Schema _schema)
948 : State(TableComputation::kStatic, std::move(_schema)) {
949 static_table = _table;
950 }
951
State(std::unique_ptr<RuntimeTable> _table)952 DbSqliteModule::State::State(std::unique_ptr<RuntimeTable> _table)
953 : State(TableComputation::kRuntime, _table->schema()) {
954 runtime_table = std::move(_table);
955 }
956
State(std::unique_ptr<StaticTableFunction> _static_function)957 DbSqliteModule::State::State(
958 std::unique_ptr<StaticTableFunction> _static_function)
959 : State(TableComputation::kTableFunction,
960 _static_function->CreateSchema()) {
961 static_table_function = std::move(_static_function);
962 for (const auto& c : schema.columns) {
963 argument_count += c.is_hidden;
964 }
965 }
966
State(TableComputation _computation,Table::Schema _schema)967 DbSqliteModule::State::State(TableComputation _computation,
968 Table::Schema _schema)
969 : computation(_computation), schema(std::move(_schema)) {}
970
971 } // namespace perfetto::trace_processor
972