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