1 /*
2 * Copyright (C) 2019 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/prelude/functions/create_function.h"
18
19 #include "perfetto/base/status.h"
20 #include "perfetto/trace_processor/basic_types.h"
21 #include "src/trace_processor/prelude/functions/create_function_internal.h"
22 #include "src/trace_processor/sqlite/scoped_db.h"
23 #include "src/trace_processor/sqlite/sqlite_engine.h"
24 #include "src/trace_processor/sqlite/sqlite_utils.h"
25 #include "src/trace_processor/tp_metatrace.h"
26 #include "src/trace_processor/util/status_macros.h"
27
28 namespace perfetto {
29 namespace trace_processor {
30
31 namespace {
32
33 struct CreatedFunction : public SqlFunction {
34 struct Context {
35 SqliteEngine* engine;
36 Prototype prototype;
37 sql_argument::Type return_type;
38 std::string sql;
39 ScopedStmt stmt;
40 };
41
42 static base::Status Run(Context* ctx,
43 size_t argc,
44 sqlite3_value** argv,
45 SqlValue& out,
46 Destructors&);
47 static base::Status VerifyPostConditions(Context*);
48 static void Cleanup(Context*);
49 };
50
Run(CreatedFunction::Context * ctx,size_t argc,sqlite3_value ** argv,SqlValue & out,Destructors &)51 base::Status CreatedFunction::Run(CreatedFunction::Context* ctx,
52 size_t argc,
53 sqlite3_value** argv,
54 SqlValue& out,
55 Destructors&) {
56 if (argc != ctx->prototype.arguments.size()) {
57 return base::ErrStatus(
58 "%s: invalid number of args; expected %zu, received %zu",
59 ctx->prototype.function_name.c_str(), ctx->prototype.arguments.size(),
60 argc);
61 }
62
63 // Type check all the arguments.
64 for (size_t i = 0; i < argc; ++i) {
65 sqlite3_value* arg = argv[i];
66 sql_argument::Type type = ctx->prototype.arguments[i].type();
67 base::Status status = sqlite_utils::TypeCheckSqliteValue(
68 arg, sql_argument::TypeToSqlValueType(type),
69 sql_argument::TypeToHumanFriendlyString(type));
70 if (!status.ok()) {
71 return base::ErrStatus("%s[arg=%s]: argument %zu %s",
72 ctx->prototype.function_name.c_str(),
73 sqlite3_value_text(arg), i, status.c_message());
74 }
75 }
76
77 PERFETTO_TP_TRACE(
78 metatrace::Category::FUNCTION, "CREATE_FUNCTION",
79 [ctx, argv](metatrace::Record* r) {
80 r->AddArg("Function", ctx->prototype.function_name.c_str());
81 for (uint32_t i = 0; i < ctx->prototype.arguments.size(); ++i) {
82 std::string key = "Arg " + std::to_string(i);
83 const char* value =
84 reinterpret_cast<const char*>(sqlite3_value_text(argv[i]));
85 r->AddArg(base::StringView(key),
86 value ? base::StringView(value) : base::StringView("NULL"));
87 }
88 });
89
90 // Bind all the arguments to the appropriate places in the function.
91 for (size_t i = 0; i < argc; ++i) {
92 RETURN_IF_ERROR(MaybeBindArgument(ctx->stmt.get(),
93 ctx->prototype.function_name,
94 ctx->prototype.arguments[i], argv[i]));
95 }
96
97 int ret = sqlite3_step(ctx->stmt.get());
98 RETURN_IF_ERROR(
99 SqliteRetToStatus(ctx->engine->db(), ctx->prototype.function_name, ret));
100 if (ret == SQLITE_DONE) {
101 // No return value means we just return don't set |out|.
102 return base::OkStatus();
103 }
104
105 PERFETTO_DCHECK(ret == SQLITE_ROW);
106 size_t col_count = static_cast<size_t>(sqlite3_column_count(ctx->stmt.get()));
107 if (col_count != 1) {
108 return base::ErrStatus(
109 "%s: SQL definition should only return one column: returned %zu "
110 "columns",
111 ctx->prototype.function_name.c_str(), col_count);
112 }
113
114 out = sqlite_utils::SqliteValueToSqlValue(
115 sqlite3_column_value(ctx->stmt.get(), 0));
116
117 // If we return a bytes type but have a null pointer, SQLite will convert this
118 // to an SQL null. However, for proto build functions, we actively want to
119 // distinguish between nulls and 0 byte strings. Therefore, change the value
120 // to an empty string.
121 if (out.type == SqlValue::kBytes && out.bytes_value == nullptr) {
122 PERFETTO_DCHECK(out.bytes_count == 0);
123 out.bytes_value = "";
124 }
125 return base::OkStatus();
126 }
127
VerifyPostConditions(Context * ctx)128 base::Status CreatedFunction::VerifyPostConditions(Context* ctx) {
129 int ret = sqlite3_step(ctx->stmt.get());
130 RETURN_IF_ERROR(
131 SqliteRetToStatus(ctx->engine->db(), ctx->prototype.function_name, ret));
132 if (ret == SQLITE_ROW) {
133 auto expanded_sql = sqlite_utils::ExpandedSqlForStmt(ctx->stmt.get());
134 return base::ErrStatus(
135 "%s: multiple values were returned when executing function body. "
136 "Executed SQL was %s",
137 ctx->prototype.function_name.c_str(), expanded_sql.get());
138 }
139 PERFETTO_DCHECK(ret == SQLITE_DONE);
140 return base::OkStatus();
141 }
142
Cleanup(CreatedFunction::Context * ctx)143 void CreatedFunction::Cleanup(CreatedFunction::Context* ctx) {
144 sqlite3_reset(ctx->stmt.get());
145 sqlite3_clear_bindings(ctx->stmt.get());
146 }
147
148 } // namespace
149
Run(SqliteEngine * engine,size_t argc,sqlite3_value ** argv,SqlValue &,Destructors &)150 base::Status CreateFunction::Run(SqliteEngine* engine,
151 size_t argc,
152 sqlite3_value** argv,
153 SqlValue&,
154 Destructors&) {
155 if (argc != 3) {
156 return base::ErrStatus(
157 "CREATE_FUNCTION: invalid number of args; expected %u, received %zu",
158 3u, argc);
159 }
160
161 sqlite3_value* prototype_value = argv[0];
162 sqlite3_value* return_type_value = argv[1];
163 sqlite3_value* sql_defn_value = argv[2];
164
165 // Type check all the arguments.
166 {
167 auto type_check = [prototype_value](sqlite3_value* value,
168 SqlValue::Type type, const char* desc) {
169 base::Status status = sqlite_utils::TypeCheckSqliteValue(value, type);
170 if (!status.ok()) {
171 return base::ErrStatus("CREATE_FUNCTION[prototype=%s]: %s %s",
172 sqlite3_value_text(prototype_value), desc,
173 status.c_message());
174 }
175 return base::OkStatus();
176 };
177
178 RETURN_IF_ERROR(type_check(prototype_value, SqlValue::Type::kString,
179 "function prototype (first argument)"));
180 RETURN_IF_ERROR(type_check(return_type_value, SqlValue::Type::kString,
181 "return type (second argument)"));
182 RETURN_IF_ERROR(type_check(sql_defn_value, SqlValue::Type::kString,
183 "SQL definition (third argument)"));
184 }
185
186 // Extract the arguments from the value wrappers.
187 auto extract_string = [](sqlite3_value* value) -> base::StringView {
188 return reinterpret_cast<const char*>(sqlite3_value_text(value));
189 };
190 base::StringView prototype_str = extract_string(prototype_value);
191 base::StringView return_type_str = extract_string(return_type_value);
192 std::string sql_defn_str = extract_string(sql_defn_value).ToStdString();
193
194 // Parse all the arguments into a more friendly form.
195 Prototype prototype;
196 base::Status status = ParsePrototype(prototype_str, prototype);
197 if (!status.ok()) {
198 return base::ErrStatus("CREATE_FUNCTION[prototype=%s]: %s",
199 prototype_str.ToStdString().c_str(),
200 status.c_message());
201 }
202
203 // Parse the return type into a enum format.
204 auto opt_return_type = sql_argument::ParseType(return_type_str);
205 if (!opt_return_type) {
206 return base::ErrStatus(
207 "CREATE_FUNCTION[prototype=%s, return=%s]: unknown return type "
208 "specified",
209 prototype_str.ToStdString().c_str(),
210 return_type_str.ToStdString().c_str());
211 }
212
213 int created_argc = static_cast<int>(prototype.arguments.size());
214 auto* fn_ctx =
215 engine->GetFunctionContext(prototype.function_name, created_argc);
216 if (fn_ctx) {
217 // If the function already exists, just verify that the prototype, return
218 // type and SQL matches exactly with what we already had registered. By
219 // doing this, we can avoid the problem plaguing C++ macros where macro
220 // ordering determines which one gets run.
221 auto* created_ctx = static_cast<CreatedFunction::Context*>(fn_ctx);
222 if (created_ctx->prototype != prototype) {
223 return base::ErrStatus(
224 "CREATE_FUNCTION[prototype=%s]: function prototype changed",
225 prototype_str.ToStdString().c_str());
226 }
227
228 if (created_ctx->return_type != *opt_return_type) {
229 return base::ErrStatus(
230 "CREATE_FUNCTION[prototype=%s]: return type changed from %s to %s",
231 prototype_str.ToStdString().c_str(),
232 sql_argument::TypeToHumanFriendlyString(created_ctx->return_type),
233 return_type_str.ToStdString().c_str());
234 }
235
236 if (created_ctx->sql != sql_defn_str) {
237 return base::ErrStatus(
238 "CREATE_FUNCTION[prototype=%s]: function SQL changed from %s to %s",
239 prototype_str.ToStdString().c_str(), created_ctx->sql.c_str(),
240 sql_defn_str.c_str());
241 }
242 return base::OkStatus();
243 }
244
245 // Prepare the SQL definition as a statement using SQLite.
246 ScopedStmt stmt;
247 sqlite3_stmt* stmt_raw = nullptr;
248 int ret = sqlite3_prepare_v2(engine->db(), sql_defn_str.data(),
249 static_cast<int>(sql_defn_str.size()), &stmt_raw,
250 nullptr);
251 if (ret != SQLITE_OK) {
252 return base::ErrStatus(
253 "CREATE_FUNCTION[prototype=%s]: SQLite error when preparing "
254 "statement %s",
255 prototype_str.ToStdString().c_str(),
256 sqlite_utils::FormatErrorMessage(
257 stmt_raw, base::StringView(sql_defn_str), engine->db(), ret)
258 .c_message());
259 }
260 stmt.reset(stmt_raw);
261
262 std::string function_name = prototype.function_name;
263 std::unique_ptr<CreatedFunction::Context> created_fn_ctx(
264 new CreatedFunction::Context{engine, std::move(prototype),
265 *opt_return_type, std::move(sql_defn_str),
266 std::move(stmt)});
267 RETURN_IF_ERROR(engine->RegisterSqlFunction<CreatedFunction>(
268 function_name.c_str(), created_argc, std::move(created_fn_ctx)));
269
270 // CREATE_FUNCTION doesn't have a return value so just don't sent |out|.
271 return base::OkStatus();
272 }
273
274 } // namespace trace_processor
275 } // namespace perfetto
276