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