xref: /aosp_15_r20/external/perfetto/src/trace_processor/sqlite/db_sqlite_table.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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