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