/* * 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/sqlite/query_constraints.h" #include #include #include "perfetto/ext/base/string_splitter.h" #include "perfetto/ext/base/string_utils.h" namespace perfetto { namespace trace_processor { QueryConstraints::QueryConstraints(uint64_t cols_used) : cols_used_(cols_used) {} QueryConstraints::~QueryConstraints() = default; QueryConstraints::QueryConstraints(QueryConstraints&&) noexcept = default; QueryConstraints& QueryConstraints::operator=(QueryConstraints&&) noexcept = 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()) || other.cols_used() != cols_used()) { return false; } for (size_t i = 0; i < constraints().size(); ++i) { if ((constraints()[i].column != other.constraints()[i].column) || (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, int aconstraint_idx) { Constraint c{}; c.column = column; c.op = op; c.a_constraint_idx = aconstraint_idx; 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); // Add all the constraints. 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.column)); str_result.append(","); str_result.append(std::to_string(cs.op)); str_result.append(","); } str_result.back() = ';'; // Add all the clauses. 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(","); } str_result.back() = ';'; // Add the columns used. str_result.append("U"); str_result.append(std::to_string(cols_used_)); SqliteString result(static_cast( sqlite3_malloc(static_cast(str_result.size() + 1)))); base::StringCopy(result.get(), str_result.c_str(), str_result.size() + 1); return result; } QueryConstraints QueryConstraints::FromString(const char* idxStr) { QueryConstraints qc; base::StringSplitter outer_splitter(std::string(idxStr), ';'); // Handle the CONSTRAINT section of the string. PERFETTO_CHECK(outer_splitter.Next() && outer_splitter.cur_token_size() > 1); { base::StringSplitter splitter(&outer_splitter, ','); PERFETTO_CHECK(splitter.Next() && splitter.cur_token_size() > 1); // The '[1]' skips the letter 'C' in the first token. int64_t num_constraints = *base::CStringToInt64(&splitter.cur_token()[1]); for (int i = 0; i < num_constraints; ++i) { PERFETTO_CHECK(splitter.Next()); int col = static_cast(*base::CStringToInt32(splitter.cur_token())); PERFETTO_CHECK(splitter.Next()); unsigned char op = static_cast( *base::CStringToUInt32(splitter.cur_token())); qc.AddConstraint(col, op, 0); } } // Handle the ORDER BY section of the string. PERFETTO_CHECK(outer_splitter.Next() && outer_splitter.cur_token_size() > 1); { base::StringSplitter splitter(&outer_splitter, ','); PERFETTO_CHECK(splitter.Next() && splitter.cur_token_size() > 1); // The '[1]' skips the letter 'O' in the current token. int64_t num_order_by = *base::CStringToInt64(&splitter.cur_token()[1]); for (int i = 0; i < num_order_by; ++i) { PERFETTO_CHECK(splitter.Next()); int col = static_cast(*base::CStringToInt32(splitter.cur_token())); PERFETTO_CHECK(splitter.Next()); unsigned char desc = static_cast( *base::CStringToUInt32(splitter.cur_token())); qc.AddOrderBy(col, desc); } } // Handle the COLS USED section of the string. PERFETTO_CHECK(outer_splitter.Next() && outer_splitter.cur_token_size() > 1); { // The '[1]' skips the letter 'U' in the current token. qc.cols_used_ = *base::CStringToUInt64(&outer_splitter.cur_token()[1]); } PERFETTO_DCHECK(!outer_splitter.Next()); return qc; } } // namespace trace_processor } // namespace perfetto