• 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/sqlite/sqlite_table.h"
18 
19 #include <ctype.h>
20 #include <inttypes.h>
21 #include <string.h>
22 #include <algorithm>
23 #include <map>
24 
25 #include "perfetto/base/logging.h"
26 
27 namespace perfetto {
28 namespace trace_processor {
29 
30 namespace {
31 
TypeToString(SqlValue::Type type)32 std::string TypeToString(SqlValue::Type type) {
33   switch (type) {
34     case SqlValue::Type::kString:
35       return "TEXT";
36     case SqlValue::Type::kLong:
37       return "BIG INT";
38     case SqlValue::Type::kDouble:
39       return "DOUBLE";
40     case SqlValue::Type::kBytes:
41       return "BLOB";
42     case SqlValue::Type::kNull:
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 SqliteTable::debug = false;
52 
53 SqliteTable::SqliteTable() = default;
54 SqliteTable::~SqliteTable() = default;
55 
OpenInternal(sqlite3_vtab_cursor ** ppCursor)56 int SqliteTable::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 SqliteTable::BestIndexInternal(sqlite3_index_info* idx) {
63   QueryConstraints qc;
64 
65   for (int i = 0; i < idx->nConstraint; i++) {
66     const auto& cs = idx->aConstraint[i];
67     if (!cs.usable)
68       continue;
69     qc.AddConstraint(cs.iColumn, cs.op, i);
70   }
71 
72   for (int i = 0; i < idx->nOrderBy; i++) {
73     int column = idx->aOrderBy[i].iColumn;
74     bool desc = idx->aOrderBy[i].desc;
75     qc.AddOrderBy(column, desc);
76   }
77 
78   int ret = ModifyConstraints(&qc);
79   if (ret != SQLITE_OK)
80     return ret;
81 
82   BestIndexInfo info;
83   info.estimated_cost = idx->estimatedCost;
84   info.estimated_rows = idx->estimatedRows;
85   info.sqlite_omit_constraint.resize(qc.constraints().size());
86 
87   ret = BestIndex(qc, &info);
88 
89   // Although the SQLite documentation promises that if we return
90   // SQLITE_CONSTRAINT, it won't chose this query plan, in practice, this causes
91   // the entire query to be abandonned even if there is another query plan which
92   // would definitely work. For this reason, we reserve idxNum == INT_MAX for
93   // invalid constraints and just keep the default estimated cost (which should
94   // lead to the plan not being chosen). In xFilter, we can then return
95   // SQLITE_CONSTRAINT if this query plan is still chosen.
96   if (ret == SQLITE_CONSTRAINT) {
97     idx->idxNum = kInvalidConstraintsInBestIndexNum;
98     return SQLITE_OK;
99   }
100 
101   if (ret != SQLITE_OK)
102     return ret;
103 
104   idx->orderByConsumed = qc.order_by().empty() || info.sqlite_omit_order_by;
105   idx->estimatedCost = info.estimated_cost;
106   idx->estimatedRows = info.estimated_rows;
107 
108   // First pass: mark all constraints as omitted to ensure that any pruned
109   // constraints are not checked for by SQLite.
110   for (int i = 0; i < idx->nConstraint; ++i) {
111     auto& u = idx->aConstraintUsage[i];
112     u.omit = true;
113   }
114 
115   // Second pass: actually set the correct omit and index values for all
116   // retained constraints.
117   for (uint32_t i = 0; i < qc.constraints().size(); ++i) {
118     auto& u = idx->aConstraintUsage[qc.constraints()[i].a_constraint_idx];
119     u.omit = info.sqlite_omit_constraint[i];
120     u.argvIndex = static_cast<int>(i) + 1;
121   }
122 
123   auto out_qc_str = qc.ToNewSqlite3String();
124   if (SqliteTable::debug) {
125     PERFETTO_LOG(
126         "[%s::BestIndex] constraints=%s orderByConsumed=%d estimatedCost=%f "
127         "estimatedRows=%" PRId64,
128         name_.c_str(), out_qc_str.get(), idx->orderByConsumed,
129         idx->estimatedCost, static_cast<int64_t>(idx->estimatedRows));
130   }
131 
132   idx->idxStr = out_qc_str.release();
133   idx->needToFreeIdxStr = true;
134   idx->idxNum = ++best_index_num_;
135 
136   return SQLITE_OK;
137 }
138 
ModifyConstraints(QueryConstraints *)139 int SqliteTable::ModifyConstraints(QueryConstraints*) {
140   return SQLITE_OK;
141 }
142 
FindFunction(const char *,FindFunctionFn *,void **)143 int SqliteTable::FindFunction(const char*, FindFunctionFn*, void**) {
144   return 0;
145 }
146 
Update(int,sqlite3_value **,sqlite3_int64 *)147 int SqliteTable::Update(int, sqlite3_value**, sqlite3_int64*) {
148   return SQLITE_READONLY;
149 }
150 
ReadConstraints(int idxNum,const char * idxStr,int argc)151 bool SqliteTable::ReadConstraints(int idxNum, const char* idxStr, int argc) {
152   bool cache_hit = true;
153   if (idxNum != qc_hash_) {
154     qc_cache_ = QueryConstraints::FromString(idxStr);
155     qc_hash_ = idxNum;
156     cache_hit = false;
157   }
158 
159   // Logging this every ReadConstraints just leads to log spam on joins making
160   // it unusable. Instead, only print this out when we miss the cache (which
161   // happens precisely when the constraint set from SQLite changes.)
162   if (SqliteTable::debug && !cache_hit) {
163     PERFETTO_LOG("[%s::ParseConstraints] constraints=%s argc=%d", name_.c_str(),
164                  idxStr, argc);
165   }
166   return cache_hit;
167 }
168 
Cursor(SqliteTable * table)169 SqliteTable::Cursor::Cursor(SqliteTable* table) : table_(table) {
170   // This is required to prevent us from leaving this field uninitialised if
171   // we ever move construct the Cursor.
172   pVtab = table;
173 }
174 SqliteTable::Cursor::~Cursor() = default;
175 
RowId(sqlite3_int64 *)176 int SqliteTable::Cursor::RowId(sqlite3_int64*) {
177   return SQLITE_ERROR;
178 }
179 
Column(size_t index,std::string name,SqlValue::Type type,bool hidden)180 SqliteTable::Column::Column(size_t index,
181                             std::string name,
182                             SqlValue::Type type,
183                             bool hidden)
184     : index_(index), name_(name), type_(type), hidden_(hidden) {}
185 
Schema(std::vector<Column> columns,std::vector<size_t> primary_keys)186 SqliteTable::Schema::Schema(std::vector<Column> columns,
187                             std::vector<size_t> primary_keys)
188     : columns_(std::move(columns)), primary_keys_(std::move(primary_keys)) {
189   for (size_t i = 0; i < columns_.size(); i++) {
190     PERFETTO_CHECK(columns_[i].index() == i);
191   }
192   for (auto key : primary_keys_) {
193     PERFETTO_CHECK(key < columns_.size());
194   }
195 }
196 
197 SqliteTable::Schema::Schema() = default;
198 SqliteTable::Schema::Schema(const Schema&) = default;
199 SqliteTable::Schema& SqliteTable::Schema::operator=(const Schema&) = default;
200 
ToCreateTableStmt() const201 std::string SqliteTable::Schema::ToCreateTableStmt() const {
202   std::string stmt = "CREATE TABLE x(";
203   for (size_t i = 0; i < columns_.size(); ++i) {
204     const Column& col = columns_[i];
205     stmt += " " + col.name();
206 
207     if (col.type() != SqlValue::Type::kNull) {
208       stmt += " " + TypeToString(col.type());
209     } else if (std::find(primary_keys_.begin(), primary_keys_.end(), i) !=
210                primary_keys_.end()) {
211       PERFETTO_FATAL("Unknown type for primary key column %s",
212                      col.name().c_str());
213     }
214     if (col.hidden()) {
215       stmt += " HIDDEN";
216     }
217     stmt += ",";
218   }
219   stmt += " PRIMARY KEY(";
220   for (size_t i = 0; i < primary_keys_.size(); i++) {
221     if (i != 0)
222       stmt += ", ";
223     stmt += columns_[primary_keys_[i]].name();
224   }
225   stmt += ")) WITHOUT ROWID;";
226   return stmt;
227 }
228 
229 }  // namespace trace_processor
230 }  // namespace perfetto
231