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