• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 == "BOOL") {
35     return Type::kBool;
36   }
37   if (str == "INT") {
38     return Type::kInt;
39   }
40   if (str == "UINT") {
41     return Type::kUint;
42   }
43   if (str == "LONG") {
44     return Type::kLong;
45   }
46   if (str == "FLOAT") {
47     return Type::kFloat;
48   }
49   if (str == "DOUBLE") {
50     return Type::kDouble;
51   }
52   if (str == "STRING") {
53     return Type::kString;
54   }
55   if (str == "PROTO") {
56     return Type::kProto;
57   }
58   if (str == "BYTES") {
59     return Type::kBytes;
60   }
61   return std::nullopt;
62 }
63 
TypeToHumanFriendlyString(sql_argument::Type type)64 const char* TypeToHumanFriendlyString(sql_argument::Type type) {
65   using Type = sql_argument::Type;
66   switch (type) {
67     case Type::kBool:
68       return "BOOL";
69     case Type::kInt:
70       return "INT";
71     case Type::kUint:
72       return "UINT";
73     case Type::kLong:
74       return "LONG";
75     case Type::kFloat:
76       return "FLOAT";
77     case Type::kDouble:
78       return "DOUBLE";
79     case Type::kString:
80       return "STRING";
81     case Type::kProto:
82       return "PROTO";
83     case Type::kBytes:
84       return "BYTES";
85   }
86   PERFETTO_FATAL("For GCC");
87 }
88 
TypeToSqlValueType(sql_argument::Type type)89 SqlValue::Type TypeToSqlValueType(sql_argument::Type type) {
90   using Type = sql_argument::Type;
91   switch (type) {
92     case Type::kBool:
93     case Type::kInt:
94     case Type::kUint:
95     case Type::kLong:
96       return SqlValue::kLong;
97     case Type::kFloat:
98     case Type::kDouble:
99       return SqlValue::kDouble;
100     case Type::kString:
101       return SqlValue::kString;
102     case Type::kProto:
103     case Type::kBytes:
104       return SqlValue::kBytes;
105   }
106   PERFETTO_FATAL("For GCC");
107 }
108 
ParseArgumentDefinitions(const std::string & args,std::vector<ArgumentDefinition> & out)109 base::Status ParseArgumentDefinitions(const std::string& args,
110                                       std::vector<ArgumentDefinition>& out) {
111   std::string trimmed_args = base::TrimWhitespace(args);
112   for (const auto& arg : base::SplitString(trimmed_args, ",")) {
113     const auto& arg_name_and_type =
114         (base::SplitString(base::TrimWhitespace(arg), " "));
115     if (arg_name_and_type.size() != 2) {
116       return base::ErrStatus(
117           "argument '%s' in function prototype should be of the form `name "
118           "TYPE`",
119           arg.c_str());
120     }
121 
122     const auto& arg_name = arg_name_and_type[0];
123     const auto& arg_type_str = arg_name_and_type[1];
124     if (!IsValidName(base::StringView(arg_name)))
125       return base::ErrStatus("argument '%s' is not alphanumeric", arg.c_str());
126 
127     auto opt_arg_type = ParseType(base::StringView(arg_type_str));
128     if (!opt_arg_type) {
129       return base::ErrStatus("unknown argument type in argument '%s'",
130                              arg.c_str());
131     }
132     out.emplace_back("$" + arg_name, *opt_arg_type);
133   }
134   return base::OkStatus();
135 }
136 
SerializeArguments(const std::vector<ArgumentDefinition> & args)137 std::string SerializeArguments(const std::vector<ArgumentDefinition>& args) {
138   bool comma = false;
139   std::string serialized;
140   for (const auto& arg : args) {
141     if (comma) {
142       serialized.append(", ");
143     }
144     comma = true;
145     serialized.append(arg.name().c_str());
146     serialized.push_back(' ');
147     serialized.append(TypeToHumanFriendlyString(arg.type()));
148   }
149   return serialized;
150 }
151 
152 }  // namespace sql_argument
153 }  // namespace trace_processor
154 }  // namespace perfetto
155