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