1 /*
2 * Copyright (C) 2021 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/perfetto_sql/parser/function_util.h"
18
19 #include "perfetto/base/status.h"
20 #include "perfetto/ext/base/string_view.h"
21 #include "src/trace_processor/sqlite/sqlite_utils.h"
22 #include "src/trace_processor/util/status_macros.h"
23
24 namespace perfetto::trace_processor {
25
ToString() const26 std::string FunctionPrototype::ToString() const {
27 return function_name + "(" + SerializeArguments(arguments) + ")";
28 }
29
ParseFunctionName(base::StringView raw,base::StringView & out)30 base::Status ParseFunctionName(base::StringView raw, base::StringView& out) {
31 size_t function_name_end = raw.find('(');
32 if (function_name_end == base::StringView::npos)
33 return base::ErrStatus("unable to find bracket starting argument list");
34
35 base::StringView function_name = raw.substr(0, function_name_end);
36 if (!sql_argument::IsValidName(function_name)) {
37 return base::ErrStatus("function name %s is not alphanumeric",
38 function_name.ToStdString().c_str());
39 }
40 out = function_name;
41 return base::OkStatus();
42 }
43
ParsePrototype(base::StringView raw,FunctionPrototype & out)44 base::Status ParsePrototype(base::StringView raw, FunctionPrototype& out) {
45 // Examples of function prototypes:
46 // ANDROID_SDK_LEVEL()
47 // STARTUP_SLICE(dur_ns INT)
48 // FIND_NEXT_SLICE_WITH_NAME(ts INT, name STRING)
49
50 base::StringView function_name;
51 RETURN_IF_ERROR(ParseFunctionName(raw, function_name));
52
53 size_t function_name_end = function_name.size();
54 size_t args_start = function_name_end + 1;
55 size_t args_end = raw.find(')', args_start);
56 if (args_end == base::StringView::npos)
57 return base::ErrStatus("unable to find bracket ending argument list");
58
59 base::StringView args_str = raw.substr(args_start, args_end - args_start);
60 RETURN_IF_ERROR(sql_argument::ParseArgumentDefinitions(args_str.ToStdString(),
61 out.arguments));
62
63 out.function_name = function_name.ToStdString();
64 return base::OkStatus();
65 }
66
SqliteRetToStatus(sqlite3 * db,const std::string & function_name,int ret)67 base::Status SqliteRetToStatus(sqlite3* db,
68 const std::string& function_name,
69 int ret) {
70 if (ret != SQLITE_ROW && ret != SQLITE_DONE) {
71 return base::ErrStatus("%s: SQLite error while executing function body: %s",
72 function_name.c_str(), sqlite3_errmsg(db));
73 }
74 return base::OkStatus();
75 }
76
MaybeBindArgument(sqlite3_stmt * stmt,const std::string & function_name,const sql_argument::ArgumentDefinition & arg,sqlite3_value * value)77 base::Status MaybeBindArgument(sqlite3_stmt* stmt,
78 const std::string& function_name,
79 const sql_argument::ArgumentDefinition& arg,
80 sqlite3_value* value) {
81 int index = sqlite3_bind_parameter_index(stmt, arg.dollar_name().c_str());
82
83 // If the argument is not in the query, this just means its an unused
84 // argument which we can just ignore.
85 if (index == 0)
86 return base::Status();
87
88 int ret = sqlite3_bind_value(stmt, index, value);
89 if (ret != SQLITE_OK) {
90 return base::ErrStatus(
91 "%s: SQLite error while binding value to argument %s: %s",
92 function_name.c_str(), arg.name().c_str(),
93 sqlite3_errmsg(sqlite3_db_handle(stmt)));
94 }
95 return base::OkStatus();
96 }
97
MaybeBindIntArgument(sqlite3_stmt * stmt,const std::string & function_name,const sql_argument::ArgumentDefinition & arg,int64_t value)98 base::Status MaybeBindIntArgument(sqlite3_stmt* stmt,
99 const std::string& function_name,
100 const sql_argument::ArgumentDefinition& arg,
101 int64_t value) {
102 int index = sqlite3_bind_parameter_index(stmt, arg.dollar_name().c_str());
103
104 // If the argument is not in the query, this just means its an unused
105 // argument which we can just ignore.
106 if (index == 0)
107 return base::Status();
108
109 int ret = sqlite3_bind_int64(stmt, index, value);
110 if (ret != SQLITE_OK) {
111 return base::ErrStatus(
112 "%s: SQLite error while binding value to argument %s: %s",
113 function_name.c_str(), arg.name().c_str(),
114 sqlite3_errmsg(sqlite3_db_handle(stmt)));
115 }
116 return base::OkStatus();
117 }
118
119 } // namespace perfetto::trace_processor
120