1 /*
2 * Copyright (C) 2019 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/db/column.h"
18
19 #include "src/trace_processor/db/compare.h"
20 #include "src/trace_processor/db/table.h"
21 #include "src/trace_processor/util/glob.h"
22
23 namespace perfetto {
24 namespace trace_processor {
25
Column(const Column & column,Table * table,uint32_t col_idx,uint32_t overlay_idx,const char * name)26 Column::Column(const Column& column,
27 Table* table,
28 uint32_t col_idx,
29 uint32_t overlay_idx,
30 const char* name)
31 : Column(name ? name : column.name_,
32 column.type_,
33 column.flags_ & ~kNoCrossTableInheritFlags,
34 table,
35 col_idx,
36 overlay_idx,
37 column.storage_) {}
38
Column(const char * name,ColumnType type,uint32_t flags,Table * table,uint32_t index_in_table,uint32_t overlay_index,ColumnStorageBase * st)39 Column::Column(const char* name,
40 ColumnType type,
41 uint32_t flags,
42 Table* table,
43 uint32_t index_in_table,
44 uint32_t overlay_index,
45 ColumnStorageBase* st)
46 : type_(type),
47 storage_(st),
48 name_(name),
49 flags_(flags),
50 table_(table),
51 index_in_table_(index_in_table),
52 overlay_index_(overlay_index),
53 string_pool_(table->string_pool_) {
54 // Check that the dense-ness of the column and the nullable vector match.
55 if (IsNullable() && !IsDummy()) {
56 bool is_storage_dense;
57 switch (type_) {
58 case ColumnType::kInt32:
59 is_storage_dense = storage<std::optional<int32_t>>().IsDense();
60 break;
61 case ColumnType::kUint32:
62 is_storage_dense = storage<std::optional<uint32_t>>().IsDense();
63 break;
64 case ColumnType::kInt64:
65 is_storage_dense = storage<std::optional<int64_t>>().IsDense();
66 break;
67 case ColumnType::kDouble:
68 is_storage_dense = storage<std::optional<double>>().IsDense();
69 break;
70 case ColumnType::kString:
71 PERFETTO_FATAL("String column should not be nullable");
72 case ColumnType::kId:
73 PERFETTO_FATAL("Id column should not be nullable");
74 case ColumnType::kDummy:
75 PERFETTO_FATAL("Dummy column excluded above");
76 }
77 PERFETTO_DCHECK(is_storage_dense == IsDense());
78 }
79 PERFETTO_DCHECK(IsFlagsAndTypeValid(flags_, type_));
80 }
81
DummyColumn(const char * name,Table * table,uint32_t col_idx_in_table)82 Column Column::DummyColumn(const char* name,
83 Table* table,
84 uint32_t col_idx_in_table) {
85 return Column(name, ColumnType::kDummy, Flag::kNoFlag, table,
86 col_idx_in_table, std::numeric_limits<uint32_t>::max(),
87 nullptr);
88 }
89
IdColumn(Table * table,uint32_t col_idx,uint32_t overlay_idx)90 Column Column::IdColumn(Table* table, uint32_t col_idx, uint32_t overlay_idx) {
91 return Column("id", ColumnType::kId, kIdFlags, table, col_idx, overlay_idx,
92 nullptr);
93 }
94
StableSort(bool desc,std::vector<uint32_t> * idx) const95 void Column::StableSort(bool desc, std::vector<uint32_t>* idx) const {
96 if (desc) {
97 StableSort<true /* desc */>(idx);
98 } else {
99 StableSort<false /* desc */>(idx);
100 }
101 }
102
FilterIntoSlow(FilterOp op,SqlValue value,RowMap * rm) const103 void Column::FilterIntoSlow(FilterOp op, SqlValue value, RowMap* rm) const {
104 switch (type_) {
105 case ColumnType::kInt32: {
106 if (IsNullable()) {
107 FilterIntoNumericSlow<int32_t, true /* is_nullable */>(op, value, rm);
108 } else {
109 FilterIntoNumericSlow<int32_t, false /* is_nullable */>(op, value, rm);
110 }
111 break;
112 }
113 case ColumnType::kUint32: {
114 if (IsNullable()) {
115 FilterIntoNumericSlow<uint32_t, true /* is_nullable */>(op, value, rm);
116 } else {
117 FilterIntoNumericSlow<uint32_t, false /* is_nullable */>(op, value, rm);
118 }
119 break;
120 }
121 case ColumnType::kInt64: {
122 if (IsNullable()) {
123 FilterIntoNumericSlow<int64_t, true /* is_nullable */>(op, value, rm);
124 } else {
125 FilterIntoNumericSlow<int64_t, false /* is_nullable */>(op, value, rm);
126 }
127 break;
128 }
129 case ColumnType::kDouble: {
130 if (IsNullable()) {
131 FilterIntoNumericSlow<double, true /* is_nullable */>(op, value, rm);
132 } else {
133 FilterIntoNumericSlow<double, false /* is_nullable */>(op, value, rm);
134 }
135 break;
136 }
137 case ColumnType::kString: {
138 FilterIntoStringSlow(op, value, rm);
139 break;
140 }
141 case ColumnType::kId: {
142 FilterIntoIdSlow(op, value, rm);
143 break;
144 }
145 case ColumnType::kDummy:
146 PERFETTO_FATAL("FilterIntoSlow not allowed on dummy column");
147 }
148 }
149
150 template <typename T, bool is_nullable>
FilterIntoNumericSlow(FilterOp op,SqlValue value,RowMap * rm) const151 void Column::FilterIntoNumericSlow(FilterOp op,
152 SqlValue value,
153 RowMap* rm) const {
154 PERFETTO_DCHECK(IsNullable() == is_nullable);
155 PERFETTO_DCHECK(type_ == ColumnTypeHelper<T>::ToColumnType());
156 PERFETTO_DCHECK(std::is_arithmetic<T>::value);
157
158 if (op == FilterOp::kIsNull) {
159 PERFETTO_DCHECK(value.is_null());
160 if (is_nullable) {
161 overlay().FilterInto(rm, [this](uint32_t row) {
162 return !storage<std::optional<T>>().Get(row).has_value();
163 });
164 } else {
165 rm->Clear();
166 }
167 return;
168 } else if (op == FilterOp::kIsNotNull) {
169 PERFETTO_DCHECK(value.is_null());
170 if (is_nullable) {
171 overlay().FilterInto(rm, [this](uint32_t row) {
172 return storage<std::optional<T>>().Get(row).has_value();
173 });
174 }
175 return;
176 }
177
178 if (value.type == SqlValue::Type::kDouble) {
179 double double_value = value.double_value;
180 if (std::is_same<T, double>::value) {
181 auto fn = [double_value](T v) {
182 // We static cast here as this code will be compiled even when T ==
183 // int64_t as we don't have if constexpr in C++11. In reality the cast
184 // is a noop but we cannot statically verify that for the compiler.
185 return compare::Numeric(static_cast<double>(v), double_value);
186 };
187 FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
188 } else {
189 auto fn = [double_value](T v) {
190 // We static cast here as this code will be compiled even when T ==
191 // double as we don't have if constexpr in C++11. In reality the cast is
192 // a noop but we cannot statically verify that for the compiler.
193 return compare::LongToDouble(static_cast<int64_t>(v), double_value);
194 };
195 FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
196 }
197 } else if (value.type == SqlValue::Type::kLong) {
198 int64_t long_value = value.long_value;
199 if (std::is_same<T, double>::value) {
200 auto fn = [long_value](T v) {
201 // We negate the return value as the long is always the first parameter
202 // for this function even though the LHS of the comparator should
203 // actually be |v|. This saves us having a duplicate implementation of
204 // the comparision function.
205 return -compare::LongToDouble(long_value, static_cast<double>(v));
206 };
207 FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
208 } else {
209 auto fn = [long_value](T v) {
210 // We static cast here as this code will be compiled even when T ==
211 // double as we don't have if constexpr in C++11. In reality the cast is
212 // a noop but we cannot statically verify that for the compiler.
213 return compare::Numeric(static_cast<int64_t>(v), long_value);
214 };
215 FilterIntoNumericWithComparatorSlow<T, is_nullable>(op, rm, fn);
216 }
217 } else {
218 rm->Clear();
219 }
220 }
221
222 template <typename T, bool is_nullable, typename Comparator>
FilterIntoNumericWithComparatorSlow(FilterOp op,RowMap * rm,Comparator cmp) const223 void Column::FilterIntoNumericWithComparatorSlow(FilterOp op,
224 RowMap* rm,
225 Comparator cmp) const {
226 switch (op) {
227 case FilterOp::kLt:
228 overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
229 if (is_nullable) {
230 auto opt_value = storage<std::optional<T>>().Get(idx);
231 return opt_value && cmp(*opt_value) < 0;
232 }
233 return cmp(storage<T>().Get(idx)) < 0;
234 });
235 break;
236 case FilterOp::kEq:
237 overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
238 if (is_nullable) {
239 auto opt_value = storage<std::optional<T>>().Get(idx);
240 return opt_value && cmp(*opt_value) == 0;
241 }
242 return cmp(storage<T>().Get(idx)) == 0;
243 });
244 break;
245 case FilterOp::kGt:
246 overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
247 if (is_nullable) {
248 auto opt_value = storage<std::optional<T>>().Get(idx);
249 return opt_value && cmp(*opt_value) > 0;
250 }
251 return cmp(storage<T>().Get(idx)) > 0;
252 });
253 break;
254 case FilterOp::kNe:
255 overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
256 if (is_nullable) {
257 auto opt_value = storage<std::optional<T>>().Get(idx);
258 return opt_value && cmp(*opt_value) != 0;
259 }
260 return cmp(storage<T>().Get(idx)) != 0;
261 });
262 break;
263 case FilterOp::kLe:
264 overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
265 if (is_nullable) {
266 auto opt_value = storage<std::optional<T>>().Get(idx);
267 return opt_value && cmp(*opt_value) <= 0;
268 }
269 return cmp(storage<T>().Get(idx)) <= 0;
270 });
271 break;
272 case FilterOp::kGe:
273 overlay().FilterInto(rm, [this, &cmp](uint32_t idx) {
274 if (is_nullable) {
275 auto opt_value = storage<std::optional<T>>().Get(idx);
276 return opt_value && cmp(*opt_value) >= 0;
277 }
278 return cmp(storage<T>().Get(idx)) >= 0;
279 });
280 break;
281 case FilterOp::kGlob:
282 rm->Clear();
283 break;
284 case FilterOp::kIsNull:
285 case FilterOp::kIsNotNull:
286 PERFETTO_FATAL("Should be handled above");
287 }
288 }
289
FilterIntoStringSlow(FilterOp op,SqlValue value,RowMap * rm) const290 void Column::FilterIntoStringSlow(FilterOp op,
291 SqlValue value,
292 RowMap* rm) const {
293 PERFETTO_DCHECK(type_ == ColumnType::kString);
294
295 if (op == FilterOp::kIsNull) {
296 PERFETTO_DCHECK(value.is_null());
297 overlay().FilterInto(rm, [this](uint32_t row) {
298 return GetStringPoolStringAtIdx(row).data() == nullptr;
299 });
300 return;
301 } else if (op == FilterOp::kIsNotNull) {
302 PERFETTO_DCHECK(value.is_null());
303 overlay().FilterInto(rm, [this](uint32_t row) {
304 return GetStringPoolStringAtIdx(row).data() != nullptr;
305 });
306 return;
307 }
308
309 if (value.type != SqlValue::Type::kString) {
310 rm->Clear();
311 return;
312 }
313
314 NullTermStringView str_value = value.string_value;
315 PERFETTO_DCHECK(str_value.data() != nullptr);
316
317 switch (op) {
318 case FilterOp::kLt:
319 overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
320 auto v = GetStringPoolStringAtIdx(idx);
321 return v.data() != nullptr && compare::String(v, str_value) < 0;
322 });
323 break;
324 case FilterOp::kEq:
325 overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
326 auto v = GetStringPoolStringAtIdx(idx);
327 return v.data() != nullptr && compare::String(v, str_value) == 0;
328 });
329 break;
330 case FilterOp::kGt:
331 overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
332 auto v = GetStringPoolStringAtIdx(idx);
333 return v.data() != nullptr && compare::String(v, str_value) > 0;
334 });
335 break;
336 case FilterOp::kNe:
337 overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
338 auto v = GetStringPoolStringAtIdx(idx);
339 return v.data() != nullptr && compare::String(v, str_value) != 0;
340 });
341 break;
342 case FilterOp::kLe:
343 overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
344 auto v = GetStringPoolStringAtIdx(idx);
345 return v.data() != nullptr && compare::String(v, str_value) <= 0;
346 });
347 break;
348 case FilterOp::kGe:
349 overlay().FilterInto(rm, [this, str_value](uint32_t idx) {
350 auto v = GetStringPoolStringAtIdx(idx);
351 return v.data() != nullptr && compare::String(v, str_value) >= 0;
352 });
353 break;
354 case FilterOp::kGlob: {
355 util::GlobMatcher matcher = util::GlobMatcher::FromPattern(str_value);
356 overlay().FilterInto(rm, [this, &matcher](uint32_t idx) {
357 auto v = GetStringPoolStringAtIdx(idx);
358 return v.data() != nullptr && matcher.Matches(v);
359 });
360 break;
361 }
362 case FilterOp::kIsNull:
363 case FilterOp::kIsNotNull:
364 PERFETTO_FATAL("Should be handled above");
365 }
366 }
367
FilterIntoIdSlow(FilterOp op,SqlValue value,RowMap * rm) const368 void Column::FilterIntoIdSlow(FilterOp op, SqlValue value, RowMap* rm) const {
369 PERFETTO_DCHECK(type_ == ColumnType::kId);
370
371 if (op == FilterOp::kIsNull) {
372 PERFETTO_DCHECK(value.is_null());
373 rm->Clear();
374 return;
375 } else if (op == FilterOp::kIsNotNull) {
376 PERFETTO_DCHECK(value.is_null());
377 return;
378 }
379
380 if (value.type != SqlValue::Type::kLong) {
381 rm->Clear();
382 return;
383 }
384
385 uint32_t id_value = static_cast<uint32_t>(value.long_value);
386 switch (op) {
387 case FilterOp::kLt:
388 overlay().FilterInto(rm, [id_value](uint32_t idx) {
389 return compare::Numeric(idx, id_value) < 0;
390 });
391 break;
392 case FilterOp::kEq:
393 overlay().FilterInto(rm, [id_value](uint32_t idx) {
394 return compare::Numeric(idx, id_value) == 0;
395 });
396 break;
397 case FilterOp::kGt:
398 overlay().FilterInto(rm, [id_value](uint32_t idx) {
399 return compare::Numeric(idx, id_value) > 0;
400 });
401 break;
402 case FilterOp::kNe:
403 overlay().FilterInto(rm, [id_value](uint32_t idx) {
404 return compare::Numeric(idx, id_value) != 0;
405 });
406 break;
407 case FilterOp::kLe:
408 overlay().FilterInto(rm, [id_value](uint32_t idx) {
409 return compare::Numeric(idx, id_value) <= 0;
410 });
411 break;
412 case FilterOp::kGe:
413 overlay().FilterInto(rm, [id_value](uint32_t idx) {
414 return compare::Numeric(idx, id_value) >= 0;
415 });
416 break;
417 case FilterOp::kGlob:
418 rm->Clear();
419 break;
420 case FilterOp::kIsNull:
421 case FilterOp::kIsNotNull:
422 PERFETTO_FATAL("Should be handled above");
423 }
424 }
425
426 template <bool desc>
StableSort(std::vector<uint32_t> * out) const427 void Column::StableSort(std::vector<uint32_t>* out) const {
428 switch (type_) {
429 case ColumnType::kInt32: {
430 if (IsNullable()) {
431 StableSortNumeric<desc, int32_t, true /* is_nullable */>(out);
432 } else {
433 StableSortNumeric<desc, int32_t, false /* is_nullable */>(out);
434 }
435 break;
436 }
437 case ColumnType::kUint32: {
438 if (IsNullable()) {
439 StableSortNumeric<desc, uint32_t, true /* is_nullable */>(out);
440 } else {
441 StableSortNumeric<desc, uint32_t, false /* is_nullable */>(out);
442 }
443 break;
444 }
445 case ColumnType::kInt64: {
446 if (IsNullable()) {
447 StableSortNumeric<desc, int64_t, true /* is_nullable */>(out);
448 } else {
449 StableSortNumeric<desc, int64_t, false /* is_nullable */>(out);
450 }
451 break;
452 }
453 case ColumnType::kDouble: {
454 if (IsNullable()) {
455 StableSortNumeric<desc, double, true /* is_nullable */>(out);
456 } else {
457 StableSortNumeric<desc, double, false /* is_nullable */>(out);
458 }
459 break;
460 }
461 case ColumnType::kString: {
462 overlay().StableSort(out, [this](uint32_t a_idx, uint32_t b_idx) {
463 auto a_str = GetStringPoolStringAtIdx(a_idx);
464 auto b_str = GetStringPoolStringAtIdx(b_idx);
465
466 int res = compare::NullableString(a_str, b_str);
467 return desc ? res > 0 : res < 0;
468 });
469 break;
470 }
471 case ColumnType::kId:
472 overlay().StableSort(out, [](uint32_t a_idx, uint32_t b_idx) {
473 int res = compare::Numeric(a_idx, b_idx);
474 return desc ? res > 0 : res < 0;
475 });
476 break;
477 case ColumnType::kDummy:
478 PERFETTO_FATAL("StableSort not allowed on dummy column");
479 }
480 }
481
482 template <bool desc, typename T, bool is_nullable>
StableSortNumeric(std::vector<uint32_t> * out) const483 void Column::StableSortNumeric(std::vector<uint32_t>* out) const {
484 PERFETTO_DCHECK(IsNullable() == is_nullable);
485 PERFETTO_DCHECK(ColumnTypeHelper<T>::ToColumnType() == type_);
486
487 overlay().StableSort(out, [this](uint32_t a_idx, uint32_t b_idx) {
488 if (is_nullable) {
489 auto a_val = storage<std::optional<T>>().Get(a_idx);
490 auto b_val = storage<std::optional<T>>().Get(b_idx);
491
492 int res = compare::NullableNumeric(a_val, b_val);
493 return desc ? res > 0 : res < 0;
494 }
495 auto a_val = storage<T>().Get(a_idx);
496 auto b_val = storage<T>().Get(b_idx);
497
498 int res = compare::Numeric(a_val, b_val);
499 return desc ? res > 0 : res < 0;
500 });
501 }
502
overlay() const503 const ColumnStorageOverlay& Column::overlay() const {
504 PERFETTO_DCHECK(type_ != ColumnType::kDummy);
505 return table_->overlays_[overlay_index()];
506 }
507
508 } // namespace trace_processor
509 } // namespace perfetto
510