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