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