• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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