1 /* 2 * Copyright (C) 2020 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #ifndef SRC_TRACE_PROCESSOR_ITERATOR_IMPL_H_ 18 #define SRC_TRACE_PROCESSOR_ITERATOR_IMPL_H_ 19 20 #include <sqlite3.h> 21 22 #include <memory> 23 #include <optional> 24 #include <vector> 25 26 #include "perfetto/base/build_config.h" 27 #include "perfetto/base/export.h" 28 #include "perfetto/trace_processor/basic_types.h" 29 #include "perfetto/trace_processor/iterator.h" 30 #include "perfetto/trace_processor/status.h" 31 #include "src/trace_processor/sqlite/scoped_db.h" 32 #include "src/trace_processor/sqlite/sqlite_utils.h" 33 34 namespace perfetto { 35 namespace trace_processor { 36 37 class TraceProcessorImpl; 38 39 class IteratorImpl { 40 public: 41 struct StmtMetadata { 42 uint32_t column_count = 0; 43 uint32_t statement_count = 0; 44 uint32_t statement_count_with_output = 0; 45 }; 46 47 IteratorImpl(TraceProcessorImpl* impl, 48 sqlite3* db, 49 base::Status, 50 ScopedStmt, 51 StmtMetadata, 52 uint32_t sql_stats_row); 53 ~IteratorImpl(); 54 55 IteratorImpl(IteratorImpl&) noexcept = delete; 56 IteratorImpl& operator=(IteratorImpl&) = delete; 57 58 IteratorImpl(IteratorImpl&&) noexcept = default; 59 IteratorImpl& operator=(IteratorImpl&&) = default; 60 61 // Methods called by the base Iterator class. Next()62 bool Next() { 63 PERFETTO_DCHECK(stmt_ || !status_.ok()); 64 65 if (!called_next_) { 66 // Delegate to the cc file to prevent trace_storage.h include in this 67 // file. 68 RecordFirstNextInSqlStats(); 69 called_next_ = true; 70 71 // In the past, we used to call sqlite3_step for the first time in this 72 // function which 1:1 matched Next calls to sqlite3_step calls. However, 73 // with the introduction of multi-statement support, we call 74 // sqlite3_step when tokenizing the queries and so we need to *not* call 75 // step the first time Next is called. 76 // 77 // Aside: if we could, we would change the API to match the new setup 78 // (i.e. implement operator bool, make Next return nothing similar to C++ 79 // iterators); however, too many clients depend on the current behavior so 80 // we have to keep the API as is. 81 return status_.ok() && !sqlite_utils::IsStmtDone(*stmt_); 82 } 83 84 if (!status_.ok()) 85 return false; 86 87 int ret = sqlite3_step(*stmt_); 88 if (PERFETTO_UNLIKELY(ret != SQLITE_ROW && ret != SQLITE_DONE)) { 89 status_ = base::ErrStatus("%s", sqlite_utils::FormatErrorMessage( 90 stmt_.get(), std::nullopt, db_, ret) 91 .c_message()); 92 stmt_.reset(); 93 return false; 94 } 95 return ret == SQLITE_ROW; 96 } 97 Get(uint32_t col)98 SqlValue Get(uint32_t col) { 99 auto column = static_cast<int>(col); 100 auto col_type = sqlite3_column_type(*stmt_, column); 101 SqlValue value; 102 switch (col_type) { 103 case SQLITE_INTEGER: 104 value.type = SqlValue::kLong; 105 value.long_value = sqlite3_column_int64(*stmt_, column); 106 break; 107 case SQLITE_TEXT: 108 value.type = SqlValue::kString; 109 value.string_value = 110 reinterpret_cast<const char*>(sqlite3_column_text(*stmt_, column)); 111 break; 112 case SQLITE_FLOAT: 113 value.type = SqlValue::kDouble; 114 value.double_value = sqlite3_column_double(*stmt_, column); 115 break; 116 case SQLITE_BLOB: 117 value.type = SqlValue::kBytes; 118 value.bytes_value = sqlite3_column_blob(*stmt_, column); 119 value.bytes_count = 120 static_cast<size_t>(sqlite3_column_bytes(*stmt_, column)); 121 break; 122 case SQLITE_NULL: 123 value.type = SqlValue::kNull; 124 break; 125 } 126 return value; 127 } 128 GetColumnName(uint32_t col)129 std::string GetColumnName(uint32_t col) { 130 return stmt_ ? sqlite3_column_name(*stmt_, static_cast<int>(col)) : ""; 131 } 132 Status()133 base::Status Status() { return status_; } 134 ColumnCount()135 uint32_t ColumnCount() { return stmt_metadata_.column_count; } 136 StatementCount()137 uint32_t StatementCount() { return stmt_metadata_.statement_count; } 138 StatementCountWithOutput()139 uint32_t StatementCountWithOutput() { 140 return stmt_metadata_.statement_count_with_output; 141 } 142 143 private: 144 // Dummy function to pass to ScopedResource. DummyClose(TraceProcessorImpl *)145 static int DummyClose(TraceProcessorImpl*) { return 0; } 146 147 // Iterators hold onto an instance of TraceProcessor to track when the query 148 // ends in the sql stats table. As iterators are movable, we need to null out 149 // the TraceProcessor in the moved out iterator to avoid double recording 150 // query ends. We could manually define a move constructor instead, but given 151 // the error prone nature of keeping functions up to date, this seems like a 152 // nicer approach. 153 using ScopedTraceProcessor = 154 base::ScopedResource<TraceProcessorImpl*, &DummyClose, nullptr>; 155 156 void RecordFirstNextInSqlStats(); 157 158 ScopedTraceProcessor trace_processor_; 159 sqlite3* db_ = nullptr; 160 base::Status status_; 161 162 ScopedStmt stmt_; 163 StmtMetadata stmt_metadata_; 164 165 uint32_t sql_stats_row_ = 0; 166 bool called_next_ = false; 167 }; 168 169 } // namespace trace_processor 170 } // namespace perfetto 171 172 #endif // SRC_TRACE_PROCESSOR_ITERATOR_IMPL_H_ 173