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/perfetto_sql/engine/perfetto_sql_engine.h"
18
19 #include "src/trace_processor/sqlite/sql_source.h"
20 #include "src/trace_processor/tables/slice_tables_py.h"
21 #include "test/gtest_and_gmock.h"
22
23 namespace perfetto {
24 namespace trace_processor {
25 namespace {
26
27 class PerfettoSqlEngineTest : public ::testing::Test {
28 protected:
29 StringPool pool_;
30 PerfettoSqlEngine engine_{&pool_};
31 };
32
CreateTestModule(std::vector<std::pair<std::string,std::string>> files)33 sql_modules::RegisteredModule CreateTestModule(
34 std::vector<std::pair<std::string, std::string>> files) {
35 sql_modules::RegisteredModule result;
36 for (auto& file : files) {
37 result.include_key_to_file[file.first] =
38 sql_modules::RegisteredModule::ModuleFile{file.second, false};
39 }
40 return result;
41 }
42
43 // These are the smoke tests for the perfetto SQL engine, focusing on
44 // ensuring that the correct statements do not return an error and that
45 // incorrect statements do.
46 //
47 // Functional tests are covered by the diff tests in
48 // test/trace_processor/diff_tests/syntax/perfetto_sql.
49
TEST_F(PerfettoSqlEngineTest,Function_Create)50 TEST_F(PerfettoSqlEngineTest, Function_Create) {
51 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
52 "CREATE PERFETTO FUNCTION foo() RETURNS INT AS select 1"));
53 ASSERT_TRUE(res.ok()) << res.status().c_message();
54
55 res = engine_.Execute(
56 SqlSource::FromExecuteQuery("creatE PeRfEttO FUNCTION foo(x INT, y LONG) "
57 "RETURNS INT AS select :x + :y"));
58 ASSERT_TRUE(res.ok()) << res.status().c_message();
59 }
60
TEST_F(PerfettoSqlEngineTest,Function_CreateWithArgs)61 TEST_F(PerfettoSqlEngineTest, Function_CreateWithArgs) {
62 auto res = engine_.ExecuteUntilLastStatement(
63 SqlSource::FromExecuteQuery("creatE PeRfEttO FUNCTION foo(x INT, y LONG) "
64 "RETURNS INT AS select $x + $y;"
65 "SELECT foo(1, 2)"));
66 ASSERT_TRUE(res.ok()) << res.status().c_message();
67 ASSERT_FALSE(res->stmt.IsDone());
68 ASSERT_EQ(sqlite3_column_int64(res->stmt.sqlite_stmt(), 0), 3);
69 ASSERT_FALSE(res->stmt.Step());
70 }
71
TEST_F(PerfettoSqlEngineTest,Function_Invalid)72 TEST_F(PerfettoSqlEngineTest, Function_Invalid) {
73 auto res = engine_.ExecuteUntilLastStatement(
74 SqlSource::FromExecuteQuery("creatE PeRfEttO FUNCTION foo(x INT, y LONG) "
75 "AS select $x + $y;"
76 "SELECT foo(1, 2)"));
77 ASSERT_FALSE(res.ok());
78 }
79
TEST_F(PerfettoSqlEngineTest,Function_Duplicates)80 TEST_F(PerfettoSqlEngineTest, Function_Duplicates) {
81 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
82 "CREATE PERFETTO FUNCTION foo() RETURNS INT AS SELECT 1"));
83 ASSERT_TRUE(res.ok()) << res.status().c_message();
84
85 res = engine_.Execute(SqlSource::FromExecuteQuery(
86 "CREATE PERFETTO FUNCTION foo() RETURNS INT AS SELECT 2"));
87 ASSERT_FALSE(res.ok());
88
89 res = engine_.Execute(SqlSource::FromExecuteQuery(
90 "CREATE OR REPLACE PERFETTO FUNCTION foo() RETURNS INT AS SELECT 3"));
91 ASSERT_TRUE(res.ok()) << res.status().c_message();
92 }
93
TEST_F(PerfettoSqlEngineTest,TableFunction_Create)94 TEST_F(PerfettoSqlEngineTest, TableFunction_Create) {
95 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
96 "CREATE PERFETTO FUNCTION foo() RETURNS TABLE(x INT) AS "
97 "select 1 AS x"));
98 ASSERT_TRUE(res.ok()) << res.status().c_message();
99 }
100
TEST_F(PerfettoSqlEngineTest,TableFunction_Duplicates)101 TEST_F(PerfettoSqlEngineTest, TableFunction_Duplicates) {
102 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
103 "CREATE PERFETTO FUNCTION foo() RETURNS TABLE(x INT) AS "
104 "select 1 AS x"));
105 ASSERT_TRUE(res.ok()) << res.status().c_message();
106
107 res = engine_.Execute(SqlSource::FromExecuteQuery(
108 "CREATE PERFETTO FUNCTION foo() RETURNS TABLE(x INT) AS "
109 "select 1 AS x"));
110 ASSERT_FALSE(res.ok());
111
112 res = engine_.Execute(SqlSource::FromExecuteQuery(
113 "CREATE OR REPLACE PERFETTO FUNCTION foo() RETURNS TABLE(x INT) AS "
114 "select 2 AS x"));
115 ASSERT_TRUE(res.ok()) << res.status().c_message();
116 }
117
TEST_F(PerfettoSqlEngineTest,Table_Create)118 TEST_F(PerfettoSqlEngineTest, Table_Create) {
119 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
120 "CREATE PERFETTO TABLE foo AS SELECT 42 AS bar"));
121 ASSERT_TRUE(res.ok()) << res.status().c_message();
122 }
123
TEST_F(PerfettoSqlEngineTest,Table_StringColumns)124 TEST_F(PerfettoSqlEngineTest, Table_StringColumns) {
125 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
126 "CREATE PERFETTO TABLE foo AS SELECT 'foo' AS bar"));
127 ASSERT_TRUE(res.ok()) << res.status().c_message();
128 }
129
TEST_F(PerfettoSqlEngineTest,Table_Schema)130 TEST_F(PerfettoSqlEngineTest, Table_Schema) {
131 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
132 "CREATE PERFETTO TABLE foo(bar INT) AS SELECT 42 AS bar"));
133 ASSERT_TRUE(res.ok()) << res.status().c_message();
134
135 res = engine_.Execute(SqlSource::FromExecuteQuery(
136 "CREATE PERFETTO TABLE foo2(bar INT) AS SELECT 42 AS bar; SELECT 1"));
137 ASSERT_TRUE(res.ok()) << res.status().c_message();
138 }
139
TEST_F(PerfettoSqlEngineTest,Table_IncorrectSchema)140 TEST_F(PerfettoSqlEngineTest, Table_IncorrectSchema) {
141 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
142 "CREATE PERFETTO TABLE foo(x INT) AS SELECT 1 as y"));
143 ASSERT_FALSE(res.ok());
144 EXPECT_THAT(
145 res.status().c_message(),
146 testing::EndsWith("CREATE PERFETTO TABLE: the following columns are "
147 "declared in the schema, but do not exist: x; and the "
148 "folowing columns exist, but are not declared: y"));
149 }
150
TEST_F(PerfettoSqlEngineTest,Table_Drop)151 TEST_F(PerfettoSqlEngineTest, Table_Drop) {
152 auto res_create = engine_.Execute(SqlSource::FromExecuteQuery(
153 "CREATE PERFETTO TABLE foo AS SELECT 'foo' AS bar"));
154 ASSERT_TRUE(res_create.ok());
155
156 auto res_drop =
157 engine_.Execute(SqlSource::FromExecuteQuery("DROP TABLE foo"));
158 ASSERT_TRUE(res_drop.ok());
159 }
160
TEST_F(PerfettoSqlEngineTest,Table_Duplicates)161 TEST_F(PerfettoSqlEngineTest, Table_Duplicates) {
162 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
163 "CREATE PERFETTO TABLE foo AS SELECT 1 as bar"));
164 ASSERT_TRUE(res.ok()) << res.status().c_message();
165
166 res = engine_.Execute(SqlSource::FromExecuteQuery(
167 "CREATE PERFETTO TABLE foo AS SELECT 1 as bar"));
168 ASSERT_FALSE(res.ok());
169
170 res = engine_.Execute(SqlSource::FromExecuteQuery(
171 "CREATE OR REPLACE PERFETTO TABLE foo AS SELECT 1 as bar"));
172 ASSERT_TRUE(res.ok()) << res.status().c_message();
173 }
174
TEST_F(PerfettoSqlEngineTest,View_Create)175 TEST_F(PerfettoSqlEngineTest, View_Create) {
176 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
177 "CREATE PERFETTO VIEW foo AS SELECT 42 AS bar"));
178 ASSERT_TRUE(res.ok()) << res.status().c_message();
179 }
180
TEST_F(PerfettoSqlEngineTest,View_Schema)181 TEST_F(PerfettoSqlEngineTest, View_Schema) {
182 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
183 "CREATE PERFETTO VIEW foo(bar INT) AS SELECT 42 AS bar"));
184 ASSERT_TRUE(res.ok()) << res.status().c_message();
185
186 res = engine_.Execute(SqlSource::FromExecuteQuery(
187 "CREATE PERFETTO VIEW foo2(bar INT) AS SELECT 42 AS bar; SELECT 1"));
188 ASSERT_TRUE(res.ok()) << res.status().c_message();
189 }
190
TEST_F(PerfettoSqlEngineTest,View_Drop)191 TEST_F(PerfettoSqlEngineTest, View_Drop) {
192 auto res_create = engine_.Execute(SqlSource::FromExecuteQuery(
193 "CREATE PERFETTO VIEW foo AS SELECT 'foo' AS bar"));
194 ASSERT_TRUE(res_create.ok());
195
196 auto res_drop = engine_.Execute(SqlSource::FromExecuteQuery("DROP VIEW foo"));
197 ASSERT_TRUE(res_drop.ok());
198 }
199
TEST_F(PerfettoSqlEngineTest,View_IncorrectSchema)200 TEST_F(PerfettoSqlEngineTest, View_IncorrectSchema) {
201 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
202 "CREATE PERFETTO VIEW foo(x INT) AS SELECT 1 as y"));
203 ASSERT_FALSE(res.ok());
204 EXPECT_THAT(
205 res.status().c_message(),
206 testing::EndsWith("CREATE PERFETTO VIEW: the following columns are "
207 "declared in the schema, but do not exist: x; and the "
208 "folowing columns exist, but are not declared: y"));
209 }
210
TEST_F(PerfettoSqlEngineTest,View_Duplicates)211 TEST_F(PerfettoSqlEngineTest, View_Duplicates) {
212 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
213 "CREATE PERFETTO VIEW foo AS SELECT 1 as bar"));
214 ASSERT_TRUE(res.ok()) << res.status().c_message();
215
216 res = engine_.Execute(SqlSource::FromExecuteQuery(
217 "CREATE PERFETTO VIEW foo AS SELECT 1 as bar"));
218 ASSERT_FALSE(res.ok());
219
220 res = engine_.Execute(SqlSource::FromExecuteQuery(
221 "CREATE OR REPLACE PERFETTO VIEW foo AS SELECT 1 as bar"));
222 ASSERT_TRUE(res.ok()) << res.status().c_message();
223 }
224
TEST_F(PerfettoSqlEngineTest,Macro_Create)225 TEST_F(PerfettoSqlEngineTest, Macro_Create) {
226 auto res_create = engine_.Execute(SqlSource::FromExecuteQuery(
227 "CREATE PERFETTO MACRO foo() RETURNS TableOrSubquery AS select 42 AS x"));
228 ASSERT_TRUE(res_create.ok()) << res_create.status().c_message();
229
230 res_create = engine_.Execute(SqlSource::FromExecuteQuery(
231 "CREATE PERFETTO MACRO bar(x TableOrSubquery) RETURNS TableOrSubquery AS "
232 "select * from $x"));
233 ASSERT_TRUE(res_create.ok()) << res_create.status().c_message();
234
235 auto res = engine_.ExecuteUntilLastStatement(
236 SqlSource::FromExecuteQuery("bar!((foo!()))"));
237 ASSERT_TRUE(res.ok()) << res.status().c_message();
238 ASSERT_FALSE(res->stmt.IsDone());
239 ASSERT_EQ(sqlite3_column_int64(res->stmt.sqlite_stmt(), 0), 42);
240 ASSERT_FALSE(res->stmt.Step());
241 }
242
TEST_F(PerfettoSqlEngineTest,Macro_Duplicates)243 TEST_F(PerfettoSqlEngineTest, Macro_Duplicates) {
244 auto res = engine_.Execute(SqlSource::FromExecuteQuery(
245 "CREATE PERFETTO MACRO foo() RETURNS TableOrSubquery AS select 42 AS x"));
246 ASSERT_TRUE(res.ok()) << res.status().c_message();
247
248 res = engine_.Execute(SqlSource::FromExecuteQuery(
249 "CREATE PERFETTO MACRO foo() RETURNS TableOrSubquery AS select 42 AS x"));
250 ASSERT_FALSE(res.ok());
251
252 res = engine_.Execute(
253 SqlSource::FromExecuteQuery("CREATE OR REPLACE PERFETTO MACRO foo() "
254 "RETURNS TableOrSubquery AS select 42 AS x"));
255 ASSERT_TRUE(res.ok());
256 }
257
TEST_F(PerfettoSqlEngineTest,Include_All)258 TEST_F(PerfettoSqlEngineTest, Include_All) {
259 engine_.RegisterModule(
260 "foo", CreateTestModule(
261 {{"foo.foo", "CREATE PERFETTO TABLE foo AS SELECT 42 AS x"}}));
262 engine_.RegisterModule(
263 "bar",
264 CreateTestModule(
265 {{"bar.bar", "CREATE PERFETTO TABLE bar AS SELECT 42 AS x "}}));
266
267 auto res_create =
268 engine_.Execute(SqlSource::FromExecuteQuery("INCLUDE PERFETTO MODULE *"));
269 ASSERT_TRUE(res_create.ok()) << res_create.status().c_message();
270 ASSERT_TRUE(
271 engine_.FindModule("foo")->include_key_to_file["foo.foo"].included);
272 ASSERT_TRUE(
273 engine_.FindModule("bar")->include_key_to_file["bar.bar"].included);
274 }
275
TEST_F(PerfettoSqlEngineTest,Include_Module)276 TEST_F(PerfettoSqlEngineTest, Include_Module) {
277 engine_.RegisterModule(
278 "foo", CreateTestModule({
279 {"foo.foo1", "CREATE PERFETTO TABLE foo1 AS SELECT 42 AS x"},
280 {"foo.foo2", "CREATE PERFETTO TABLE foo2 AS SELECT 42 AS x"},
281 }));
282 engine_.RegisterModule(
283 "bar",
284 CreateTestModule(
285 {{"bar.bar", "CREATE PERFETTO TABLE bar AS SELECT 42 AS x "}}));
286
287 auto res_create = engine_.Execute(
288 SqlSource::FromExecuteQuery("INCLUDE PERFETTO MODULE foo.*"));
289 ASSERT_TRUE(res_create.ok()) << res_create.status().c_message();
290 ASSERT_TRUE(
291 engine_.FindModule("foo")->include_key_to_file["foo.foo1"].included);
292 ASSERT_TRUE(
293 engine_.FindModule("foo")->include_key_to_file["foo.foo2"].included);
294 ASSERT_FALSE(
295 engine_.FindModule("bar")->include_key_to_file["bar.bar"].included);
296 }
297
TEST_F(PerfettoSqlEngineTest,MismatchedRange)298 TEST_F(PerfettoSqlEngineTest, MismatchedRange) {
299 tables::SliceTable parent(&pool_);
300 tables::ExpectedFrameTimelineSliceTable child(&pool_, &parent);
301
302 engine_.RegisterStaticTable(parent, "parent",
303 tables::SliceTable::ComputeStaticSchema());
304 engine_.RegisterStaticTable(
305 child, "child",
306 tables::ExpectedFrameTimelineSliceTable::ComputeStaticSchema());
307
308 for (uint32_t i = 0; i < 5; i++) {
309 child.Insert({});
310 }
311
312 for (uint32_t i = 0; i < 10; i++) {
313 parent.Insert({});
314 }
315
316 auto res = engine_.Execute(
317 SqlSource::FromExecuteQuery("SELECT * FROM child WHERE ts > 3"));
318 ASSERT_TRUE(res.ok()) << res.status().c_message();
319 }
320
321 } // namespace
322 } // namespace trace_processor
323 } // namespace perfetto
324