/* * 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/table.h" #include <ctype.h> #include <string.h> #include <algorithm> #include "perfetto/base/logging.h" namespace perfetto { namespace trace_processor { namespace { std::string TypeToString(Table::ColumnType type) { switch (type) { case Table::ColumnType::kString: return "STRING"; case Table::ColumnType::kUint: return "UNSIGNED INT"; case Table::ColumnType::kLong: return "BIG INT"; case Table::ColumnType::kInt: return "INT"; case Table::ColumnType::kDouble: return "DOUBLE"; case Table::ColumnType::kUnknown: PERFETTO_FATAL("Cannot map unknown column type"); } PERFETTO_FATAL("Not reached"); // For gcc } } // namespace // static bool Table::debug = false; Table::Table() = default; Table::~Table() = default; int Table::OpenInternal(sqlite3_vtab_cursor** ppCursor) { // Freed in xClose(). *ppCursor = static_cast<sqlite3_vtab_cursor*>(CreateCursor().release()); return SQLITE_OK; } int Table::BestIndexInternal(sqlite3_index_info* idx) { QueryConstraints query_constraints; for (int i = 0; i < idx->nOrderBy; i++) { int column = idx->aOrderBy[i].iColumn; bool desc = idx->aOrderBy[i].desc; query_constraints.AddOrderBy(column, desc); } for (int i = 0; i < idx->nConstraint; i++) { const auto& cs = idx->aConstraint[i]; if (!cs.usable) continue; query_constraints.AddConstraint(cs.iColumn, cs.op); // argvIndex is 1-based so use the current size of the vector. int argv_index = static_cast<int>(query_constraints.constraints().size()); idx->aConstraintUsage[i].argvIndex = argv_index; } BestIndexInfo info; info.omit.resize(query_constraints.constraints().size()); int ret = BestIndex(query_constraints, &info); if (Table::debug) { PERFETTO_LOG( "[%s::BestIndex] constraints=%s orderByConsumed=%d estimatedCost=%d", name_.c_str(), query_constraints.ToNewSqlite3String().get(), info.order_by_consumed, info.estimated_cost); } if (ret != SQLITE_OK) return ret; idx->orderByConsumed = info.order_by_consumed; idx->estimatedCost = info.estimated_cost; size_t j = 0; for (int i = 0; i < idx->nConstraint; i++) { const auto& cs = idx->aConstraint[i]; if (cs.usable) idx->aConstraintUsage[i].omit = info.omit[j++]; } if (!info.order_by_consumed) query_constraints.ClearOrderBy(); idx->idxStr = query_constraints.ToNewSqlite3String().release(); idx->needToFreeIdxStr = true; idx->idxNum = ++best_index_num_; return SQLITE_OK; } int Table::FindFunction(const char*, FindFunctionFn, void**) { return 0; } int Table::Update(int, sqlite3_value**, sqlite3_int64*) { return SQLITE_READONLY; } const QueryConstraints& Table::ParseConstraints(int idxNum, const char* idxStr, int argc) { bool cache_hit = true; if (idxNum != qc_hash_) { qc_cache_ = QueryConstraints::FromString(idxStr); qc_hash_ = idxNum; cache_hit = false; } if (Table::debug) { PERFETTO_LOG("[%s::ParseConstraints] constraints=%s argc=%d cache_hit=%d", name_.c_str(), idxStr, argc, cache_hit); } return qc_cache_; } Table::Cursor::Cursor(Table* table) : table_(table) { // This is required to prevent us from leaving this field uninitialised if // we ever move construct the Cursor. pVtab = table; } Table::Cursor::~Cursor() = default; int Table::Cursor::RowId(sqlite3_int64*) { return SQLITE_ERROR; } Table::Column::Column(size_t index, std::string name, ColumnType type, bool hidden) : index_(index), name_(name), type_(type), hidden_(hidden) {} Table::Schema::Schema(std::vector<Column> columns, std::vector<size_t> primary_keys) : columns_(std::move(columns)), primary_keys_(std::move(primary_keys)) { for (size_t i = 0; i < columns_.size(); i++) { PERFETTO_CHECK(columns_[i].index() == i); } for (auto key : primary_keys_) { PERFETTO_CHECK(key < columns_.size()); } } Table::Schema::Schema() = default; Table::Schema::Schema(const Schema&) = default; Table::Schema& Table::Schema::operator=(const Schema&) = default; std::string Table::Schema::ToCreateTableStmt() const { std::string stmt = "CREATE TABLE x("; for (size_t i = 0; i < columns_.size(); ++i) { const Column& col = columns_[i]; stmt += " " + col.name(); if (col.type() != ColumnType::kUnknown) { stmt += " " + TypeToString(col.type()); } else if (std::find(primary_keys_.begin(), primary_keys_.end(), i) != primary_keys_.end()) { PERFETTO_FATAL("Unknown type for primary key column %s", col.name().c_str()); } if (col.hidden()) { stmt += " HIDDEN"; } stmt += ","; } stmt += " PRIMARY KEY("; for (size_t i = 0; i < primary_keys_.size(); i++) { if (i != 0) stmt += ", "; stmt += columns_[primary_keys_[i]].name(); } stmt += ")) WITHOUT ROWID;"; return stmt; } } // namespace trace_processor } // namespace perfetto