• 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 "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