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 auto pred = [](char c) { return !(isalnum(c) || c == '_'); };
27 return std::find_if(str.begin(), str.end(), pred) == str.end();
28 }
29
ParseType(base::StringView str)30 std::optional<Type> ParseType(base::StringView str) {
31 if (str == "BOOL") {
32 return Type::kBool;
33 } else if (str == "INT") {
34 return Type::kInt;
35 } else if (str == "UINT") {
36 return Type::kUint;
37 } else if (str == "LONG") {
38 return Type::kLong;
39 } else if (str == "FLOAT") {
40 return Type::kFloat;
41 } else if (str == "DOUBLE") {
42 return Type::kDouble;
43 } else if (str == "STRING") {
44 return Type::kString;
45 } else if (str == "PROTO") {
46 return Type::kProto;
47 } else if (str == "BYTES") {
48 return Type::kBytes;
49 }
50 return std::nullopt;
51 }
52
TypeToHumanFriendlyString(sql_argument::Type type)53 const char* TypeToHumanFriendlyString(sql_argument::Type type) {
54 using Type = sql_argument::Type;
55 switch (type) {
56 case Type::kBool:
57 return "BOOL";
58 case Type::kInt:
59 return "INT";
60 case Type::kUint:
61 return "UINT";
62 case Type::kLong:
63 return "LONG";
64 case Type::kFloat:
65 return "FLOAT";
66 case Type::kDouble:
67 return "DOUBLE";
68 case Type::kString:
69 return "STRING";
70 case Type::kProto:
71 return "PROTO";
72 case Type::kBytes:
73 return "BYTES";
74 }
75 PERFETTO_FATAL("For GCC");
76 }
77
TypeToSqlValueType(sql_argument::Type type)78 SqlValue::Type TypeToSqlValueType(sql_argument::Type type) {
79 using Type = sql_argument::Type;
80 switch (type) {
81 case Type::kBool:
82 case Type::kInt:
83 case Type::kUint:
84 case Type::kLong:
85 return SqlValue::kLong;
86 case Type::kFloat:
87 case Type::kDouble:
88 return SqlValue::kDouble;
89 case Type::kString:
90 return SqlValue::kString;
91 case Type::kProto:
92 case Type::kBytes:
93 return SqlValue::kBytes;
94 }
95 PERFETTO_FATAL("For GCC");
96 }
97
ParseArgumentDefinitions(const std::string & args,std::vector<ArgumentDefinition> & out)98 base::Status ParseArgumentDefinitions(const std::string& args,
99 std::vector<ArgumentDefinition>& out) {
100 std::string trimmed_args = base::TrimWhitespace(args);
101 for (const auto& arg : base::SplitString(trimmed_args, ",")) {
102 const auto& arg_name_and_type =
103 (base::SplitString(base::TrimWhitespace(arg), " "));
104 if (arg_name_and_type.size() != 2) {
105 return base::ErrStatus(
106 "argument '%s' in function prototype should be of the form `name "
107 "TYPE`",
108 arg.c_str());
109 }
110
111 const auto& arg_name = arg_name_and_type[0];
112 const auto& arg_type_str = arg_name_and_type[1];
113 if (!IsValidName(base::StringView(arg_name)))
114 return base::ErrStatus("argument '%s' is not alphanumeric", arg.c_str());
115
116 auto opt_arg_type = ParseType(base::StringView(arg_type_str));
117 if (!opt_arg_type) {
118 return base::ErrStatus("unknown argument type in argument '%s'",
119 arg.c_str());
120 }
121 out.emplace_back("$" + arg_name, *opt_arg_type);
122 }
123 return base::OkStatus();
124 }
125
126 } // namespace sql_argument
127 } // namespace trace_processor
128 } // namespace perfetto
129