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