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