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