xref: /aosp_15_r20/external/perfetto/src/trace_processor/util/sql_argument.cc (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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/util/sql_argument.h"
18 
19 #include "perfetto/ext/base/string_utils.h"
20 
21 namespace perfetto {
22 namespace trace_processor {
23 namespace sql_argument {
24 
IsValidName(base::StringView str)25 bool IsValidName(base::StringView str) {
26   if (str.empty()) {
27     return false;
28   }
29   auto pred = [](char c) { return !(isalnum(c) || c == '_'); };
30   return std::find_if(str.begin(), str.end(), pred) == str.end();
31 }
32 
ParseType(base::StringView str)33 std::optional<Type> ParseType(base::StringView str) {
34   if (str.CaseInsensitiveEq("bool")) {
35     return Type::kBool;
36   }
37   if (str.CaseInsensitiveOneOf(
38           {"long", "timestamp", "duration", "id", "joinid", "argsetid"})) {
39     return Type::kLong;
40   }
41   if (str.CaseInsensitiveEq("double")) {
42     return Type::kDouble;
43   }
44   if (str.CaseInsensitiveEq("string")) {
45     return Type::kString;
46   }
47   if (str.CaseInsensitiveEq("bytes")) {
48     return Type::kBytes;
49   }
50 
51   // Deprecated types.
52   // TODO(b/380259828): Remove.
53   if (str.CaseInsensitiveEq("int")) {
54     return Type::kInt;
55   }
56   if (str.CaseInsensitiveEq("uint")) {
57     return Type::kUint;
58   }
59   if (str.CaseInsensitiveEq("float")) {
60     return Type::kFloat;
61   }
62   if (str.CaseInsensitiveEq("proto")) {
63     return Type::kProto;
64   }
65   return std::nullopt;
66 }
67 
TypeToHumanFriendlyString(sql_argument::Type type)68 const char* TypeToHumanFriendlyString(sql_argument::Type type) {
69   using Type = sql_argument::Type;
70   switch (type) {
71     case Type::kBool:
72       return "BOOL";
73     case Type::kInt:
74       return "INT";
75     case Type::kUint:
76       return "UINT";
77     case Type::kLong:
78       return "LONG";
79     case Type::kFloat:
80       return "FLOAT";
81     case Type::kDouble:
82       return "DOUBLE";
83     case Type::kString:
84       return "STRING";
85     case Type::kProto:
86       return "PROTO";
87     case Type::kBytes:
88       return "BYTES";
89   }
90   PERFETTO_FATAL("For GCC");
91 }
92 
TypeToSqlValueType(sql_argument::Type type)93 SqlValue::Type TypeToSqlValueType(sql_argument::Type type) {
94   using Type = sql_argument::Type;
95   switch (type) {
96     case Type::kBool:
97     case Type::kInt:
98     case Type::kUint:
99     case Type::kLong:
100       return SqlValue::kLong;
101     case Type::kFloat:
102     case Type::kDouble:
103       return SqlValue::kDouble;
104     case Type::kString:
105       return SqlValue::kString;
106     case Type::kProto:
107     case Type::kBytes:
108       return SqlValue::kBytes;
109   }
110   PERFETTO_FATAL("For GCC");
111 }
112 
ParseArgumentDefinitions(const std::string & args,std::vector<ArgumentDefinition> & out)113 base::Status ParseArgumentDefinitions(const std::string& args,
114                                       std::vector<ArgumentDefinition>& out) {
115   std::string trimmed_args = base::TrimWhitespace(args);
116   for (const auto& arg : base::SplitString(trimmed_args, ",")) {
117     const auto& arg_name_and_type =
118         (base::SplitString(base::TrimWhitespace(arg), " "));
119     if (arg_name_and_type.size() != 2) {
120       return base::ErrStatus(
121           "argument '%s' in function prototype should be of the form `name "
122           "TYPE`",
123           arg.c_str());
124     }
125 
126     const auto& arg_name = arg_name_and_type[0];
127     const auto& arg_type_str = arg_name_and_type[1];
128     if (!IsValidName(base::StringView(arg_name)))
129       return base::ErrStatus("argument '%s' is not alphanumeric", arg.c_str());
130 
131     auto opt_arg_type = ParseType(base::StringView(arg_type_str));
132     if (!opt_arg_type) {
133       return base::ErrStatus("unknown argument type in argument '%s'",
134                              arg.c_str());
135     }
136     out.emplace_back("$" + arg_name, *opt_arg_type);
137   }
138   return base::OkStatus();
139 }
140 
SerializeArguments(const std::vector<ArgumentDefinition> & args)141 std::string SerializeArguments(const std::vector<ArgumentDefinition>& args) {
142   bool comma = false;
143   std::string serialized;
144   for (const auto& arg : args) {
145     if (comma) {
146       serialized.append(", ");
147     }
148     comma = true;
149     serialized.append(arg.name().c_str());
150     serialized.push_back(' ');
151     serialized.append(TypeToHumanFriendlyString(arg.type()));
152   }
153   return serialized;
154 }
155 
156 }  // namespace sql_argument
157 }  // namespace trace_processor
158 }  // namespace perfetto
159