• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2018 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/table.h"
18 
19 #include <ctype.h>
20 #include <string.h>
21 #include <algorithm>
22 
23 #include "perfetto/base/logging.h"
24 
25 namespace perfetto {
26 namespace trace_processor {
27 
28 namespace {
29 
TypeToString(Table::ColumnType type)30 std::string TypeToString(Table::ColumnType type) {
31   switch (type) {
32     case Table::ColumnType::kString:
33       return "STRING";
34     case Table::ColumnType::kUint:
35       return "UNSIGNED INT";
36     case Table::ColumnType::kLong:
37       return "BIG INT";
38     case Table::ColumnType::kInt:
39       return "INT";
40     case Table::ColumnType::kDouble:
41       return "DOUBLE";
42     case Table::ColumnType::kUnknown:
43       PERFETTO_FATAL("Cannot map unknown column type");
44   }
45   PERFETTO_FATAL("Not reached");  // For gcc
46 }
47 
48 }  // namespace
49 
50 // static
51 bool Table::debug = false;
52 
53 Table::Table() = default;
54 Table::~Table() = default;
55 
OpenInternal(sqlite3_vtab_cursor ** ppCursor)56 int Table::OpenInternal(sqlite3_vtab_cursor** ppCursor) {
57   // Freed in xClose().
58   *ppCursor = static_cast<sqlite3_vtab_cursor*>(CreateCursor().release());
59   return SQLITE_OK;
60 }
61 
BestIndexInternal(sqlite3_index_info * idx)62 int Table::BestIndexInternal(sqlite3_index_info* idx) {
63   QueryConstraints query_constraints;
64 
65   for (int i = 0; i < idx->nOrderBy; i++) {
66     int column = idx->aOrderBy[i].iColumn;
67     bool desc = idx->aOrderBy[i].desc;
68     query_constraints.AddOrderBy(column, desc);
69   }
70 
71   for (int i = 0; i < idx->nConstraint; i++) {
72     const auto& cs = idx->aConstraint[i];
73     if (!cs.usable)
74       continue;
75     query_constraints.AddConstraint(cs.iColumn, cs.op);
76 
77     // argvIndex is 1-based so use the current size of the vector.
78     int argv_index = static_cast<int>(query_constraints.constraints().size());
79     idx->aConstraintUsage[i].argvIndex = argv_index;
80   }
81 
82   BestIndexInfo info;
83   info.omit.resize(query_constraints.constraints().size());
84 
85   int ret = BestIndex(query_constraints, &info);
86 
87   if (Table::debug) {
88     PERFETTO_LOG(
89         "[%s::BestIndex] constraints=%s orderByConsumed=%d estimatedCost=%d",
90         name_.c_str(), query_constraints.ToNewSqlite3String().get(),
91         info.order_by_consumed, info.estimated_cost);
92   }
93 
94   if (ret != SQLITE_OK)
95     return ret;
96 
97   idx->orderByConsumed = info.order_by_consumed;
98   idx->estimatedCost = info.estimated_cost;
99 
100   size_t j = 0;
101   for (int i = 0; i < idx->nConstraint; i++) {
102     const auto& cs = idx->aConstraint[i];
103     if (cs.usable)
104       idx->aConstraintUsage[i].omit = info.omit[j++];
105   }
106 
107   if (!info.order_by_consumed)
108     query_constraints.ClearOrderBy();
109 
110   idx->idxStr = query_constraints.ToNewSqlite3String().release();
111   idx->needToFreeIdxStr = true;
112   idx->idxNum = ++best_index_num_;
113 
114   return SQLITE_OK;
115 }
116 
FindFunction(const char *,FindFunctionFn,void **)117 int Table::FindFunction(const char*, FindFunctionFn, void**) {
118   return 0;
119 }
120 
Update(int,sqlite3_value **,sqlite3_int64 *)121 int Table::Update(int, sqlite3_value**, sqlite3_int64*) {
122   return SQLITE_READONLY;
123 }
124 
ParseConstraints(int idxNum,const char * idxStr,int argc)125 const QueryConstraints& Table::ParseConstraints(int idxNum,
126                                                 const char* idxStr,
127                                                 int argc) {
128   bool cache_hit = true;
129   if (idxNum != qc_hash_) {
130     qc_cache_ = QueryConstraints::FromString(idxStr);
131     qc_hash_ = idxNum;
132     cache_hit = false;
133   }
134   if (Table::debug) {
135     PERFETTO_LOG("[%s::ParseConstraints] constraints=%s argc=%d cache_hit=%d",
136                  name_.c_str(), idxStr, argc, cache_hit);
137   }
138   return qc_cache_;
139 }
140 
Cursor(Table * table)141 Table::Cursor::Cursor(Table* table) : table_(table) {
142   // This is required to prevent us from leaving this field uninitialised if
143   // we ever move construct the Cursor.
144   pVtab = table;
145 }
146 Table::Cursor::~Cursor() = default;
147 
RowId(sqlite3_int64 *)148 int Table::Cursor::RowId(sqlite3_int64*) {
149   return SQLITE_ERROR;
150 }
151 
Column(size_t index,std::string name,ColumnType type,bool hidden)152 Table::Column::Column(size_t index,
153                       std::string name,
154                       ColumnType type,
155                       bool hidden)
156     : index_(index), name_(name), type_(type), hidden_(hidden) {}
157 
Schema(std::vector<Column> columns,std::vector<size_t> primary_keys)158 Table::Schema::Schema(std::vector<Column> columns,
159                       std::vector<size_t> primary_keys)
160     : columns_(std::move(columns)), primary_keys_(std::move(primary_keys)) {
161   for (size_t i = 0; i < columns_.size(); i++) {
162     PERFETTO_CHECK(columns_[i].index() == i);
163   }
164   for (auto key : primary_keys_) {
165     PERFETTO_CHECK(key < columns_.size());
166   }
167 }
168 
169 Table::Schema::Schema() = default;
170 Table::Schema::Schema(const Schema&) = default;
171 Table::Schema& Table::Schema::operator=(const Schema&) = default;
172 
ToCreateTableStmt() const173 std::string Table::Schema::ToCreateTableStmt() const {
174   std::string stmt = "CREATE TABLE x(";
175   for (size_t i = 0; i < columns_.size(); ++i) {
176     const Column& col = columns_[i];
177     stmt += " " + col.name();
178 
179     if (col.type() != ColumnType::kUnknown) {
180       stmt += " " + TypeToString(col.type());
181     } else if (std::find(primary_keys_.begin(), primary_keys_.end(), i) !=
182                primary_keys_.end()) {
183       PERFETTO_FATAL("Unknown type for primary key column %s",
184                      col.name().c_str());
185     }
186     if (col.hidden()) {
187       stmt += " HIDDEN";
188     }
189     stmt += ",";
190   }
191   stmt += " PRIMARY KEY(";
192   for (size_t i = 0; i < primary_keys_.size(); i++) {
193     if (i != 0)
194       stmt += ", ";
195     stmt += columns_[primary_keys_[i]].name();
196   }
197   stmt += ")) WITHOUT ROWID;";
198   return stmt;
199 }
200 
201 }  // namespace trace_processor
202 }  // namespace perfetto
203