| /* | 
 |  * 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 "perfetto/base/status.h" | 
 | #include "src/trace_processor/sqlite/sqlite_utils.h" | 
 |  | 
 | namespace perfetto { | 
 | namespace trace_processor { | 
 |  | 
 | StatsTable::StatsTable(sqlite3*, const TraceStorage* storage) | 
 |     : storage_(storage) {} | 
 |  | 
 | StatsTable::~StatsTable() = default; | 
 |  | 
 | 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::BaseCursor> StatsTable::CreateCursor() { | 
 |   return std::unique_ptr<SqliteTable::BaseCursor>(new Cursor(this)); | 
 | } | 
 |  | 
 | int StatsTable::BestIndex(const QueryConstraints&, BestIndexInfo*) { | 
 |   return SQLITE_OK; | 
 | } | 
 |  | 
 | StatsTable::Cursor::Cursor(StatsTable* table) | 
 |     : SqliteTable::BaseCursor(table), | 
 |       table_(table), | 
 |       storage_(table->storage_) {} | 
 |  | 
 | StatsTable::Cursor::~Cursor() = default; | 
 |  | 
 | base::Status StatsTable::Cursor::Filter(const QueryConstraints&, | 
 |                                         sqlite3_value**, | 
 |                                         FilterHistory) { | 
 |   *this = Cursor(table_); | 
 |   return base::OkStatus(); | 
 | } | 
 |  | 
 | base::Status 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 base::OkStatus(); | 
 | } | 
 |  | 
 | base::Status 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 base::OkStatus(); | 
 |     } | 
 |   } | 
 |   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 base::OkStatus(); | 
 | } | 
 |  | 
 | bool StatsTable::Cursor::Eof() { | 
 |   return key_ >= stats::kNumKeys; | 
 | } | 
 |  | 
 | }  // namespace trace_processor | 
 | }  // namespace perfetto |