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