blob: 14384c65adab31cd0da0a32cbcd085aeafd80891 [file] [log] [blame]
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "src/trace_processor/util/sql_argument.h"
#include "perfetto/ext/base/string_utils.h"
namespace perfetto {
namespace trace_processor {
namespace sql_argument {
bool IsValidName(base::StringView str) {
if (str.empty()) {
return false;
}
auto pred = [](char c) { return !(isalnum(c) || c == '_'); };
return std::find_if(str.begin(), str.end(), pred) == str.end();
}
std::optional<Type> ParseType(base::StringView str) {
if (str.CaseInsensitiveEq("bool")) {
return Type::kBool;
}
if (str.CaseInsensitiveEq("int")) {
return Type::kInt;
}
if (str.CaseInsensitiveEq("uint")) {
return Type::kUint;
}
if (str.CaseInsensitiveEq("long")) {
return Type::kLong;
}
if (str.CaseInsensitiveEq("float")) {
return Type::kFloat;
}
if (str.CaseInsensitiveEq("double")) {
return Type::kDouble;
}
if (str.CaseInsensitiveEq("string")) {
return Type::kString;
}
if (str.CaseInsensitiveEq("proto")) {
return Type::kProto;
}
if (str.CaseInsensitiveEq("bytes")) {
return Type::kBytes;
}
return std::nullopt;
}
const char* TypeToHumanFriendlyString(sql_argument::Type type) {
using Type = sql_argument::Type;
switch (type) {
case Type::kBool:
return "BOOL";
case Type::kInt:
return "INT";
case Type::kUint:
return "UINT";
case Type::kLong:
return "LONG";
case Type::kFloat:
return "FLOAT";
case Type::kDouble:
return "DOUBLE";
case Type::kString:
return "STRING";
case Type::kProto:
return "PROTO";
case Type::kBytes:
return "BYTES";
}
PERFETTO_FATAL("For GCC");
}
SqlValue::Type TypeToSqlValueType(sql_argument::Type type) {
using Type = sql_argument::Type;
switch (type) {
case Type::kBool:
case Type::kInt:
case Type::kUint:
case Type::kLong:
return SqlValue::kLong;
case Type::kFloat:
case Type::kDouble:
return SqlValue::kDouble;
case Type::kString:
return SqlValue::kString;
case Type::kProto:
case Type::kBytes:
return SqlValue::kBytes;
}
PERFETTO_FATAL("For GCC");
}
base::Status ParseArgumentDefinitions(const std::string& args,
std::vector<ArgumentDefinition>& out) {
std::string trimmed_args = base::TrimWhitespace(args);
for (const auto& arg : base::SplitString(trimmed_args, ",")) {
const auto& arg_name_and_type =
(base::SplitString(base::TrimWhitespace(arg), " "));
if (arg_name_and_type.size() != 2) {
return base::ErrStatus(
"argument '%s' in function prototype should be of the form `name "
"TYPE`",
arg.c_str());
}
const auto& arg_name = arg_name_and_type[0];
const auto& arg_type_str = arg_name_and_type[1];
if (!IsValidName(base::StringView(arg_name)))
return base::ErrStatus("argument '%s' is not alphanumeric", arg.c_str());
auto opt_arg_type = ParseType(base::StringView(arg_type_str));
if (!opt_arg_type) {
return base::ErrStatus("unknown argument type in argument '%s'",
arg.c_str());
}
out.emplace_back("$" + arg_name, *opt_arg_type);
}
return base::OkStatus();
}
std::string SerializeArguments(const std::vector<ArgumentDefinition>& args) {
bool comma = false;
std::string serialized;
for (const auto& arg : args) {
if (comma) {
serialized.append(", ");
}
comma = true;
serialized.append(arg.name().c_str());
serialized.push_back(' ');
serialized.append(TypeToHumanFriendlyString(arg.type()));
}
return serialized;
}
} // namespace sql_argument
} // namespace trace_processor
} // namespace perfetto