blob: 9092cb77c076a4fd6d9c624a02baf7540c7581fe [file] [log] [blame]
/*
* Copyright (C) 2018 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/query_constraints.h"
#include <sqlite3.h>
#include <string>
#include "perfetto/base/string_splitter.h"
namespace perfetto {
namespace trace_processor {
QueryConstraints::QueryConstraints() = default;
QueryConstraints::~QueryConstraints() = default;
QueryConstraints::QueryConstraints(QueryConstraints&&) noexcept = default;
QueryConstraints& QueryConstraints::operator=(QueryConstraints&&) = default;
int QueryConstraints::FreeSqliteString(char* resource) {
sqlite3_free(resource);
return 0;
}
bool QueryConstraints::operator==(const QueryConstraints& other) const {
if ((other.constraints().size() != constraints().size()) ||
(other.order_by().size() != order_by().size())) {
return false;
}
for (size_t i = 0; i < constraints().size(); ++i) {
if ((constraints()[i].iColumn != other.constraints()[i].iColumn) ||
(constraints()[i].op != other.constraints()[i].op)) {
return false;
}
}
for (size_t i = 0; i < order_by().size(); ++i) {
if ((order_by()[i].iColumn != other.order_by()[i].iColumn) ||
(order_by()[i].desc != other.order_by()[i].desc)) {
return false;
}
}
return true;
}
void QueryConstraints::AddConstraint(int column, unsigned char op) {
Constraint c{};
c.iColumn = column;
c.op = op;
constraints_.emplace_back(c);
}
void QueryConstraints::AddOrderBy(int column, unsigned char desc) {
OrderBy ob{};
ob.iColumn = column;
ob.desc = desc;
order_by_.emplace_back(ob);
}
QueryConstraints::SqliteString QueryConstraints::ToNewSqlite3String() const {
std::string str_result;
str_result.reserve(512);
str_result.append("C");
str_result.append(std::to_string(constraints_.size()));
str_result.append(",");
for (const auto& cs : constraints_) {
str_result.append(std::to_string(cs.iColumn));
str_result.append(",");
str_result.append(std::to_string(cs.op));
str_result.append(",");
}
str_result.append("O");
str_result.append(std::to_string(order_by_.size()));
str_result.append(",");
for (const auto& ob : order_by_) {
str_result.append(std::to_string(ob.iColumn));
str_result.append(",");
str_result.append(std::to_string(ob.desc));
str_result.append(",");
}
// The last char is a "," so overwriting with the null terminator on purpose.
SqliteString result(
static_cast<char*>(sqlite3_malloc(static_cast<int>(str_result.size()))));
strncpy(result.get(), str_result.c_str(), str_result.size());
(*result)[str_result.size() - 1] = '\0';
return result;
}
QueryConstraints QueryConstraints::FromString(const char* idxStr) {
QueryConstraints qc;
base::StringSplitter splitter(std::string(idxStr), ',');
PERFETTO_CHECK(splitter.Next() && splitter.cur_token_size() > 1);
// The '+ 1' skips the letter 'C' in the first token.
long num_constraints = strtol(splitter.cur_token() + 1, nullptr, 10);
for (int i = 0; i < num_constraints; ++i) {
PERFETTO_CHECK(splitter.Next());
int col = static_cast<int>(strtol(splitter.cur_token(), nullptr, 10));
PERFETTO_CHECK(splitter.Next());
unsigned char op =
static_cast<unsigned char>(strtol(splitter.cur_token(), nullptr, 10));
qc.AddConstraint(col, op);
}
PERFETTO_CHECK(splitter.Next() && splitter.cur_token_size() > 1);
// The '+ 1' skips the letter 'O' in the current token.
long num_order_by = strtol(splitter.cur_token() + 1, nullptr, 10);
for (int i = 0; i < num_order_by; ++i) {
PERFETTO_CHECK(splitter.Next());
int col = static_cast<int>(strtol(splitter.cur_token(), nullptr, 10));
PERFETTO_CHECK(splitter.Next());
unsigned char desc =
static_cast<unsigned char>(strtol(splitter.cur_token(), nullptr, 10));
qc.AddOrderBy(col, desc);
}
PERFETTO_DCHECK(!splitter.Next());
return qc;
}
} // namespace trace_processor
} // namespace perfetto