1 /*
2 * Copyright (C) 2023 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/query_executor.h"
18
19 #include <algorithm>
20 #include <cstdint>
21 #include <memory>
22 #include <numeric>
23 #include <string>
24 #include <vector>
25
26 #include "perfetto/ext/base/string_view.h"
27 #include "perfetto/trace_processor/basic_types.h"
28 #include "src/trace_processor/containers/bit_vector.h"
29 #include "src/trace_processor/containers/row_map.h"
30 #include "src/trace_processor/containers/string_pool.h"
31 #include "src/trace_processor/db/column/arrangement_overlay.h"
32 #include "src/trace_processor/db/column/data_layer.h"
33 #include "src/trace_processor/db/column/fake_storage.h"
34 #include "src/trace_processor/db/column/id_storage.h"
35 #include "src/trace_processor/db/column/null_overlay.h"
36 #include "src/trace_processor/db/column/numeric_storage.h"
37 #include "src/trace_processor/db/column/selector_overlay.h"
38 #include "src/trace_processor/db/column/set_id_storage.h"
39 #include "src/trace_processor/db/column/string_storage.h"
40 #include "src/trace_processor/db/column/types.h"
41 #include "test/gtest_and_gmock.h"
42
43 namespace perfetto::trace_processor {
44 namespace {
45
46 using testing::ElementsAre;
47
48 using IdStorage = column::IdStorage;
49 using SetIdStorage = column::SetIdStorage;
50 using StringStorage = column::StringStorage;
51 using NullOverlay = column::NullOverlay;
52 using ArrangementOverlay = column::ArrangementOverlay;
53 using SelectorOverlay = column::SelectorOverlay;
54
55 using Indices = column::DataLayerChain::Indices;
56
TEST(QueryExecutor,OnlyStorageRange)57 TEST(QueryExecutor, OnlyStorageRange) {
58 std::vector<int64_t> storage_data{1, 2, 3, 4, 5};
59 column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
60 false);
61 auto chain = storage.MakeChain();
62
63 Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
64 RowMap rm(0, chain->size());
65 QueryExecutor::BoundedColumnFilterForTesting(c, *chain, &rm);
66
67 ASSERT_EQ(rm.size(), 3u);
68 ASSERT_EQ(rm.Get(0), 2u);
69 }
70
TEST(QueryExecutor,OnlyStorageRangeIsNull)71 TEST(QueryExecutor, OnlyStorageRangeIsNull) {
72 std::vector<int64_t> storage_data{1, 2, 3, 4, 5};
73 column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
74 false);
75 auto chain = storage.MakeChain();
76
77 Constraint c{0, FilterOp::kIsNull, SqlValue()};
78 RowMap rm(0, 5);
79 QueryExecutor::BoundedColumnFilterForTesting(c, *chain, &rm);
80
81 ASSERT_EQ(rm.size(), 0u);
82 }
83
TEST(QueryExecutor,OnlyStorageIndex)84 TEST(QueryExecutor, OnlyStorageIndex) {
85 // Setup storage
86 std::vector<int64_t> storage_data(10);
87 std::iota(storage_data.begin(), storage_data.end(), 0);
88 std::transform(storage_data.begin(), storage_data.end(), storage_data.begin(),
89 [](int64_t n) { return n % 5; });
90 column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
91 false);
92 auto chain = storage.MakeChain();
93
94 Constraint c{0, FilterOp::kLt, SqlValue::Long(2)};
95 RowMap rm(0, 10);
96 QueryExecutor::IndexedColumnFilterForTesting(c, *chain, &rm);
97
98 ASSERT_EQ(rm.size(), 4u);
99 ASSERT_EQ(rm.Get(0), 0u);
100 ASSERT_EQ(rm.Get(1), 1u);
101 ASSERT_EQ(rm.Get(2), 5u);
102 ASSERT_EQ(rm.Get(3), 6u);
103 }
104
TEST(QueryExecutor,OnlyStorageIndexIsNull)105 TEST(QueryExecutor, OnlyStorageIndexIsNull) {
106 std::vector<int64_t> storage_data{1, 2, 3, 4, 5};
107 column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
108 false);
109 auto chain = storage.MakeChain();
110
111 Constraint c{0, FilterOp::kIsNull, SqlValue()};
112 RowMap rm(0, 5);
113 QueryExecutor::IndexedColumnFilterForTesting(c, *chain, &rm);
114
115 ASSERT_EQ(rm.size(), 0u);
116 }
117
TEST(QueryExecutor,NullBounds)118 TEST(QueryExecutor, NullBounds) {
119 std::vector<int64_t> storage_data(5);
120 std::iota(storage_data.begin(), storage_data.end(), 0);
121 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
122 &storage_data, ColumnType::kInt64, false);
123 BitVector bv{1, 1, 0, 1, 1, 0, 0, 0, 1, 0};
124 column::NullOverlay storage(&bv);
125 auto chain = storage.MakeChain(numeric->MakeChain());
126
127 Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
128 RowMap rm(0, 10);
129 QueryExecutor::BoundedColumnFilterForTesting(c, *chain, &rm);
130
131 ASSERT_EQ(rm.size(), 2u);
132 ASSERT_EQ(rm.Get(0), 4u);
133 ASSERT_EQ(rm.Get(1), 8u);
134 }
135
TEST(QueryExecutor,NullRangeIsNull)136 TEST(QueryExecutor, NullRangeIsNull) {
137 std::vector<int64_t> storage_data(5);
138 std::iota(storage_data.begin(), storage_data.end(), 0);
139 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
140 &storage_data, ColumnType::kInt64, false);
141
142 BitVector bv{1, 1, 0, 1, 1, 0, 0, 0, 1, 0};
143 column::NullOverlay storage(&bv);
144 auto chain = storage.MakeChain(numeric->MakeChain());
145
146 Constraint c{0, FilterOp::kIsNull, SqlValue()};
147 RowMap rm(0, chain->size());
148 QueryExecutor::BoundedColumnFilterForTesting(c, *chain, &rm);
149
150 ASSERT_EQ(rm.size(), 5u);
151 ASSERT_EQ(rm.Get(0), 2u);
152 ASSERT_EQ(rm.Get(1), 5u);
153 ASSERT_EQ(rm.Get(2), 6u);
154 ASSERT_EQ(rm.Get(3), 7u);
155 ASSERT_EQ(rm.Get(4), 9u);
156 }
157
TEST(QueryExecutor,NullIndex)158 TEST(QueryExecutor, NullIndex) {
159 std::vector<int64_t> storage_data(6);
160 std::iota(storage_data.begin(), storage_data.end(), 0);
161 std::transform(storage_data.begin(), storage_data.end(), storage_data.begin(),
162 [](int64_t n) { return n % 3; });
163 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
164 &storage_data, ColumnType::kInt64, false);
165
166 BitVector bv{1, 1, 0, 1, 1, 0, 1, 0, 0, 1};
167 column::NullOverlay storage(&bv);
168 auto chain = storage.MakeChain(numeric->MakeChain());
169
170 Constraint c{0, FilterOp::kGe, SqlValue::Long(1)};
171 RowMap rm(0, 10);
172 QueryExecutor::IndexedColumnFilterForTesting(c, *chain, &rm);
173
174 ASSERT_EQ(rm.size(), 4u);
175 ASSERT_EQ(rm.Get(0), 1u);
176 ASSERT_EQ(rm.Get(1), 3u);
177 ASSERT_EQ(rm.Get(2), 6u);
178 ASSERT_EQ(rm.Get(3), 9u);
179 }
180
TEST(QueryExecutor,NullIndexIsNull)181 TEST(QueryExecutor, NullIndexIsNull) {
182 std::vector<int64_t> storage_data(5);
183 std::iota(storage_data.begin(), storage_data.end(), 0);
184 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
185 &storage_data, ColumnType::kInt64, false);
186
187 BitVector bv{1, 1, 0, 1, 1, 0, 0, 0, 1, 0};
188 column::NullOverlay storage(&bv);
189 auto chain = storage.MakeChain(numeric->MakeChain());
190
191 Constraint c{0, FilterOp::kIsNull, SqlValue()};
192 RowMap rm(0, 10);
193 QueryExecutor::IndexedColumnFilterForTesting(c, *chain, &rm);
194
195 ASSERT_EQ(rm.size(), 5u);
196 ASSERT_EQ(rm.Get(0), 2u);
197 ASSERT_EQ(rm.Get(1), 5u);
198 ASSERT_EQ(rm.Get(2), 6u);
199 ASSERT_EQ(rm.Get(3), 7u);
200 ASSERT_EQ(rm.Get(4), 9u);
201 }
202
TEST(QueryExecutor,SelectorOverlayBounds)203 TEST(QueryExecutor, SelectorOverlayBounds) {
204 std::vector<int64_t> storage_data(5);
205 std::iota(storage_data.begin(), storage_data.end(), 0);
206 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
207 &storage_data, ColumnType::kInt64, false);
208
209 BitVector bv{1, 1, 0, 0, 1};
210 SelectorOverlay storage(&bv);
211 auto chain = storage.MakeChain(numeric->MakeChain());
212
213 Constraint c{0, FilterOp::kGt, SqlValue::Long(1)};
214 RowMap rm(0, 3);
215 QueryExecutor::BoundedColumnFilterForTesting(c, *chain, &rm);
216
217 ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
218 }
219
TEST(QueryExecutor,SelectorOverlayIndex)220 TEST(QueryExecutor, SelectorOverlayIndex) {
221 std::vector<int64_t> storage_data(10);
222 std::iota(storage_data.begin(), storage_data.end(), 0);
223 std::transform(storage_data.begin(), storage_data.end(), storage_data.begin(),
224 [](int64_t n) { return n % 5; });
225 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
226 &storage_data, ColumnType::kInt64, false);
227
228 BitVector bv{1, 1, 0, 1, 1, 0, 1, 0, 0, 1};
229 SelectorOverlay storage(&bv);
230 auto chain = storage.MakeChain(numeric->MakeChain());
231
232 Constraint c{0, FilterOp::kGe, SqlValue::Long(2)};
233 RowMap rm(0, 6);
234 QueryExecutor::IndexedColumnFilterForTesting(c, *chain, &rm);
235
236 ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u, 3u, 5u));
237 }
238
TEST(QueryExecutor,ArrangementOverlayBounds)239 TEST(QueryExecutor, ArrangementOverlayBounds) {
240 std::vector<int64_t> storage_data(5);
241 std::iota(storage_data.begin(), storage_data.end(), 0);
242 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
243 &storage_data, ColumnType::kInt64, false);
244
245 std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
246 ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
247 auto chain = storage.MakeChain(numeric->MakeChain());
248
249 Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
250 RowMap rm(0, 5);
251 QueryExecutor::BoundedColumnFilterForTesting(c, *chain, &rm);
252
253 ASSERT_THAT(rm.GetAllIndices(), ElementsAre(0u, 4u));
254 }
255
TEST(QueryExecutor,ArrangementOverlaySubsetInputRange)256 TEST(QueryExecutor, ArrangementOverlaySubsetInputRange) {
257 auto fake = column::FakeStorageChain::SearchSubset(5u, RowMap::Range(2u, 4u));
258
259 std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
260 ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
261 auto chain = storage.MakeChain(std::move(fake));
262
263 Constraint c{0, FilterOp::kGe, SqlValue::Long(0u)};
264 RowMap rm(1, 3);
265 QueryExecutor::BoundedColumnFilterForTesting(c, *chain, &rm);
266
267 ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
268 }
269
TEST(QueryExecutor,ArrangementOverlaySubsetInputBitvector)270 TEST(QueryExecutor, ArrangementOverlaySubsetInputBitvector) {
271 auto fake =
272 column::FakeStorageChain::SearchSubset(5u, BitVector({0, 0, 1, 1, 0}));
273
274 std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
275 ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
276 auto chain = storage.MakeChain(std::move(fake));
277
278 Constraint c{0, FilterOp::kGe, SqlValue::Long(0u)};
279 RowMap rm(1, 3);
280 QueryExecutor::BoundedColumnFilterForTesting(c, *chain, &rm);
281
282 ASSERT_THAT(rm.GetAllIndices(), ElementsAre(2u));
283 }
284
TEST(QueryExecutor,ArrangementOverlayIndex)285 TEST(QueryExecutor, ArrangementOverlayIndex) {
286 std::vector<int64_t> storage_data(5);
287 std::iota(storage_data.begin(), storage_data.end(), 0);
288 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
289 &storage_data, ColumnType::kInt64, false);
290
291 std::vector<uint32_t> arrangement{4, 1, 2, 2, 3};
292 ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
293 auto chain = storage.MakeChain(numeric->MakeChain());
294
295 Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
296 RowMap rm(0, 5);
297 QueryExecutor::IndexedColumnFilterForTesting(c, *chain, &rm);
298
299 ASSERT_THAT(rm.GetAllIndices(), ElementsAre(0u, 4u));
300 }
301
TEST(QueryExecutor,MismatchedTypeNullWithOtherOperations)302 TEST(QueryExecutor, MismatchedTypeNullWithOtherOperations) {
303 std::vector<int64_t> storage_data{0, 1, 2, 3, 0, 1, 2, 3};
304 column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
305 false);
306 auto chain = storage.MakeChain();
307
308 // Filter.
309 Constraint c{0, FilterOp::kGe, SqlValue()};
310 QueryExecutor exec({chain.get()}, 6);
311 RowMap res = exec.Filter({c});
312
313 ASSERT_TRUE(res.empty());
314 }
315
TEST(QueryExecutor,SingleConstraintWithNullAndSelector)316 TEST(QueryExecutor, SingleConstraintWithNullAndSelector) {
317 std::vector<int64_t> storage_data{0, 1, 2, 3, 0, 1, 2, 3};
318 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
319 &storage_data, ColumnType::kInt64, false);
320
321 // Current vector
322 // 0, 1, NULL, 2, 3, 0, NULL, NULL, 1, 2, 3, NULL
323 BitVector null_bv{1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
324 auto null = std::make_unique<column::NullOverlay>(&null_bv);
325
326 // Final vector
327 // 0, NULL, 3, NULL, 1, 3
328 BitVector selector_bv{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
329 SelectorOverlay storage(&selector_bv);
330 auto chain = storage.MakeChain(null->MakeChain(numeric->MakeChain()));
331
332 // Filter.
333 Constraint c{0, FilterOp::kGe, SqlValue::Long(2)};
334 QueryExecutor exec({chain.get()}, 6);
335 RowMap res = exec.Filter({c});
336
337 ASSERT_EQ(res.size(), 2u);
338 ASSERT_EQ(res.Get(0), 2u);
339 ASSERT_EQ(res.Get(1), 5u);
340 }
341
TEST(QueryExecutor,SingleConstraintWithNullAndArrangement)342 TEST(QueryExecutor, SingleConstraintWithNullAndArrangement) {
343 std::vector<int64_t> storage_data{0, 1, 2, 3, 0, 1, 2, 3};
344 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
345 &storage_data, ColumnType::kInt64, false);
346
347 // Current vector
348 // 0, 1, NULL, 2, 3, 0, NULL, NULL, 1, 2, 3, NULL
349 BitVector null_bv{1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
350 auto null = std::make_unique<column::NullOverlay>(&null_bv);
351
352 // Final vector
353 // NULL, 3, NULL, NULL, 3, NULL
354 std::vector<uint32_t> arrangement{2, 4, 6, 2, 4, 6};
355 ArrangementOverlay storage(&arrangement, Indices::State::kNonmonotonic);
356 auto chain = storage.MakeChain(null->MakeChain(numeric->MakeChain()));
357
358 // Filter.
359 Constraint c{0, FilterOp::kGe, SqlValue::Long(1)};
360 QueryExecutor exec({chain.get()}, 6);
361 RowMap res = exec.Filter({c});
362
363 ASSERT_EQ(res.size(), 2u);
364 ASSERT_EQ(res.Get(0), 1u);
365 ASSERT_EQ(res.Get(1), 4u);
366 }
367
TEST(QueryExecutor,IsNullWithSelector)368 TEST(QueryExecutor, IsNullWithSelector) {
369 std::vector<int64_t> storage_data{0, 1, 2, 3, 0, 1, 2, 3};
370 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
371 &storage_data, ColumnType::kInt64, false);
372
373 // Current vector
374 // 0, 1, NULL, 2, 3, 0, NULL, NULL, 1, 2, 3, NULL
375 BitVector null_bv{1, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0};
376 auto null = std::make_unique<column::NullOverlay>(&null_bv);
377
378 // Final vector
379 // 0, NULL, 3, NULL, 1, 3
380 BitVector selector_bv{1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0};
381 SelectorOverlay storage(&selector_bv);
382 auto chain = storage.MakeChain(null->MakeChain(numeric->MakeChain()));
383
384 // Filter.
385 Constraint c{0, FilterOp::kIsNull, SqlValue()};
386 QueryExecutor exec({chain.get()}, 6);
387 RowMap res = exec.Filter({c});
388
389 ASSERT_EQ(res.size(), 2u);
390 ASSERT_EQ(res.Get(0), 1u);
391 ASSERT_EQ(res.Get(1), 3u);
392 }
393
TEST(QueryExecutor,BinarySearch)394 TEST(QueryExecutor, BinarySearch) {
395 std::vector<int64_t> storage_data{0, 1, 2, 3, 4, 5, 6};
396 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
397 &storage_data, ColumnType::kInt64, true);
398
399 // Add nulls - {0, 1, NULL, NULL, 2, 3, NULL, NULL, 4, 5, 6, NULL}
400 BitVector null_bv{1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0};
401 auto null = std::make_unique<column::NullOverlay>(&null_bv);
402
403 // Final vector {1, NULL, 3, NULL, 5, NULL}.
404 BitVector selector_bv{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
405 SelectorOverlay storage(&selector_bv);
406
407 auto chain = storage.MakeChain(null->MakeChain(numeric->MakeChain()));
408
409 // Filter.
410 Constraint c{0, FilterOp::kGe, SqlValue::Long(3)};
411 QueryExecutor exec({chain.get()}, 6);
412 RowMap res = exec.Filter({c});
413
414 ASSERT_EQ(res.size(), 2u);
415 ASSERT_EQ(res.Get(0), 2u);
416 ASSERT_EQ(res.Get(1), 4u);
417 }
418
TEST(QueryExecutor,BinarySearchIsNull)419 TEST(QueryExecutor, BinarySearchIsNull) {
420 std::vector<int64_t> storage_data{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
421 auto numeric = std::make_unique<column::NumericStorage<int64_t>>(
422 &storage_data, ColumnType::kInt64, true);
423
424 // Select 6 elements from storage, resulting in a vector {0, 1, 3, 4, 6, 7}.
425 BitVector selector_bv{1, 1, 0, 1, 1, 0, 1, 1, 0, 0};
426 auto selector = std::make_unique<SelectorOverlay>(&selector_bv);
427
428 // Add nulls, final vector {NULL, NULL, NULL 0, 1, 3, 4, 6, 7}.
429 BitVector null_bv{0, 0, 0, 1, 1, 1, 1, 1, 1};
430 column::NullOverlay storage(&null_bv);
431
432 auto chain = storage.MakeChain(selector->MakeChain(numeric->MakeChain()));
433
434 // Filter.
435 Constraint c{0, FilterOp::kIsNull, SqlValue()};
436 QueryExecutor exec({chain.get()}, 9);
437 RowMap res = exec.Filter({c});
438
439 ASSERT_EQ(res.size(), 3u);
440 ASSERT_EQ(res.Get(0), 0u);
441 ASSERT_EQ(res.Get(1), 1u);
442 ASSERT_EQ(res.Get(2), 2u);
443 }
444
TEST(QueryExecutor,SetIdStorage)445 TEST(QueryExecutor, SetIdStorage) {
446 std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
447 auto numeric = std::make_unique<column::SetIdStorage>(&storage_data);
448
449 // Select 6 elements from storage, resulting in a vector {0, 3, 3, 6, 9, 9}.
450 BitVector selector_bv{0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};
451 auto selector = std::make_unique<SelectorOverlay>(&selector_bv);
452
453 // Add nulls - vector (size 10) {NULL, 0, 3, NULL, 3, 6, NULL, 9, 9, NULL}.
454 BitVector null_bv{0, 1, 1, 0, 1, 1, 0, 1, 1, 0};
455 column::NullOverlay storage(&null_bv);
456
457 auto chain = storage.MakeChain(selector->MakeChain(numeric->MakeChain()));
458
459 // Filter.
460 Constraint c{0, FilterOp::kIsNull, SqlValue()};
461 QueryExecutor exec({chain.get()}, 10);
462 RowMap res = exec.Filter({c});
463
464 ASSERT_EQ(res.size(), 4u);
465 ASSERT_EQ(res.Get(0), 0u);
466 ASSERT_EQ(res.Get(1), 3u);
467 ASSERT_EQ(res.Get(2), 6u);
468 ASSERT_EQ(res.Get(3), 9u);
469 }
470
TEST(QueryExecutor,BinarySearchNotEq)471 TEST(QueryExecutor, BinarySearchNotEq) {
472 std::vector<int64_t> storage_data{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
473 column::NumericStorage<int64_t> storage(&storage_data, ColumnType::kInt64,
474 true);
475 auto chain = storage.MakeChain();
476
477 // Filter.
478 Constraint c{0, FilterOp::kNe, SqlValue::Long(5)};
479 QueryExecutor exec({chain.get()}, 10);
480 RowMap res = exec.Filter({c});
481
482 ASSERT_EQ(res.size(), 9u);
483 }
484
TEST(QueryExecutor,IdSearchIsNull)485 TEST(QueryExecutor, IdSearchIsNull) {
486 IdStorage storage;
487 auto chain = storage.MakeChain();
488
489 // Filter.
490 Constraint c{0, FilterOp::kIsNull, SqlValue()};
491 QueryExecutor exec({chain.get()}, 5);
492 RowMap res = exec.Filter({c});
493
494 ASSERT_EQ(res.size(), 0u);
495 }
496
TEST(QueryExecutor,IdSearchIsNotNull)497 TEST(QueryExecutor, IdSearchIsNotNull) {
498 IdStorage storage;
499 auto chain = storage.MakeChain();
500
501 // Filter.
502 Constraint c{0, FilterOp::kIsNotNull, SqlValue()};
503 QueryExecutor exec({chain.get()}, 5);
504 RowMap res = exec.Filter({c});
505
506 ASSERT_EQ(res.size(), 5u);
507 }
508
TEST(QueryExecutor,IdSearchNotEq)509 TEST(QueryExecutor, IdSearchNotEq) {
510 IdStorage storage;
511 auto chain = storage.MakeChain();
512
513 // Filter.
514 Constraint c{0, FilterOp::kNe, SqlValue::Long(3)};
515 QueryExecutor exec({chain.get()}, 5);
516 RowMap res = exec.Filter({c});
517
518 ASSERT_EQ(res.size(), 4u);
519 }
520
TEST(QueryExecutor,StringSearchIsNull)521 TEST(QueryExecutor, StringSearchIsNull) {
522 StringPool pool;
523 std::vector<std::string> strings{"cheese", "pasta", "pizza",
524 "pierogi", "onion", "fries"};
525 std::vector<StringPool::Id> ids;
526 for (const auto& string : strings) {
527 ids.push_back(pool.InternString(base::StringView(string)));
528 }
529 ids.insert(ids.begin() + 3, StringPool::Id::Null());
530 auto string = std::make_unique<StringStorage>(&pool, &ids);
531
532 // Final vec {"cheese", "pasta", "NULL", "pierogi", "fries"}.
533 BitVector selector_bv{1, 1, 0, 1, 1, 0, 1};
534 SelectorOverlay storage(&selector_bv);
535 auto chain = storage.MakeChain(string->MakeChain());
536
537 // Filter.
538 Constraint c{0, FilterOp::kIsNull, SqlValue()};
539 QueryExecutor exec({chain.get()}, 5);
540 RowMap res = exec.Filter({c});
541
542 ASSERT_EQ(res.size(), 1u);
543 ASSERT_EQ(res.Get(0), 2u);
544 }
545
TEST(QueryExecutor,StringSearchGtSorted)546 TEST(QueryExecutor, StringSearchGtSorted) {
547 StringPool pool;
548 std::vector<std::string> strings{"apple", "burger", "cheese",
549 "doughnut", "eggplant", "fries"};
550 std::vector<StringPool::Id> ids;
551 for (const auto& string : strings) {
552 ids.push_back(pool.InternString(base::StringView(string)));
553 }
554 auto string = std::make_unique<StringStorage>(&pool, &ids, true);
555
556 // Final vec {"apple", "burger", "doughnut", "eggplant"}.
557 BitVector selector_bv{1, 1, 0, 1, 1, 0};
558 SelectorOverlay storage(&selector_bv);
559 auto chain = storage.MakeChain(string->MakeChain());
560
561 // Filter.
562 Constraint c{0, FilterOp::kGe, SqlValue::String("camembert")};
563 QueryExecutor exec({chain.get()}, 4);
564 RowMap res = exec.Filter({c});
565
566 ASSERT_EQ(res.size(), 2u);
567 ASSERT_EQ(res.Get(0), 2u);
568 }
569
TEST(QueryExecutor,StringSearchNeSorted)570 TEST(QueryExecutor, StringSearchNeSorted) {
571 StringPool pool;
572 std::vector<std::string> strings{"apple", "burger", "cheese",
573 "doughnut", "eggplant", "fries"};
574 std::vector<StringPool::Id> ids;
575 for (const auto& string : strings) {
576 ids.push_back(pool.InternString(base::StringView(string)));
577 }
578 auto string = std::make_unique<StringStorage>(&pool, &ids, true);
579
580 // Final vec {"apple", "burger", "doughnut", "eggplant"}.
581 BitVector selector_bv{1, 1, 0, 1, 1, 0};
582 SelectorOverlay storage(&selector_bv);
583 auto chain = storage.MakeChain(string->MakeChain());
584
585 // Filter.
586 Constraint c{0, FilterOp::kNe, SqlValue::String("doughnut")};
587 QueryExecutor exec({chain.get()}, 4);
588 RowMap res = exec.Filter({c});
589
590 ASSERT_EQ(res.size(), 3u);
591 ASSERT_EQ(res.Get(0), 0u);
592 }
593
TEST(QueryExecutor,MismatchedTypeIdWithString)594 TEST(QueryExecutor, MismatchedTypeIdWithString) {
595 IdStorage storage;
596 auto chain = storage.MakeChain();
597
598 // Filter.
599 Constraint c{0, FilterOp::kGe, SqlValue::String("cheese")};
600 QueryExecutor exec({chain.get()}, 5);
601 RowMap res = exec.Filter({c});
602
603 ASSERT_EQ(res.size(), 0u);
604 }
605
TEST(QueryExecutor,MismatchedTypeIdWithDouble)606 TEST(QueryExecutor, MismatchedTypeIdWithDouble) {
607 IdStorage storage;
608 auto chain = storage.MakeChain();
609
610 // Filter.
611 Constraint c{0, FilterOp::kGe, SqlValue::Double(1.5)};
612 QueryExecutor exec({chain.get()}, 5);
613 RowMap res = exec.Filter({c});
614
615 ASSERT_EQ(res.size(), 3u);
616 }
617
TEST(QueryExecutor,MismatchedTypeSetIdWithDouble)618 TEST(QueryExecutor, MismatchedTypeSetIdWithDouble) {
619 std::vector<uint32_t> storage_data{0, 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9};
620 SetIdStorage storage(&storage_data);
621 auto chain = storage.MakeChain();
622
623 // Filter.
624 Constraint c{0, FilterOp::kGe, SqlValue::Double(1.5)};
625 QueryExecutor exec({chain.get()}, chain->size());
626 RowMap res = exec.Filter({c});
627
628 ASSERT_EQ(res.size(), 9u);
629 }
630
631 #if !PERFETTO_BUILDFLAG(PERFETTO_OS_WIN)
TEST(QueryExecutor,StringBinarySearchRegex)632 TEST(QueryExecutor, StringBinarySearchRegex) {
633 StringPool pool;
634 std::vector<std::string> strings{"cheese", "pasta", "pizza",
635 "pierogi", "onion", "fries"};
636 std::vector<StringPool::Id> ids;
637 for (const auto& string : strings) {
638 ids.push_back(pool.InternString(base::StringView(string)));
639 }
640 ids.insert(ids.begin() + 3, StringPool::Id::Null());
641 auto string = std::make_unique<StringStorage>(&pool, &ids);
642
643 // Final vec {"cheese", "pasta", "NULL", "pierogi", "fries"}.
644 BitVector selector_bv{1, 1, 0, 1, 1, 0, 1};
645 SelectorOverlay storage(&selector_bv);
646 auto chain = storage.MakeChain(string->MakeChain());
647
648 // Filter.
649 Constraint c{0, FilterOp::kRegex, SqlValue::String("p.*")};
650 QueryExecutor exec({chain.get()}, 5);
651 RowMap res = exec.Filter({c});
652
653 ASSERT_EQ(res.size(), 2u);
654 ASSERT_EQ(res.Get(0), 1u);
655 ASSERT_EQ(res.Get(1), 3u);
656 }
657
TEST(QueryExecutor,StringBinarySearchRegexWithNum)658 TEST(QueryExecutor, StringBinarySearchRegexWithNum) {
659 StringPool pool;
660 std::vector<std::string> strings{"cheese", "pasta", "pizza",
661 "pierogi", "onion", "fries"};
662 std::vector<StringPool::Id> ids;
663 for (const auto& string : strings) {
664 ids.push_back(pool.InternString(base::StringView(string)));
665 }
666 ids.insert(ids.begin() + 3, StringPool::Id::Null());
667 auto string = std::make_unique<StringStorage>(&pool, &ids);
668
669 // Final vec {"cheese", "pasta", "NULL", "pierogi", "fries"}.
670 BitVector selector_bv{1, 1, 0, 1, 1, 0, 1};
671 SelectorOverlay storage(&selector_bv);
672 auto chain = storage.MakeChain(string->MakeChain());
673
674 // Filter.
675 Constraint c{0, FilterOp::kRegex, SqlValue::Long(4)};
676 QueryExecutor exec({chain.get()}, 5);
677 RowMap res = exec.Filter({c});
678
679 ASSERT_EQ(res.size(), 0u);
680 }
681 #endif
682
683 } // namespace
684 } // namespace perfetto::trace_processor
685