|  | /* | 
|  | * 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/stats_table.h" | 
|  |  | 
|  | #include "src/trace_processor/sqlite/sqlite_utils.h" | 
|  |  | 
|  | namespace perfetto { | 
|  | namespace trace_processor { | 
|  |  | 
|  | StatsTable::StatsTable(sqlite3*, const TraceStorage* storage) | 
|  | : storage_(storage) {} | 
|  |  | 
|  | void StatsTable::RegisterTable(sqlite3* db, const TraceStorage* storage) { | 
|  | SqliteTable::Register<StatsTable>(db, storage, "stats"); | 
|  | } | 
|  |  | 
|  | util::Status StatsTable::Init(int, const char* const*, Schema* schema) { | 
|  | *schema = Schema( | 
|  | { | 
|  | SqliteTable::Column(Column::kName, "name", SqlValue::Type::kString), | 
|  | // Calling a column "index" causes sqlite to silently fail, hence idx. | 
|  | SqliteTable::Column(Column::kIndex, "idx", SqlValue::Type::kLong), | 
|  | SqliteTable::Column(Column::kSeverity, "severity", | 
|  | SqlValue::Type::kString), | 
|  | SqliteTable::Column(Column::kSource, "source", | 
|  | SqlValue::Type::kString), | 
|  | SqliteTable::Column(Column::kValue, "value", SqlValue::Type::kLong), | 
|  | SqliteTable::Column(Column::kDescription, "description", | 
|  | SqlValue::Type::kString), | 
|  | }, | 
|  | {Column::kName}); | 
|  | return util::OkStatus(); | 
|  | } | 
|  |  | 
|  | std::unique_ptr<SqliteTable::Cursor> StatsTable::CreateCursor() { | 
|  | return std::unique_ptr<SqliteTable::Cursor>(new Cursor(this)); | 
|  | } | 
|  |  | 
|  | int StatsTable::BestIndex(const QueryConstraints&, BestIndexInfo*) { | 
|  | return SQLITE_OK; | 
|  | } | 
|  |  | 
|  | StatsTable::Cursor::Cursor(StatsTable* table) | 
|  | : SqliteTable::Cursor(table), table_(table), storage_(table->storage_) {} | 
|  |  | 
|  | int StatsTable::Cursor::Filter(const QueryConstraints&, | 
|  | sqlite3_value**, | 
|  | FilterHistory) { | 
|  | *this = Cursor(table_); | 
|  | return SQLITE_OK; | 
|  | } | 
|  |  | 
|  | int StatsTable::Cursor::Column(sqlite3_context* ctx, int N) { | 
|  | const auto kSqliteStatic = sqlite_utils::kSqliteStatic; | 
|  | switch (N) { | 
|  | case Column::kName: | 
|  | sqlite3_result_text(ctx, stats::kNames[key_], -1, kSqliteStatic); | 
|  | break; | 
|  | case Column::kIndex: | 
|  | if (stats::kTypes[key_] == stats::kIndexed) { | 
|  | sqlite3_result_int(ctx, index_->first); | 
|  | } else { | 
|  | sqlite3_result_null(ctx); | 
|  | } | 
|  | break; | 
|  | case Column::kSeverity: | 
|  | switch (stats::kSeverities[key_]) { | 
|  | case stats::kInfo: | 
|  | sqlite3_result_text(ctx, "info", -1, kSqliteStatic); | 
|  | break; | 
|  | case stats::kDataLoss: | 
|  | sqlite3_result_text(ctx, "data_loss", -1, kSqliteStatic); | 
|  | break; | 
|  | case stats::kError: | 
|  | sqlite3_result_text(ctx, "error", -1, kSqliteStatic); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case Column::kSource: | 
|  | switch (stats::kSources[key_]) { | 
|  | case stats::kTrace: | 
|  | sqlite3_result_text(ctx, "trace", -1, kSqliteStatic); | 
|  | break; | 
|  | case stats::kAnalysis: | 
|  | sqlite3_result_text(ctx, "analysis", -1, kSqliteStatic); | 
|  | break; | 
|  | } | 
|  | break; | 
|  | case Column::kValue: | 
|  | if (stats::kTypes[key_] == stats::kIndexed) { | 
|  | sqlite3_result_int64(ctx, index_->second); | 
|  | } else { | 
|  | sqlite3_result_int64(ctx, storage_->stats()[key_].value); | 
|  | } | 
|  | break; | 
|  | case Column::kDescription: | 
|  | sqlite3_result_text(ctx, stats::kDescriptions[key_], -1, kSqliteStatic); | 
|  | break; | 
|  | default: | 
|  | PERFETTO_FATAL("Unknown column %d", N); | 
|  | break; | 
|  | } | 
|  | return SQLITE_OK; | 
|  | } | 
|  |  | 
|  | int StatsTable::Cursor::Next() { | 
|  | static_assert(stats::kTypes[0] == stats::kSingle, | 
|  | "the first stats entry cannot be indexed"); | 
|  | const auto* cur_entry = &storage_->stats()[key_]; | 
|  | if (stats::kTypes[key_] == stats::kIndexed) { | 
|  | if (++index_ != cur_entry->indexed_values.end()) { | 
|  | return SQLITE_OK; | 
|  | } | 
|  | } | 
|  | while (++key_ < stats::kNumKeys) { | 
|  | cur_entry = &storage_->stats()[key_]; | 
|  | index_ = cur_entry->indexed_values.begin(); | 
|  | if (stats::kTypes[key_] == stats::kSingle || | 
|  | !cur_entry->indexed_values.empty()) { | 
|  | break; | 
|  | } | 
|  | } | 
|  | return SQLITE_OK; | 
|  | } | 
|  |  | 
|  | int StatsTable::Cursor::Eof() { | 
|  | return key_ >= stats::kNumKeys; | 
|  | } | 
|  |  | 
|  | }  // namespace trace_processor | 
|  | }  // namespace perfetto |