xref: /aosp_15_r20/external/perfetto/src/trace_processor/sqlite/sqlite_utils.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
1 /*
2  * Copyright (C) 2022 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 #include "src/trace_processor/sqlite/sqlite_utils.h"
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <limits>
22 #include <optional>
23 #include <sstream>
24 #include <string>
25 #include <utility>
26 #include <vector>
27 
28 #include "perfetto/base/logging.h"
29 #include "perfetto/base/status.h"
30 #include "perfetto/ext/base/status_or.h"
31 #include "perfetto/ext/base/string_utils.h"
32 #include "perfetto/trace_processor/basic_types.h"
33 #include "src/trace_processor/sqlite/scoped_db.h"
34 
35 namespace perfetto::trace_processor::sqlite::utils {
36 namespace internal {
37 namespace {
ToExpectedTypesString(ExpectedTypesSet expected_types)38 std::string ToExpectedTypesString(ExpectedTypesSet expected_types) {
39   PERFETTO_CHECK(expected_types.any());
40   std::stringstream ss;
41   if (expected_types.count() > 1) {
42     ss << "any of ";
43   }
44 
45   bool add_separator = false;
46   for (size_t i = 0; i < expected_types.size(); ++i) {
47     if (expected_types[i]) {
48       ss << (add_separator ? ", " : "")
49          << SqliteTypeToFriendlyString(static_cast<SqlValue::Type>(i));
50       add_separator = true;
51     }
52   }
53 
54   return ss.str();
55 }
56 }  // namespace
57 
InvalidArgumentTypeError(const char * argument_name,size_t arg_index,SqlValue::Type actual_type,ExpectedTypesSet expected_types)58 base::Status InvalidArgumentTypeError(const char* argument_name,
59                                       size_t arg_index,
60                                       SqlValue::Type actual_type,
61                                       ExpectedTypesSet expected_types) {
62   return ToInvalidArgumentError(
63       argument_name, arg_index,
64       base::ErrStatus("does not have expected type. Expected %s but found %s",
65                       ToExpectedTypesString(expected_types).c_str(),
66                       SqliteTypeToFriendlyString(actual_type)));
67 }
68 
ExtractArgument(size_t argc,sqlite3_value ** argv,const char * argument_name,size_t arg_index,ExpectedTypesSet expected_types)69 base::StatusOr<SqlValue> ExtractArgument(size_t argc,
70                                          sqlite3_value** argv,
71                                          const char* argument_name,
72                                          size_t arg_index,
73                                          ExpectedTypesSet expected_types) {
74   if (arg_index >= argc) {
75     return MissingArgumentError(argument_name);
76   }
77 
78   SqlValue value = sqlite::utils::SqliteValueToSqlValue(argv[arg_index]);
79   if (!expected_types.test(value.type)) {
80     return InvalidArgumentTypeError(argument_name, arg_index, value.type,
81                                     expected_types);
82   }
83   return value;
84 }
85 }  // namespace internal
86 
SqliteValueToWString(sqlite3_value * value)87 std::wstring SqliteValueToWString(sqlite3_value* value) {
88   PERFETTO_CHECK(sqlite3_value_type(value) == SQLITE_TEXT);
89   int len = sqlite3_value_bytes16(value);
90   PERFETTO_CHECK(len >= 0);
91   size_t count = static_cast<size_t>(len) / sizeof(wchar_t);
92   return {reinterpret_cast<const wchar_t*>(sqlite3_value_text16(value)), count};
93 }
94 
GetColumnsForTable(sqlite3 * db,const std::string & raw_table_name,std::vector<std::pair<SqlValue::Type,std::string>> & columns)95 base::Status GetColumnsForTable(
96     sqlite3* db,
97     const std::string& raw_table_name,
98     std::vector<std::pair<SqlValue::Type, std::string>>& columns) {
99   PERFETTO_DCHECK(columns.empty());
100   char sql[1024];
101   const char kRawSql[] = "SELECT name, type from pragma_table_info(\"%s\")";
102 
103   // Support names which are table valued functions with arguments.
104   std::string table_name = raw_table_name.substr(0, raw_table_name.find('('));
105   size_t n = base::SprintfTrunc(sql, sizeof(sql), kRawSql, table_name.c_str());
106   PERFETTO_DCHECK(n > 0);
107 
108   sqlite3_stmt* raw_stmt = nullptr;
109   int err =
110       sqlite3_prepare_v2(db, sql, static_cast<int>(n), &raw_stmt, nullptr);
111   if (err != SQLITE_OK) {
112     return base::ErrStatus("Preparing database failed");
113   }
114   ScopedStmt stmt(raw_stmt);
115   PERFETTO_DCHECK(sqlite3_column_count(*stmt) == 2);
116 
117   for (;;) {
118     err = sqlite3_step(raw_stmt);
119     if (err == SQLITE_DONE)
120       break;
121     if (err != SQLITE_ROW) {
122       return base::ErrStatus("Querying schema of table %s failed",
123                              raw_table_name.c_str());
124     }
125 
126     const char* name =
127         reinterpret_cast<const char*>(sqlite3_column_text(*stmt, 0));
128     const char* raw_type =
129         reinterpret_cast<const char*>(sqlite3_column_text(*stmt, 1));
130     if (!name || !raw_type || !*name) {
131       return base::ErrStatus("Schema for %s has invalid column values",
132                              raw_table_name.c_str());
133     }
134 
135     SqlValue::Type type;
136     if (base::CaseInsensitiveEqual(raw_type, "STRING") ||
137         base::CaseInsensitiveEqual(raw_type, "TEXT")) {
138       type = SqlValue::Type::kString;
139     } else if (base::CaseInsensitiveEqual(raw_type, "DOUBLE")) {
140       type = SqlValue::Type::kDouble;
141     } else if (base::CaseInsensitiveEqual(raw_type, "BIG INT") ||
142                base::CaseInsensitiveEqual(raw_type, "BIGINT") ||
143                base::CaseInsensitiveEqual(raw_type, "UNSIGNED INT") ||
144                base::CaseInsensitiveEqual(raw_type, "INT") ||
145                base::CaseInsensitiveEqual(raw_type, "BOOLEAN") ||
146                base::CaseInsensitiveEqual(raw_type, "INTEGER")) {
147       type = SqlValue::Type::kLong;
148     } else if (base::CaseInsensitiveEqual(raw_type, "BLOB")) {
149       type = SqlValue::Type::kBytes;
150     } else if (!*raw_type) {
151       PERFETTO_DLOG("Unknown column type for %s %s", raw_table_name.c_str(),
152                     name);
153       type = SqlValue::Type::kNull;
154     } else {
155       return base::ErrStatus("Unknown column type '%s' on table %s", raw_type,
156                              raw_table_name.c_str());
157     }
158     columns.emplace_back(type, name);
159   }
160 
161   // Catch mis-spelt table names.
162   //
163   // A SELECT on pragma_table_info() returns no rows if the
164   // table that was queried is not present.
165   if (columns.empty()) {
166     return base::ErrStatus("Unknown table or view name '%s'",
167                            raw_table_name.c_str());
168   }
169 
170   return base::OkStatus();
171 }
172 
SqliteTypeToFriendlyString(SqlValue::Type type)173 const char* SqliteTypeToFriendlyString(SqlValue::Type type) {
174   switch (type) {
175     case SqlValue::Type::kNull:
176       return "NULL";
177     case SqlValue::Type::kLong:
178       return "BOOL/INT/UINT/LONG";
179     case SqlValue::Type::kDouble:
180       return "FLOAT/DOUBLE";
181     case SqlValue::Type::kString:
182       return "STRING";
183     case SqlValue::Type::kBytes:
184       return "BYTES/PROTO";
185   }
186   PERFETTO_FATAL("For GCC");
187 }
188 
CheckArgCount(const char * function_name,size_t argc,size_t expected_argc)189 base::Status CheckArgCount(const char* function_name,
190                            size_t argc,
191                            size_t expected_argc) {
192   if (argc == expected_argc) {
193     return base::OkStatus();
194   }
195   return base::ErrStatus("%s: expected %zu arguments, got %zu", function_name,
196                          expected_argc, argc);
197 }
198 
ExtractIntArg(const char * function_name,const char * arg_name,sqlite3_value * sql_value)199 base::StatusOr<int64_t> ExtractIntArg(const char* function_name,
200                                       const char* arg_name,
201                                       sqlite3_value* sql_value) {
202   SqlValue value = SqliteValueToSqlValue(sql_value);
203   std::optional<int64_t> result;
204 
205   base::Status status = ExtractFromSqlValue(value, result);
206   if (!status.ok()) {
207     return base::ErrStatus("%s(%s): %s", function_name, arg_name,
208                            status.message().c_str());
209   }
210   PERFETTO_CHECK(result);
211   return *result;
212 }
213 
ExtractDoubleArg(const char * function_name,const char * arg_name,sqlite3_value * sql_value)214 base::StatusOr<double> ExtractDoubleArg(const char* function_name,
215                                         const char* arg_name,
216                                         sqlite3_value* sql_value) {
217   SqlValue value = SqliteValueToSqlValue(sql_value);
218   std::optional<double> result;
219 
220   base::Status status = ExtractFromSqlValue(value, result);
221   if (!status.ok()) {
222     return base::ErrStatus("%s(%s): %s", function_name, arg_name,
223                            status.message().c_str());
224   }
225   PERFETTO_CHECK(result);
226   return *result;
227 }
228 
ExtractStringArg(const char * function_name,const char * arg_name,sqlite3_value * sql_value)229 base::StatusOr<std::string> ExtractStringArg(const char* function_name,
230                                              const char* arg_name,
231                                              sqlite3_value* sql_value) {
232   SqlValue value = SqliteValueToSqlValue(sql_value);
233   std::optional<const char*> result;
234 
235   base::Status status = ExtractFromSqlValue(value, result);
236   if (!status.ok()) {
237     return base::ErrStatus("%s(%s): %s", function_name, arg_name,
238                            status.message().c_str());
239   }
240   PERFETTO_CHECK(result);
241   return std::string(*result);
242 }
243 
TypeCheckSqliteValue(sqlite3_value * value,SqlValue::Type expected_type)244 base::Status TypeCheckSqliteValue(sqlite3_value* value,
245                                   SqlValue::Type expected_type) {
246   return TypeCheckSqliteValue(value, expected_type,
247                               SqliteTypeToFriendlyString(expected_type));
248 }
249 
TypeCheckSqliteValue(sqlite3_value * value,SqlValue::Type expected_type,const char * expected_type_str)250 base::Status TypeCheckSqliteValue(sqlite3_value* value,
251                                   SqlValue::Type expected_type,
252                                   const char* expected_type_str) {
253   SqlValue::Type actual_type =
254       sqlite::utils::SqliteTypeToSqlValueType(sqlite3_value_type(value));
255   if (actual_type != SqlValue::Type::kNull && actual_type != expected_type) {
256     return base::ErrStatus(
257         "does not have expected type: expected %s, actual %s",
258         expected_type_str, SqliteTypeToFriendlyString(actual_type));
259   }
260   return base::OkStatus();
261 }
262 
263 template <typename T>
ExtractFromSqlValueInt(const SqlValue & value,std::optional<T> & out)264 base::Status ExtractFromSqlValueInt(const SqlValue& value,
265                                     std::optional<T>& out) {
266   if (value.is_null()) {
267     out = std::nullopt;
268     return base::OkStatus();
269   }
270   if (value.type != SqlValue::kLong) {
271     return base::ErrStatus(
272         "value has type %s which does not match the expected type %s",
273         SqliteTypeToFriendlyString(value.type),
274         SqliteTypeToFriendlyString(SqlValue::kLong));
275   }
276 
277   int64_t res = value.AsLong();
278   if (res > std::numeric_limits<T>::max() ||
279       res < std::numeric_limits<T>::min()) {
280     return base::ErrStatus("value %ld does not fit inside the range [%ld, %ld]",
281                            static_cast<long>(res),
282                            static_cast<long>(std::numeric_limits<T>::min()),
283                            static_cast<long>(std::numeric_limits<T>::max()));
284   }
285   out = static_cast<T>(res);
286   return base::OkStatus();
287 }
288 
ExtractFromSqlValue(const SqlValue & value,std::optional<int64_t> & out)289 base::Status ExtractFromSqlValue(const SqlValue& value,
290                                  std::optional<int64_t>& out) {
291   return ExtractFromSqlValueInt(value, out);
292 }
ExtractFromSqlValue(const SqlValue & value,std::optional<int32_t> & out)293 base::Status ExtractFromSqlValue(const SqlValue& value,
294                                  std::optional<int32_t>& out) {
295   return ExtractFromSqlValueInt(value, out);
296 }
ExtractFromSqlValue(const SqlValue & value,std::optional<uint32_t> & out)297 base::Status ExtractFromSqlValue(const SqlValue& value,
298                                  std::optional<uint32_t>& out) {
299   return ExtractFromSqlValueInt(value, out);
300 }
ExtractFromSqlValue(const SqlValue & value,std::optional<double> & out)301 base::Status ExtractFromSqlValue(const SqlValue& value,
302                                  std::optional<double>& out) {
303   if (value.is_null()) {
304     out = std::nullopt;
305     return base::OkStatus();
306   }
307   if (value.type != SqlValue::kDouble) {
308     return base::ErrStatus(
309         "value has type %s which does not match the expected type %s",
310         SqliteTypeToFriendlyString(value.type),
311         SqliteTypeToFriendlyString(SqlValue::kDouble));
312   }
313   out = value.AsDouble();
314   return base::OkStatus();
315 }
ExtractFromSqlValue(const SqlValue & value,std::optional<const char * > & out)316 base::Status ExtractFromSqlValue(const SqlValue& value,
317                                  std::optional<const char*>& out) {
318   if (value.is_null()) {
319     out = std::nullopt;
320     return base::OkStatus();
321   }
322   if (value.type != SqlValue::kString) {
323     return base::ErrStatus(
324         "value has type %s which does not match the expected type %s",
325         SqliteTypeToFriendlyString(value.type),
326         SqliteTypeToFriendlyString(SqlValue::kString));
327   }
328   out = value.AsString();
329   return base::OkStatus();
330 }
331 
MissingArgumentError(const char * argument_name)332 base::Status MissingArgumentError(const char* argument_name) {
333   return base::ErrStatus("argument missing: %s", argument_name);
334 }
335 
ToInvalidArgumentError(const char * argument_name,size_t arg_index,const base::Status & error)336 base::Status ToInvalidArgumentError(const char* argument_name,
337                                     size_t arg_index,
338                                     const base::Status& error) {
339   return base::ErrStatus("argument %s at pos %zu: %s", argument_name,
340                          arg_index + 1, error.message().c_str());
341 }
342 
343 }  // namespace perfetto::trace_processor::sqlite::utils
344