Home | History | Annotate | Download | only in trace_processor
      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 
     50 inline bool IsOpEq(int op) {
     51   return op == SQLITE_INDEX_CONSTRAINT_EQ;
     52 }
     53 
     54 inline bool IsOpGe(int op) {
     55   return op == SQLITE_INDEX_CONSTRAINT_GE;
     56 }
     57 
     58 inline bool IsOpGt(int op) {
     59   return op == SQLITE_INDEX_CONSTRAINT_GT;
     60 }
     61 
     62 inline bool IsOpLe(int op) {
     63   return op == SQLITE_INDEX_CONSTRAINT_LE;
     64 }
     65 
     66 inline bool IsOpLt(int op) {
     67   return op == SQLITE_INDEX_CONSTRAINT_LT;
     68 }
     69 
     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 
     89 inline bool IsOpIsNull(int op) {
     90   return op == SQLITE_INDEX_CONSTRAINT_ISNULL;
     91 }
     92 
     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 <>
    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 <>
    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 <>
    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 <>
    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 <>
    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 <>
    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:
    150   NumericPredicate(int op, T constant) : op_(op), constant_(constant) {}
    151 
    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>
    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 
    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>
    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>
    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>
    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>
    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>
    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>
    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 <>
    342 inline void ReportSqliteResult(sqlite3_context* ctx, int32_t value) {
    343   sqlite3_result_int(ctx, value);
    344 }
    345 
    346 template <>
    347 inline void ReportSqliteResult(sqlite3_context* ctx, int64_t value) {
    348   sqlite3_result_int64(ctx, value);
    349 }
    350 
    351 template <>
    352 inline void ReportSqliteResult(sqlite3_context* ctx, uint8_t value) {
    353   sqlite3_result_int(ctx, value);
    354 }
    355 
    356 template <>
    357 inline void ReportSqliteResult(sqlite3_context* ctx, uint32_t value) {
    358   sqlite3_result_int64(ctx, value);
    359 }
    360 
    361 template <>
    362 inline void ReportSqliteResult(sqlite3_context* ctx, double value) {
    363   sqlite3_result_double(ctx, value);
    364 }
    365 
    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 
    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>
    444 int CompareValuesAsc(const T& f, const T& s) {
    445   return f < s ? -1 : (f > s ? 1 : 0);
    446 }
    447 
    448 template <typename T>
    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