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 
32 namespace perfetto {
33 namespace trace_processor {
34 
35 class TraceProcessorImpl;
36 
37 class IteratorImpl {
38  public:
39   IteratorImpl(TraceProcessorImpl* impl,
40                sqlite3* db,
41                ScopedStmt,
42                uint32_t column_count,
43                util::Status,
44                uint32_t sql_stats_row);
45   ~IteratorImpl();
46 
47   IteratorImpl(IteratorImpl&) noexcept = delete;
48   IteratorImpl& operator=(IteratorImpl&) = delete;
49 
50   IteratorImpl(IteratorImpl&&) noexcept = default;
51   IteratorImpl& operator=(IteratorImpl&&) = default;
52 
53   // Methods called by the base Iterator class.
Next()54   bool Next() {
55     // Delegate to the cc file to prevent trace_storage.h include in this file.
56     if (!called_next_) {
57       RecordFirstNextInSqlStats();
58       called_next_ = true;
59     }
60 
61     if (!status_.ok())
62       return false;
63 
64     int ret = sqlite3_step(*stmt_);
65     if (PERFETTO_UNLIKELY(ret != SQLITE_ROW && ret != SQLITE_DONE)) {
66       status_ = util::ErrStatus("%s", sqlite3_errmsg(db_));
67       return false;
68     }
69     return ret == SQLITE_ROW;
70   }
71 
Get(uint32_t col)72   SqlValue Get(uint32_t col) {
73     auto column = static_cast<int>(col);
74     auto col_type = sqlite3_column_type(*stmt_, column);
75     SqlValue value;
76     switch (col_type) {
77       case SQLITE_INTEGER:
78         value.type = SqlValue::kLong;
79         value.long_value = sqlite3_column_int64(*stmt_, column);
80         break;
81       case SQLITE_TEXT:
82         value.type = SqlValue::kString;
83         value.string_value =
84             reinterpret_cast<const char*>(sqlite3_column_text(*stmt_, column));
85         break;
86       case SQLITE_FLOAT:
87         value.type = SqlValue::kDouble;
88         value.double_value = sqlite3_column_double(*stmt_, column);
89         break;
90       case SQLITE_BLOB:
91         value.type = SqlValue::kBytes;
92         value.bytes_value = sqlite3_column_blob(*stmt_, column);
93         value.bytes_count =
94             static_cast<size_t>(sqlite3_column_bytes(*stmt_, column));
95         break;
96       case SQLITE_NULL:
97         value.type = SqlValue::kNull;
98         break;
99     }
100     return value;
101   }
102 
GetColumnName(uint32_t col)103   std::string GetColumnName(uint32_t col) {
104     return sqlite3_column_name(stmt_.get(), static_cast<int>(col));
105   }
106 
ColumnCount()107   uint32_t ColumnCount() { return column_count_; }
108 
Status()109   util::Status Status() { return status_; }
110 
111  private:
112   // Dummy function to pass to ScopedResource.
DummyClose(TraceProcessorImpl *)113   static int DummyClose(TraceProcessorImpl*) { return 0; }
114 
115   // Iterators hold onto an instance of TraceProcessor to track when the query
116   // ends in the sql stats table. As iterators are movable, we need to null out
117   // the TraceProcessor in the moved out iterator to avoid double recording
118   // query ends. We could manually define a move constructor instead, but given
119   // the error prone nature of keeping functions up to date, this seems like a
120   // nicer approach.
121   using ScopedTraceProcessor =
122       base::ScopedResource<TraceProcessorImpl*, &DummyClose, nullptr>;
123 
124   void RecordFirstNextInSqlStats();
125 
126   ScopedTraceProcessor trace_processor_;
127   sqlite3* db_ = nullptr;
128   ScopedStmt stmt_;
129   uint32_t column_count_ = 0;
130   util::Status status_;
131 
132   uint32_t sql_stats_row_ = 0;
133   bool called_next_ = false;
134 };
135 
136 }  // namespace trace_processor
137 }  // namespace perfetto
138 
139 #endif  // SRC_TRACE_PROCESSOR_ITERATOR_IMPL_H_
140