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/span_join_operator.h"
18
19 #include <sqlite3.h>
20 #include <cstddef>
21 #include <cstdint>
22 #include <memory>
23 #include <string>
24 #include <vector>
25
26 #include "src/trace_processor/containers/string_pool.h"
27 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
28 #include "src/trace_processor/sqlite/scoped_db.h"
29 #include "src/trace_processor/sqlite/sqlite_engine.h"
30 #include "test/gtest_and_gmock.h"
31
32 namespace perfetto::trace_processor {
33 namespace {
34
35 class SpanJoinOperatorTableTest : public ::testing::Test {
36 public:
SpanJoinOperatorTableTest()37 SpanJoinOperatorTableTest() {
38 engine_.sqlite_engine()->RegisterVirtualTableModule<SpanJoinOperatorModule>(
39 "span_join",
40 std::make_unique<SpanJoinOperatorModule::Context>(&engine_));
41 engine_.sqlite_engine()->RegisterVirtualTableModule<SpanJoinOperatorModule>(
42 "span_left_join",
43 std::make_unique<SpanJoinOperatorModule::Context>(&engine_));
44 }
45
PrepareValidStatement(const std::string & sql)46 void PrepareValidStatement(const std::string& sql) {
47 int size = static_cast<int>(sql.size());
48 sqlite3_stmt* stmt;
49 ASSERT_EQ(sqlite3_prepare_v2(engine_.sqlite_engine()->db(), sql.c_str(),
50 size, &stmt, nullptr),
51 SQLITE_OK);
52 stmt_.reset(stmt);
53 }
54
RunStatement(const std::string & sql)55 void RunStatement(const std::string& sql) {
56 PrepareValidStatement(sql);
57 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_DONE);
58 }
59
AssertNextRow(const std::vector<int64_t> & elements)60 void AssertNextRow(const std::vector<int64_t>& elements) {
61 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
62 for (size_t i = 0; i < elements.size(); ++i) {
63 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), static_cast<int>(i)),
64 elements[i]);
65 }
66 }
67
68 protected:
69 StringPool pool_;
70 PerfettoSqlEngine engine_{&pool_, true};
71 ScopedStmt stmt_;
72 };
73
TEST_F(SpanJoinOperatorTableTest,JoinTwoSpanTables)74 TEST_F(SpanJoinOperatorTableTest, JoinTwoSpanTables) {
75 RunStatement(
76 "CREATE TEMP TABLE f("
77 "ts BIGINT PRIMARY KEY, "
78 "dur BIGINT, "
79 "cpu UNSIGNED INT"
80 ");");
81 RunStatement(
82 "CREATE TEMP TABLE s("
83 "ts BIGINT PRIMARY KEY, "
84 "dur BIGINT, "
85 "cpu UNSIGNED INT"
86 ");");
87 RunStatement(
88 "CREATE VIRTUAL TABLE sp USING span_join(f PARTITIONED cpu, "
89 "s PARTITIONED cpu);");
90
91 RunStatement("INSERT INTO f VALUES(100, 10, 5);");
92 RunStatement("INSERT INTO f VALUES(110, 50, 5);");
93 RunStatement("INSERT INTO f VALUES(120, 100, 2);");
94 RunStatement("INSERT INTO f VALUES(160, 10, 5);");
95
96 RunStatement("INSERT INTO s VALUES(100, 5, 5);");
97 RunStatement("INSERT INTO s VALUES(105, 100, 5);");
98 RunStatement("INSERT INTO s VALUES(110, 50, 2);");
99 RunStatement("INSERT INTO s VALUES(160, 100, 2);");
100
101 PrepareValidStatement("SELECT * FROM sp");
102
103 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
104 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 120);
105 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 40);
106 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 2);
107
108 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
109 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 160);
110 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 60);
111 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 2);
112
113 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
114 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 100);
115 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 5);
116 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 5);
117
118 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
119 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 105);
120 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 5);
121 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 5);
122
123 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
124 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 110);
125 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 50);
126 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 5);
127
128 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
129 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 160);
130 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 10);
131 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 5);
132
133 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_DONE);
134 }
135
TEST_F(SpanJoinOperatorTableTest,NullPartitionKey)136 TEST_F(SpanJoinOperatorTableTest, NullPartitionKey) {
137 RunStatement(
138 "CREATE TEMP TABLE f("
139 "ts BIGINT PRIMARY KEY, "
140 "dur BIGINT, "
141 "cpu UNSIGNED INT"
142 ");");
143 RunStatement(
144 "CREATE TEMP TABLE s("
145 "ts BIGINT PRIMARY KEY, "
146 "dur BIGINT, "
147 "cpu UNSIGNED INT"
148 ");");
149 RunStatement(
150 "CREATE VIRTUAL TABLE sp USING span_join(f PARTITIONED cpu, "
151 "s PARTITIONED cpu);");
152
153 RunStatement("INSERT INTO f VALUES(30, 20, NULL);");
154 RunStatement("INSERT INTO f VALUES(100, 10, 5);");
155 RunStatement("INSERT INTO f VALUES(110, 50, 5);");
156 RunStatement("INSERT INTO f VALUES(120, 100, 2);");
157 RunStatement("INSERT INTO f VALUES(160, 10, 5);");
158
159 RunStatement("INSERT INTO s VALUES(40, 10, NULL);");
160 RunStatement("INSERT INTO s VALUES(100, 5, 5);");
161 RunStatement("INSERT INTO s VALUES(105, 100, 5);");
162 RunStatement("INSERT INTO s VALUES(110, 50, 2);");
163 RunStatement("INSERT INTO s VALUES(160, 100, 2);");
164
165 PrepareValidStatement("SELECT * FROM sp");
166
167 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
168 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 120);
169 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 40);
170 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 2);
171
172 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
173 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 160);
174 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 60);
175 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 2);
176
177 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
178 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 100);
179 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 5);
180 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 5);
181
182 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
183 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 105);
184 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 5);
185 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 5);
186
187 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
188 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 110);
189 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 50);
190 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 5);
191
192 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
193 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 160);
194 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 10);
195 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 5);
196
197 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_DONE);
198 }
199
TEST_F(SpanJoinOperatorTableTest,MixedPartitioning)200 TEST_F(SpanJoinOperatorTableTest, MixedPartitioning) {
201 RunStatement(
202 "CREATE TEMP TABLE f("
203 "ts BIGINT PRIMARY KEY, "
204 "dur BIGINT, "
205 "upid UNSIGNED INT"
206 ");");
207 RunStatement(
208 "CREATE TEMP TABLE s("
209 "ts BIGINT PRIMARY KEY, "
210 "dur BIGINT, "
211 "s_val BIGINT"
212 ");");
213 RunStatement(
214 "CREATE VIRTUAL TABLE sp USING span_join(f PARTITIONED upid, s);");
215
216 RunStatement("INSERT INTO f VALUES(30, 20, NULL);");
217 RunStatement("INSERT INTO f VALUES(100, 10, 5);");
218 RunStatement("INSERT INTO f VALUES(110, 50, 5);");
219 RunStatement("INSERT INTO f VALUES(120, 100, 2);");
220 RunStatement("INSERT INTO f VALUES(160, 10, 5);");
221 RunStatement("INSERT INTO f VALUES(300, 100, 2);");
222
223 RunStatement("INSERT INTO s VALUES(100, 5, 11111);");
224 RunStatement("INSERT INTO s VALUES(105, 5, 22222);");
225 RunStatement("INSERT INTO s VALUES(110, 60, 33333);");
226 RunStatement("INSERT INTO s VALUES(320, 10, 44444);");
227
228 PrepareValidStatement("SELECT * FROM sp");
229 AssertNextRow({120, 50, 2, 33333});
230 AssertNextRow({320, 10, 2, 44444});
231 AssertNextRow({100, 5, 5, 11111});
232 AssertNextRow({105, 5, 5, 22222});
233 AssertNextRow({110, 50, 5, 33333});
234 AssertNextRow({160, 10, 5, 33333});
235 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_DONE);
236 }
237
TEST_F(SpanJoinOperatorTableTest,NoPartitioning)238 TEST_F(SpanJoinOperatorTableTest, NoPartitioning) {
239 RunStatement(
240 "CREATE TEMP TABLE f("
241 "ts BIGINT PRIMARY KEY, "
242 "dur BIGINT, "
243 "f_val BIGINT"
244 ");");
245 RunStatement(
246 "CREATE TEMP TABLE s("
247 "ts BIGINT PRIMARY KEY, "
248 "dur BIGINT, "
249 "s_val BIGINT"
250 ");");
251 RunStatement("CREATE VIRTUAL TABLE sp USING span_join(f, s);");
252
253 RunStatement("INSERT INTO f VALUES(100, 10, 44444);");
254 RunStatement("INSERT INTO f VALUES(110, 50, 55555);");
255 RunStatement("INSERT INTO f VALUES(160, 10, 44444);");
256
257 RunStatement("INSERT INTO s VALUES(100, 5, 11111);");
258 RunStatement("INSERT INTO s VALUES(105, 5, 22222);");
259 RunStatement("INSERT INTO s VALUES(110, 60, 33333);");
260
261 PrepareValidStatement("SELECT * FROM sp");
262 AssertNextRow({100, 5, 44444, 11111});
263 AssertNextRow({105, 5, 44444, 22222});
264 AssertNextRow({110, 50, 55555, 33333});
265 AssertNextRow({160, 10, 44444, 33333});
266 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_DONE);
267 }
268
TEST_F(SpanJoinOperatorTableTest,LeftJoinTwoSpanTables)269 TEST_F(SpanJoinOperatorTableTest, LeftJoinTwoSpanTables) {
270 RunStatement(
271 "CREATE TEMP TABLE f("
272 "ts BIGINT PRIMARY KEY, "
273 "dur BIGINT, "
274 "cpu UNSIGNED INT"
275 ");");
276 RunStatement(
277 "CREATE TEMP TABLE s("
278 "ts BIGINT PRIMARY KEY, "
279 "dur BIGINT, "
280 "tid UNSIGNED INT"
281 ");");
282 RunStatement("CREATE VIRTUAL TABLE sp USING span_left_join(f, s);");
283
284 RunStatement("INSERT INTO f VALUES(100, 10, 0);");
285 RunStatement("INSERT INTO f VALUES(110, 50, 1);");
286
287 RunStatement("INSERT INTO s VALUES(100, 5, 1);");
288 RunStatement("INSERT INTO s VALUES(110, 40, 2);");
289 RunStatement("INSERT INTO s VALUES(150, 50, 3);");
290
291 PrepareValidStatement("SELECT * FROM sp");
292
293 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
294 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 100);
295 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 5);
296 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 0);
297 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 3), 1);
298
299 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
300 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 105);
301 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 5);
302 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 0);
303 ASSERT_EQ(sqlite3_column_type(stmt_.get(), 3), SQLITE_NULL);
304
305 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
306 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 110);
307 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 40);
308 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 1);
309 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 3), 2);
310
311 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
312 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 150);
313 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 10);
314 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 1);
315 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 3), 3);
316
317 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_DONE);
318 }
319
TEST_F(SpanJoinOperatorTableTest,LeftJoinTwoSpanTables_EmptyRight)320 TEST_F(SpanJoinOperatorTableTest, LeftJoinTwoSpanTables_EmptyRight) {
321 RunStatement(
322 "CREATE TEMP TABLE f("
323 "ts BIGINT PRIMARY KEY, "
324 "dur BIGINT, "
325 "cpu UNSIGNED INT"
326 ");");
327 RunStatement(
328 "CREATE TEMP TABLE s("
329 "ts BIGINT PRIMARY KEY, "
330 "dur BIGINT, "
331 "tid UNSIGNED INT"
332 ");");
333 RunStatement("CREATE VIRTUAL TABLE sp USING span_left_join(f, s);");
334
335 RunStatement("INSERT INTO f VALUES(100, 10, 0);");
336 RunStatement("INSERT INTO f VALUES(110, 50, 1);");
337
338 PrepareValidStatement("SELECT * FROM sp");
339
340 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
341 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 100);
342 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 10);
343 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 0);
344 ASSERT_EQ(sqlite3_column_type(stmt_.get(), 3), SQLITE_NULL);
345
346 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
347 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 110);
348 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 50);
349 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 1);
350 ASSERT_EQ(sqlite3_column_type(stmt_.get(), 3), SQLITE_NULL);
351
352 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_DONE);
353 }
354
TEST_F(SpanJoinOperatorTableTest,CapitalizedLeftJoin)355 TEST_F(SpanJoinOperatorTableTest, CapitalizedLeftJoin) {
356 RunStatement(
357 "CREATE TEMP TABLE f("
358 "ts BIGINT PRIMARY KEY, "
359 "dur BIGINT, "
360 "cpu UNSIGNED INT"
361 ");");
362 RunStatement(
363 "CREATE TEMP TABLE s("
364 "ts BIGINT PRIMARY KEY, "
365 "dur BIGINT, "
366 "tid UNSIGNED INT"
367 ");");
368 RunStatement("CREATE VIRTUAL TABLE sp USING SPAN_LEFT_JOIN(f, s);");
369
370 RunStatement("INSERT INTO f VALUES(100, 10, 0);");
371 RunStatement("INSERT INTO f VALUES(110, 50, 1);");
372
373 PrepareValidStatement("SELECT * FROM sp");
374
375 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
376 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 100);
377 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 10);
378 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 0);
379 ASSERT_EQ(sqlite3_column_type(stmt_.get(), 3), SQLITE_NULL);
380
381 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_ROW);
382 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 0), 110);
383 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 1), 50);
384 ASSERT_EQ(sqlite3_column_int64(stmt_.get(), 2), 1);
385 ASSERT_EQ(sqlite3_column_type(stmt_.get(), 3), SQLITE_NULL);
386
387 ASSERT_EQ(sqlite3_step(stmt_.get()), SQLITE_DONE);
388 }
389
390 } // namespace
391 } // namespace perfetto::trace_processor
392