1 /*
2 * Copyright (C) 2018 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 #include "src/trace_processor/perfetto_sql/intrinsics/operators/window_operator.h"
18
19 #include <sqlite3.h>
20 #include <cstdint>
21 #include <memory>
22
23 #include "perfetto/base/logging.h"
24 #include "src/trace_processor/sqlite/bindings/sqlite_result.h"
25 #include "src/trace_processor/sqlite/module_lifecycle_manager.h"
26 #include "src/trace_processor/sqlite/sqlite_utils.h"
27
28 namespace perfetto::trace_processor {
29
30 namespace {
31 constexpr char kSchema[] = R"(
32 CREATE TABLE x(
33 rowid BIGINT HIDDEN,
34 quantum BIGINT HIDDEN,
35 window_start BIGINT HIDDEN,
36 window_dur BIGINT HIDDEN,
37 ts BIGINT,
38 dur BIGINT,
39 quantum_ts BIGINT,
40 PRIMARY KEY(rowid)
41 ) WITHOUT ROWID
42 )";
43 }
44
45 enum Column {
46 kRowId = 0,
47 kQuantum = 1,
48 kWindowStart = 2,
49 kWindowDur = 3,
50 kTs = 4,
51 kDuration = 5,
52 kQuantumTs = 6
53 };
54
Create(sqlite3 * db,void * raw_ctx,int argc,const char * const * argv,sqlite3_vtab ** vtab,char **)55 int WindowOperatorModule::Create(sqlite3* db,
56 void* raw_ctx,
57 int argc,
58 const char* const* argv,
59 sqlite3_vtab** vtab,
60 char**) {
61 PERFETTO_CHECK(argc == 3);
62 if (int ret = sqlite3_declare_vtab(db, kSchema); ret != SQLITE_OK) {
63 return ret;
64 }
65 auto* ctx = GetContext(raw_ctx);
66 std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
67 res->state = ctx->manager.OnCreate(argv, std::make_unique<State>());
68 *vtab = res.release();
69 return SQLITE_OK;
70 }
71
Destroy(sqlite3_vtab * vtab)72 int WindowOperatorModule::Destroy(sqlite3_vtab* vtab) {
73 std::unique_ptr<Vtab> tab(GetVtab(vtab));
74 sqlite::ModuleStateManager<WindowOperatorModule>::OnDestroy(tab->state);
75 return SQLITE_OK;
76 }
77
Connect(sqlite3 * db,void * raw_ctx,int argc,const char * const * argv,sqlite3_vtab ** vtab,char **)78 int WindowOperatorModule::Connect(sqlite3* db,
79 void* raw_ctx,
80 int argc,
81 const char* const* argv,
82 sqlite3_vtab** vtab,
83 char**) {
84 PERFETTO_CHECK(argc == 3);
85 if (int ret = sqlite3_declare_vtab(db, kSchema); ret != SQLITE_OK) {
86 return ret;
87 }
88 auto* ctx = GetContext(raw_ctx);
89 std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
90 res->state = ctx->manager.OnConnect(argv);
91 *vtab = res.release();
92 return SQLITE_OK;
93 }
94
Disconnect(sqlite3_vtab * vtab)95 int WindowOperatorModule::Disconnect(sqlite3_vtab* vtab) {
96 std::unique_ptr<Vtab> tab(GetVtab(vtab));
97 sqlite::ModuleStateManager<WindowOperatorModule>::OnDisconnect(tab->state);
98 return SQLITE_OK;
99 }
100
BestIndex(sqlite3_vtab *,sqlite3_index_info * info)101 int WindowOperatorModule::BestIndex(sqlite3_vtab*, sqlite3_index_info* info) {
102 info->orderByConsumed = info->nOrderBy == 1 &&
103 info->aOrderBy[0].iColumn == Column::kTs &&
104 !info->aOrderBy[0].desc;
105
106 // Set return first if there is a equals constraint on the row id asking to
107 // return the first row.
108 bool is_row_id_constraint = info->nConstraint == 1 &&
109 info->aConstraint[0].iColumn == Column::kRowId &&
110 info->aConstraint[0].usable &&
111 sqlite::utils::IsOpEq(info->aConstraint[0].op);
112 if (is_row_id_constraint) {
113 info->idxNum = 1;
114 info->aConstraintUsage[0].argvIndex = 1;
115 } else {
116 info->idxNum = 0;
117 }
118 return SQLITE_OK;
119 }
120
Open(sqlite3_vtab *,sqlite3_vtab_cursor ** cursor)121 int WindowOperatorModule::Open(sqlite3_vtab*, sqlite3_vtab_cursor** cursor) {
122 std::unique_ptr<Cursor> c = std::make_unique<Cursor>();
123 *cursor = c.release();
124 return SQLITE_OK;
125 }
126
Close(sqlite3_vtab_cursor * cursor)127 int WindowOperatorModule::Close(sqlite3_vtab_cursor* cursor) {
128 delete GetCursor(cursor);
129 return SQLITE_OK;
130 }
131
Filter(sqlite3_vtab_cursor * cursor,int is_row_id_constraint,const char *,int argc,sqlite3_value ** argv)132 int WindowOperatorModule::Filter(sqlite3_vtab_cursor* cursor,
133 int is_row_id_constraint,
134 const char*,
135 int argc,
136 sqlite3_value** argv) {
137 auto* t = GetVtab(cursor->pVtab);
138 auto* c = GetCursor(cursor);
139 auto* s =
140 sqlite::ModuleStateManager<WindowOperatorModule>::GetState(t->state);
141
142 c->window_end = s->window_start + s->window_dur;
143 c->step_size = s->quantum == 0 ? s->window_dur : s->quantum;
144 c->current_ts = s->window_start;
145
146 if (is_row_id_constraint) {
147 PERFETTO_CHECK(argc == 1);
148 c->filter_type = sqlite3_value_int(argv[0]) == 0 ? FilterType::kReturnFirst
149 : FilterType::kReturnAll;
150 } else {
151 c->filter_type = FilterType::kReturnAll;
152 }
153 return SQLITE_OK;
154 }
155
Next(sqlite3_vtab_cursor * cursor)156 int WindowOperatorModule::Next(sqlite3_vtab_cursor* cursor) {
157 auto* c = GetCursor(cursor);
158 switch (c->filter_type) {
159 case FilterType::kReturnFirst:
160 c->current_ts = c->window_end;
161 break;
162 case FilterType::kReturnAll:
163 c->current_ts += c->step_size;
164 c->quantum_ts++;
165 break;
166 }
167 c->row_id++;
168 return SQLITE_OK;
169 }
170
Eof(sqlite3_vtab_cursor * cursor)171 int WindowOperatorModule::Eof(sqlite3_vtab_cursor* cursor) {
172 auto* c = GetCursor(cursor);
173 return c->current_ts >= c->window_end;
174 }
175
Column(sqlite3_vtab_cursor * cursor,sqlite3_context * ctx,int N)176 int WindowOperatorModule::Column(sqlite3_vtab_cursor* cursor,
177 sqlite3_context* ctx,
178 int N) {
179 auto* t = GetVtab(cursor->pVtab);
180 auto* c = GetCursor(cursor);
181 auto* s =
182 sqlite::ModuleStateManager<WindowOperatorModule>::GetState(t->state);
183 switch (N) {
184 case Column::kQuantum: {
185 sqlite::result::Long(ctx, static_cast<sqlite_int64>(s->quantum));
186 break;
187 }
188 case Column::kWindowStart: {
189 sqlite::result::Long(ctx, static_cast<sqlite_int64>(s->window_start));
190 break;
191 }
192 case Column::kWindowDur: {
193 sqlite::result::Long(ctx, static_cast<int>(s->window_dur));
194 break;
195 }
196 case Column::kTs: {
197 sqlite::result::Long(ctx, static_cast<sqlite_int64>(c->current_ts));
198 break;
199 }
200 case Column::kDuration: {
201 sqlite::result::Long(ctx, static_cast<sqlite_int64>(c->step_size));
202 break;
203 }
204 case Column::kQuantumTs: {
205 sqlite::result::Long(ctx, static_cast<sqlite_int64>(c->quantum_ts));
206 break;
207 }
208 case Column::kRowId: {
209 sqlite::result::Long(ctx, static_cast<sqlite_int64>(c->row_id));
210 break;
211 }
212 default: {
213 PERFETTO_FATAL("Unknown column %d", N);
214 break;
215 }
216 }
217 return SQLITE_OK;
218 }
219
Rowid(sqlite3_vtab_cursor *,sqlite_int64 *)220 int WindowOperatorModule::Rowid(sqlite3_vtab_cursor*, sqlite_int64*) {
221 return SQLITE_ERROR;
222 }
223
Update(sqlite3_vtab * tab,int argc,sqlite3_value ** argv,sqlite_int64 *)224 int WindowOperatorModule::Update(sqlite3_vtab* tab,
225 int argc,
226 sqlite3_value** argv,
227 sqlite_int64*) {
228 auto* t = GetVtab(tab);
229 auto* s =
230 sqlite::ModuleStateManager<WindowOperatorModule>::GetState(t->state);
231
232 // We only support updates to ts and dur. Disallow deletes (argc == 1) and
233 // inserts (argv[0] == null).
234 if (argc < 2 || sqlite3_value_type(argv[0]) == SQLITE_NULL) {
235 return sqlite::utils::SetError(
236 tab, "Invalid number/value of arguments when updating window table");
237 }
238
239 int64_t new_quantum = sqlite3_value_int64(argv[3]);
240 int64_t new_start = sqlite3_value_int64(argv[4]);
241 int64_t new_dur = sqlite3_value_int64(argv[5]);
242 if (new_dur == 0) {
243 return sqlite::utils::SetError(
244 tab, "Cannot set duration of window table to zero.");
245 }
246
247 s->quantum = new_quantum;
248 s->window_start = new_start;
249 s->window_dur = new_dur;
250
251 return SQLITE_OK;
252 }
253
254 } // namespace perfetto::trace_processor
255