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 #ifndef SRC_TRACE_PROCESSOR_SQLITE_SQLITE_UTILS_H_
18 #define SRC_TRACE_PROCESSOR_SQLITE_SQLITE_UTILS_H_
19
20 #include <math.h>
21 #include <sqlite3.h>
22
23 #include <functional>
24 #include <limits>
25 #include <string>
26
27 #include "perfetto/base/logging.h"
28 #include "perfetto/ext/base/optional.h"
29 #include "perfetto/ext/base/string_utils.h"
30 #include "src/trace_processor/sqlite/scoped_db.h"
31 #include "src/trace_processor/sqlite/sqlite_table.h"
32
33 namespace perfetto {
34 namespace trace_processor {
35 namespace sqlite_utils {
36
37 const auto kSqliteStatic = reinterpret_cast<sqlite3_destructor_type>(0);
38 const auto kSqliteTransient = reinterpret_cast<sqlite3_destructor_type>(-1);
39
40 template <typename T>
41 using is_numeric =
42 typename std::enable_if<std::is_arithmetic<T>::value, T>::type;
43
44 template <typename T>
45 using is_float =
46 typename std::enable_if<std::is_floating_point<T>::value, T>::type;
47
48 template <typename T>
49 using is_int = typename std::enable_if<std::is_integral<T>::value, T>::type;
50
IsOpEq(int op)51 inline bool IsOpEq(int op) {
52 return op == SQLITE_INDEX_CONSTRAINT_EQ;
53 }
54
IsOpGe(int op)55 inline bool IsOpGe(int op) {
56 return op == SQLITE_INDEX_CONSTRAINT_GE;
57 }
58
IsOpGt(int op)59 inline bool IsOpGt(int op) {
60 return op == SQLITE_INDEX_CONSTRAINT_GT;
61 }
62
IsOpLe(int op)63 inline bool IsOpLe(int op) {
64 return op == SQLITE_INDEX_CONSTRAINT_LE;
65 }
66
IsOpLt(int op)67 inline bool IsOpLt(int op) {
68 return op == SQLITE_INDEX_CONSTRAINT_LT;
69 }
70
IsOpIsNull(int op)71 inline bool IsOpIsNull(int op) {
72 return op == SQLITE_INDEX_CONSTRAINT_ISNULL;
73 }
74
IsOpIsNotNull(int op)75 inline bool IsOpIsNotNull(int op) {
76 return op == SQLITE_INDEX_CONSTRAINT_ISNOTNULL;
77 }
78
79 template <typename T>
80 T ExtractSqliteValue(sqlite3_value* value);
81
82 template <>
ExtractSqliteValue(sqlite3_value * value)83 inline uint8_t ExtractSqliteValue(sqlite3_value* value) {
84 auto type = sqlite3_value_type(value);
85 PERFETTO_DCHECK(type == SQLITE_INTEGER);
86 return static_cast<uint8_t>(sqlite3_value_int(value));
87 }
88
89 template <>
ExtractSqliteValue(sqlite3_value * value)90 inline uint32_t ExtractSqliteValue(sqlite3_value* value) {
91 auto type = sqlite3_value_type(value);
92 PERFETTO_DCHECK(type == SQLITE_INTEGER);
93 return static_cast<uint32_t>(sqlite3_value_int64(value));
94 }
95
96 template <>
ExtractSqliteValue(sqlite3_value * value)97 inline int32_t ExtractSqliteValue(sqlite3_value* value) {
98 auto type = sqlite3_value_type(value);
99 PERFETTO_DCHECK(type == SQLITE_INTEGER);
100 return sqlite3_value_int(value);
101 }
102
103 template <>
ExtractSqliteValue(sqlite3_value * value)104 inline int64_t ExtractSqliteValue(sqlite3_value* value) {
105 auto type = sqlite3_value_type(value);
106 PERFETTO_DCHECK(type == SQLITE_INTEGER);
107 return static_cast<int64_t>(sqlite3_value_int64(value));
108 }
109
110 template <>
ExtractSqliteValue(sqlite3_value * value)111 inline double ExtractSqliteValue(sqlite3_value* value) {
112 auto type = sqlite3_value_type(value);
113 PERFETTO_DCHECK(type == SQLITE_FLOAT || type == SQLITE_INTEGER);
114 return sqlite3_value_double(value);
115 }
116
117 template <>
ExtractSqliteValue(sqlite3_value * value)118 inline bool ExtractSqliteValue(sqlite3_value* value) {
119 auto type = sqlite3_value_type(value);
120 PERFETTO_DCHECK(type == SQLITE_INTEGER);
121 return static_cast<bool>(sqlite3_value_int(value));
122 }
123
124 // Do not add a uint64_t version of ExtractSqliteValue. You should not be using
125 // uint64_t at all given that SQLite doesn't support it.
126
127 template <>
ExtractSqliteValue(sqlite3_value * value)128 inline const char* ExtractSqliteValue(sqlite3_value* value) {
129 auto type = sqlite3_value_type(value);
130 PERFETTO_DCHECK(type == SQLITE_TEXT);
131 return reinterpret_cast<const char*>(sqlite3_value_text(value));
132 }
133
134 template <>
ExtractSqliteValue(sqlite3_value * value)135 inline std::string ExtractSqliteValue(sqlite3_value* value) {
136 return ExtractSqliteValue<const char*>(value);
137 }
138
139 template <typename T>
140 class NumericPredicate {
141 public:
NumericPredicate(int op,T constant)142 NumericPredicate(int op, T constant) : op_(op), constant_(constant) {}
143
operator()144 PERFETTO_ALWAYS_INLINE bool operator()(T other) const {
145 switch (op_) {
146 case SQLITE_INDEX_CONSTRAINT_ISNULL:
147 return false;
148 case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
149 return true;
150 case SQLITE_INDEX_CONSTRAINT_EQ:
151 case SQLITE_INDEX_CONSTRAINT_IS:
152 return std::equal_to<T>()(other, constant_);
153 case SQLITE_INDEX_CONSTRAINT_NE:
154 case SQLITE_INDEX_CONSTRAINT_ISNOT:
155 return std::not_equal_to<T>()(other, constant_);
156 case SQLITE_INDEX_CONSTRAINT_GE:
157 return std::greater_equal<T>()(other, constant_);
158 case SQLITE_INDEX_CONSTRAINT_GT:
159 return std::greater<T>()(other, constant_);
160 case SQLITE_INDEX_CONSTRAINT_LE:
161 return std::less_equal<T>()(other, constant_);
162 case SQLITE_INDEX_CONSTRAINT_LT:
163 return std::less<T>()(other, constant_);
164 default:
165 PERFETTO_FATAL("For GCC");
166 }
167 }
168
169 private:
170 int op_;
171 T constant_;
172 };
173
174 template <typename T, typename sqlite_utils::is_numeric<T>* = nullptr>
CreateNumericPredicate(int op,sqlite3_value * value)175 NumericPredicate<T> CreateNumericPredicate(int op, sqlite3_value* value) {
176 T extracted =
177 IsOpIsNull(op) || IsOpIsNotNull(op) ? 0 : ExtractSqliteValue<T>(value);
178 return NumericPredicate<T>(op, extracted);
179 }
180
CreateStringPredicate(int op,sqlite3_value * value)181 inline std::function<bool(const char*)> CreateStringPredicate(
182 int op,
183 sqlite3_value* value) {
184 switch (op) {
185 case SQLITE_INDEX_CONSTRAINT_ISNULL:
186 return [](const char* f) { return f == nullptr; };
187 case SQLITE_INDEX_CONSTRAINT_ISNOTNULL:
188 return [](const char* f) { return f != nullptr; };
189 }
190
191 const char* val = reinterpret_cast<const char*>(sqlite3_value_text(value));
192
193 // If the value compared against is null, then to stay consistent with SQL
194 // handling, we have to return false for non-null operators.
195 if (val == nullptr) {
196 PERFETTO_CHECK(op != SQLITE_INDEX_CONSTRAINT_IS &&
197 op != SQLITE_INDEX_CONSTRAINT_ISNOT);
198 return [](const char*) { return false; };
199 }
200
201 switch (op) {
202 case SQLITE_INDEX_CONSTRAINT_EQ:
203 case SQLITE_INDEX_CONSTRAINT_IS:
204 return [val](const char* str) {
205 return str != nullptr && strcmp(str, val) == 0;
206 };
207 case SQLITE_INDEX_CONSTRAINT_NE:
208 case SQLITE_INDEX_CONSTRAINT_ISNOT:
209 return [val](const char* str) {
210 return str != nullptr && strcmp(str, val) != 0;
211 };
212 case SQLITE_INDEX_CONSTRAINT_GE:
213 return [val](const char* str) {
214 return str != nullptr && strcmp(str, val) >= 0;
215 };
216 case SQLITE_INDEX_CONSTRAINT_GT:
217 return [val](const char* str) {
218 return str != nullptr && strcmp(str, val) > 0;
219 };
220 case SQLITE_INDEX_CONSTRAINT_LE:
221 return [val](const char* str) {
222 return str != nullptr && strcmp(str, val) <= 0;
223 };
224 case SQLITE_INDEX_CONSTRAINT_LT:
225 return [val](const char* str) {
226 return str != nullptr && strcmp(str, val) < 0;
227 };
228 case SQLITE_INDEX_CONSTRAINT_LIKE:
229 return [val](const char* str) {
230 return str != nullptr && sqlite3_strlike(val, str, 0) == 0;
231 };
232 case SQLITE_INDEX_CONSTRAINT_GLOB:
233 return [val](const char* str) {
234 return str != nullptr && sqlite3_strglob(val, str) == 0;
235 };
236 default:
237 PERFETTO_FATAL("For GCC");
238 }
239 }
240
241 // Greater bound for floating point numbers.
242 template <typename T, typename sqlite_utils::is_float<T>* = nullptr>
FindGtBound(bool is_eq,sqlite3_value * sqlite_val)243 T FindGtBound(bool is_eq, sqlite3_value* sqlite_val) {
244 constexpr auto kMax = static_cast<long double>(std::numeric_limits<T>::max());
245 auto type = sqlite3_value_type(sqlite_val);
246 if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) {
247 return kMax;
248 }
249
250 // If this is a strict gt bound then just get the next highest float
251 // after value.
252 auto value = ExtractSqliteValue<T>(sqlite_val);
253 return is_eq ? value : nexttoward(value, kMax);
254 }
255
256 template <typename T, typename sqlite_utils::is_int<T>* = nullptr>
FindGtBound(bool is_eq,sqlite3_value * sqlite_val)257 T FindGtBound(bool is_eq, sqlite3_value* sqlite_val) {
258 auto type = sqlite3_value_type(sqlite_val);
259 if (type == SQLITE_INTEGER) {
260 auto value = ExtractSqliteValue<T>(sqlite_val);
261 return is_eq ? value : value + 1;
262 } else if (type == SQLITE_FLOAT) {
263 auto value = ExtractSqliteValue<double>(sqlite_val);
264 auto above = ceil(value);
265 auto cast = static_cast<T>(above);
266 return value < above ? cast : (is_eq ? cast : cast + 1);
267 } else {
268 return std::numeric_limits<T>::max();
269 }
270 }
271
272 template <typename T, typename sqlite_utils::is_float<T>* = nullptr>
FindLtBound(bool is_eq,sqlite3_value * sqlite_val)273 T FindLtBound(bool is_eq, sqlite3_value* sqlite_val) {
274 constexpr auto kMin =
275 static_cast<long double>(std::numeric_limits<T>::lowest());
276 auto type = sqlite3_value_type(sqlite_val);
277 if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) {
278 return kMin;
279 }
280
281 // If this is a strict lt bound then just get the next lowest float
282 // before value.
283 auto value = ExtractSqliteValue<T>(sqlite_val);
284 return is_eq ? value : nexttoward(value, kMin);
285 }
286
287 template <typename T, typename sqlite_utils::is_int<T>* = nullptr>
FindLtBound(bool is_eq,sqlite3_value * sqlite_val)288 T FindLtBound(bool is_eq, sqlite3_value* sqlite_val) {
289 auto type = sqlite3_value_type(sqlite_val);
290 if (type == SQLITE_INTEGER) {
291 auto value = ExtractSqliteValue<T>(sqlite_val);
292 return is_eq ? value : value - 1;
293 } else if (type == SQLITE_FLOAT) {
294 auto value = ExtractSqliteValue<double>(sqlite_val);
295 auto below = floor(value);
296 auto cast = static_cast<T>(below);
297 return value > below ? cast : (is_eq ? cast : cast - 1);
298 } else {
299 return std::numeric_limits<T>::max();
300 }
301 }
302
303 template <typename T, typename sqlite_utils::is_float<T>* = nullptr>
FindEqBound(sqlite3_value * sqlite_val)304 T FindEqBound(sqlite3_value* sqlite_val) {
305 auto type = sqlite3_value_type(sqlite_val);
306 if (type != SQLITE_INTEGER && type != SQLITE_FLOAT) {
307 return std::numeric_limits<T>::max();
308 }
309 return ExtractSqliteValue<T>(sqlite_val);
310 }
311
312 template <typename T, typename sqlite_utils::is_int<T>* = nullptr>
FindEqBound(sqlite3_value * sqlite_val)313 T FindEqBound(sqlite3_value* sqlite_val) {
314 auto type = sqlite3_value_type(sqlite_val);
315 if (type == SQLITE_INTEGER) {
316 return ExtractSqliteValue<T>(sqlite_val);
317 } else if (type == SQLITE_FLOAT) {
318 auto value = ExtractSqliteValue<double>(sqlite_val);
319 auto below = floor(value);
320 auto cast = static_cast<T>(below);
321 return value > below ? std::numeric_limits<T>::max() : cast;
322 } else {
323 return std::numeric_limits<T>::max();
324 }
325 }
326
327 template <typename T>
328 void ReportSqliteResult(sqlite3_context*, T value);
329
330 // Do not add a uint64_t version of ReportSqliteResult. You should not be using
331 // uint64_t at all given that SQLite doesn't support it.
332
333 template <>
ReportSqliteResult(sqlite3_context * ctx,int32_t value)334 inline void ReportSqliteResult(sqlite3_context* ctx, int32_t value) {
335 sqlite3_result_int(ctx, value);
336 }
337
338 template <>
ReportSqliteResult(sqlite3_context * ctx,int64_t value)339 inline void ReportSqliteResult(sqlite3_context* ctx, int64_t value) {
340 sqlite3_result_int64(ctx, value);
341 }
342
343 template <>
ReportSqliteResult(sqlite3_context * ctx,uint8_t value)344 inline void ReportSqliteResult(sqlite3_context* ctx, uint8_t value) {
345 sqlite3_result_int(ctx, value);
346 }
347
348 template <>
ReportSqliteResult(sqlite3_context * ctx,uint32_t value)349 inline void ReportSqliteResult(sqlite3_context* ctx, uint32_t value) {
350 sqlite3_result_int64(ctx, value);
351 }
352
353 template <>
ReportSqliteResult(sqlite3_context * ctx,bool value)354 inline void ReportSqliteResult(sqlite3_context* ctx, bool value) {
355 sqlite3_result_int(ctx, value);
356 }
357
358 template <>
ReportSqliteResult(sqlite3_context * ctx,double value)359 inline void ReportSqliteResult(sqlite3_context* ctx, double value) {
360 sqlite3_result_double(ctx, value);
361 }
362
GetColumnsForTable(sqlite3 * db,const std::string & raw_table_name,std::vector<SqliteTable::Column> & columns)363 inline util::Status GetColumnsForTable(
364 sqlite3* db,
365 const std::string& raw_table_name,
366 std::vector<SqliteTable::Column>& columns) {
367 PERFETTO_DCHECK(columns.empty());
368 char sql[1024];
369 const char kRawSql[] = "SELECT name, type from pragma_table_info(\"%s\")";
370
371 // Support names which are table valued functions with arguments.
372 std::string table_name = raw_table_name.substr(0, raw_table_name.find('('));
373 int n = snprintf(sql, sizeof(sql), kRawSql, table_name.c_str());
374 PERFETTO_DCHECK(n >= 0 || static_cast<size_t>(n) < sizeof(sql));
375
376 sqlite3_stmt* raw_stmt = nullptr;
377 int err = sqlite3_prepare_v2(db, sql, n, &raw_stmt, nullptr);
378 if (err != SQLITE_OK) {
379 return util::ErrStatus("Preparing database failed");
380 }
381 ScopedStmt stmt(raw_stmt);
382 PERFETTO_DCHECK(sqlite3_column_count(*stmt) == 2);
383
384 for (;;) {
385 err = sqlite3_step(raw_stmt);
386 if (err == SQLITE_DONE)
387 break;
388 if (err != SQLITE_ROW) {
389 return util::ErrStatus("Querying schema of table %s failed",
390 raw_table_name.c_str());
391 }
392
393 const char* name =
394 reinterpret_cast<const char*>(sqlite3_column_text(*stmt, 0));
395 const char* raw_type =
396 reinterpret_cast<const char*>(sqlite3_column_text(*stmt, 1));
397 if (!name || !raw_type || !*name) {
398 return util::ErrStatus("Schema for %s has invalid column values",
399 raw_table_name.c_str());
400 }
401
402 SqlValue::Type type;
403 if (base::CaseInsensitiveEqual(raw_type, "STRING") ||
404 base::CaseInsensitiveEqual(raw_type, "TEXT")) {
405 type = SqlValue::Type::kString;
406 } else if (base::CaseInsensitiveEqual(raw_type, "DOUBLE")) {
407 type = SqlValue::Type::kDouble;
408 } else if (base::CaseInsensitiveEqual(raw_type, "BIG INT") ||
409 base::CaseInsensitiveEqual(raw_type, "UNSIGNED INT") ||
410 base::CaseInsensitiveEqual(raw_type, "INT") ||
411 base::CaseInsensitiveEqual(raw_type, "BOOLEAN")) {
412 type = SqlValue::Type::kLong;
413 } else if (!*raw_type) {
414 PERFETTO_DLOG("Unknown column type for %s %s", raw_table_name.c_str(),
415 name);
416 type = SqlValue::Type::kNull;
417 } else {
418 return util::ErrStatus("Unknown column type '%s' on table %s", raw_type,
419 raw_table_name.c_str());
420 }
421 columns.emplace_back(columns.size(), name, type);
422 }
423 return util::OkStatus();
424 }
425
426 template <typename T>
CompareValuesAsc(const T & f,const T & s)427 int CompareValuesAsc(const T& f, const T& s) {
428 return f < s ? -1 : (f > s ? 1 : 0);
429 }
430
431 template <typename T>
CompareValuesDesc(const T & f,const T & s)432 int CompareValuesDesc(const T& f, const T& s) {
433 return -CompareValuesAsc(f, s);
434 }
435
436 } // namespace sqlite_utils
437 } // namespace trace_processor
438 } // namespace perfetto
439
440 #endif // SRC_TRACE_PROCESSOR_SQLITE_SQLITE_UTILS_H_
441