• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_parser.h"
18 
19 #include <cstdint>
20 #include <variant>
21 #include <vector>
22 
23 #include "perfetto/base/logging.h"
24 #include "perfetto/ext/base/status_or.h"
25 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_test_utils.h"
26 #include "src/trace_processor/sqlite/sql_source.h"
27 #include "test/gtest_and_gmock.h"
28 
29 namespace perfetto {
30 namespace trace_processor {
31 
32 using Result = PerfettoSqlParser::Statement;
33 using Statement = PerfettoSqlParser::Statement;
34 using SqliteSql = PerfettoSqlParser::SqliteSql;
35 using CreateFn = PerfettoSqlParser::CreateFunction;
36 using CreateTable = PerfettoSqlParser::CreateTable;
37 using CreateView = PerfettoSqlParser::CreateView;
38 using Include = PerfettoSqlParser::Include;
39 using CreateMacro = PerfettoSqlParser::CreateMacro;
40 
41 namespace {
42 
43 class PerfettoSqlParserTest : public ::testing::Test {
44  protected:
Parse(SqlSource sql)45   base::StatusOr<std::vector<PerfettoSqlParser::Statement>> Parse(
46       SqlSource sql) {
47     PerfettoSqlParser parser(sql, macros_);
48     std::vector<PerfettoSqlParser::Statement> results;
49     while (parser.Next()) {
50       results.push_back(std::move(parser.statement()));
51     }
52     if (!parser.status().ok()) {
53       return parser.status();
54     }
55     return results;
56   }
57 
58   base::FlatHashMap<std::string, PerfettoSqlPreprocessor::Macro> macros_;
59 };
60 
TEST_F(PerfettoSqlParserTest,Empty)61 TEST_F(PerfettoSqlParserTest, Empty) {
62   ASSERT_THAT(*Parse(SqlSource::FromExecuteQuery("")), testing::IsEmpty());
63 }
64 
TEST_F(PerfettoSqlParserTest,SemiColonTerminatedStatement)65 TEST_F(PerfettoSqlParserTest, SemiColonTerminatedStatement) {
66   SqlSource res = SqlSource::FromExecuteQuery("SELECT * FROM slice;");
67   PerfettoSqlParser parser(res, macros_);
68   ASSERT_TRUE(parser.Next());
69   ASSERT_EQ(parser.statement(), Statement{SqliteSql{}});
70   ASSERT_EQ(parser.statement_sql(), FindSubstr(res, "SELECT * FROM slice"));
71 }
72 
TEST_F(PerfettoSqlParserTest,MultipleStmts)73 TEST_F(PerfettoSqlParserTest, MultipleStmts) {
74   auto res =
75       SqlSource::FromExecuteQuery("SELECT * FROM slice; SELECT * FROM s");
76   PerfettoSqlParser parser(res, macros_);
77   ASSERT_TRUE(parser.Next());
78   ASSERT_EQ(parser.statement(), Statement{SqliteSql{}});
79   ASSERT_EQ(parser.statement_sql().sql(),
80             FindSubstr(res, "SELECT * FROM slice").sql());
81   ASSERT_TRUE(parser.Next());
82   ASSERT_EQ(parser.statement(), Statement{SqliteSql{}});
83   ASSERT_EQ(parser.statement_sql().sql(),
84             FindSubstr(res, "SELECT * FROM s").sql());
85 }
86 
TEST_F(PerfettoSqlParserTest,IgnoreOnlySpace)87 TEST_F(PerfettoSqlParserTest, IgnoreOnlySpace) {
88   auto res = SqlSource::FromExecuteQuery(" ; SELECT * FROM s; ; ;");
89   PerfettoSqlParser parser(res, macros_);
90   ASSERT_TRUE(parser.Next());
91   ASSERT_EQ(parser.statement(), Statement{SqliteSql{}});
92   ASSERT_EQ(parser.statement_sql().sql(),
93             FindSubstr(res, "SELECT * FROM s").sql());
94 }
95 
TEST_F(PerfettoSqlParserTest,CreatePerfettoFunctionScalar)96 TEST_F(PerfettoSqlParserTest, CreatePerfettoFunctionScalar) {
97   auto res = SqlSource::FromExecuteQuery(
98       "create perfetto function foo() returns INT as select 1");
99   ASSERT_THAT(*Parse(res), testing::ElementsAre(CreateFn{
100                                false, FunctionPrototype{"foo", {}}, "INT",
101                                FindSubstr(res, "select 1"), false}));
102 
103   res = SqlSource::FromExecuteQuery(
104       "create perfetto function bar(x INT, y LONG) returns STRING as "
105       "select 'foo'");
106   ASSERT_THAT(*Parse(res),
107               testing::ElementsAre(
108                   CreateFn{false,
109                            FunctionPrototype{
110                                "bar",
111                                {
112                                    {"$x", sql_argument::Type::kInt},
113                                    {"$y", sql_argument::Type::kLong},
114                                },
115                            },
116                            "STRING", FindSubstr(res, "select 'foo'"), false}));
117 
118   res = SqlSource::FromExecuteQuery(
119       "CREATE perfetto FuNcTiOn bar(x INT, y LONG) returnS STRING As "
120       "select 'foo'");
121   ASSERT_THAT(*Parse(res),
122               testing::ElementsAre(
123                   CreateFn{false,
124                            FunctionPrototype{
125                                "bar",
126                                {
127                                    {"$x", sql_argument::Type::kInt},
128                                    {"$y", sql_argument::Type::kLong},
129                                },
130                            },
131                            "STRING", FindSubstr(res, "select 'foo'"), false}));
132 }
133 
TEST_F(PerfettoSqlParserTest,CreateOrReplacePerfettoFunctionScalar)134 TEST_F(PerfettoSqlParserTest, CreateOrReplacePerfettoFunctionScalar) {
135   auto res = SqlSource::FromExecuteQuery(
136       "create or replace perfetto function foo() returns INT as select 1");
137   ASSERT_THAT(*Parse(res), testing::ElementsAre(CreateFn{
138                                true, FunctionPrototype{"foo", {}}, "INT",
139                                FindSubstr(res, "select 1"), false}));
140 }
141 
TEST_F(PerfettoSqlParserTest,CreatePerfettoFunctionScalarError)142 TEST_F(PerfettoSqlParserTest, CreatePerfettoFunctionScalarError) {
143   auto res = SqlSource::FromExecuteQuery(
144       "create perfetto function foo( returns INT as select 1");
145   ASSERT_FALSE(Parse(res).status().ok());
146 
147   res = SqlSource::FromExecuteQuery(
148       "create perfetto function foo(x INT) as select 1");
149   ASSERT_FALSE(Parse(res).status().ok());
150 
151   res = SqlSource::FromExecuteQuery(
152       "create perfetto function foo(x INT) returns INT");
153   ASSERT_FALSE(Parse(res).status().ok());
154 }
155 
TEST_F(PerfettoSqlParserTest,CreatePerfettoFunctionAndOther)156 TEST_F(PerfettoSqlParserTest, CreatePerfettoFunctionAndOther) {
157   auto res = SqlSource::FromExecuteQuery(
158       "create perfetto function foo() returns INT as select 1; select foo()");
159   PerfettoSqlParser parser(res, macros_);
160   ASSERT_TRUE(parser.Next());
161   CreateFn fn{false, FunctionPrototype{"foo", {}}, "INT",
162               FindSubstr(res, "select 1"), false};
163   ASSERT_EQ(parser.statement(), Statement{fn});
164   ASSERT_EQ(
165       parser.statement_sql().sql(),
166       FindSubstr(res, "create perfetto function foo() returns INT as select 1")
167           .sql());
168   ASSERT_TRUE(parser.Next());
169   ASSERT_EQ(parser.statement(), Statement{SqliteSql{}});
170   ASSERT_EQ(parser.statement_sql().sql(),
171             FindSubstr(res, "select foo()").sql());
172 }
173 
TEST_F(PerfettoSqlParserTest,IncludePerfettoTrivial)174 TEST_F(PerfettoSqlParserTest, IncludePerfettoTrivial) {
175   auto res =
176       SqlSource::FromExecuteQuery("include perfetto module cheese.bre_ad;");
177   ASSERT_THAT(*Parse(res), testing::ElementsAre(Include{"cheese.bre_ad"}));
178 }
179 
TEST_F(PerfettoSqlParserTest,IncludePerfettoErrorAdditionalChars)180 TEST_F(PerfettoSqlParserTest, IncludePerfettoErrorAdditionalChars) {
181   auto res = SqlSource::FromExecuteQuery(
182       "include perfetto module cheese.bre_ad blabla;");
183   ASSERT_FALSE(Parse(res).status().ok());
184 }
185 
TEST_F(PerfettoSqlParserTest,IncludePerfettoErrorWrongModuleName)186 TEST_F(PerfettoSqlParserTest, IncludePerfettoErrorWrongModuleName) {
187   auto res =
188       SqlSource::FromExecuteQuery("include perfetto module chees*e.bre_ad;");
189   ASSERT_FALSE(Parse(res).status().ok());
190 }
191 
TEST_F(PerfettoSqlParserTest,CreatePerfettoMacro)192 TEST_F(PerfettoSqlParserTest, CreatePerfettoMacro) {
193   auto res = SqlSource::FromExecuteQuery(
194       "create perfetto macro foo(a1 Expr, b1 TableOrSubquery,c3_d "
195       "TableOrSubquery2 ) returns TableOrSubquery3 as random sql snippet");
196   PerfettoSqlParser parser(res, macros_);
197   ASSERT_TRUE(parser.Next());
198   ASSERT_EQ(
199       parser.statement(),
200       Statement(CreateMacro{
201           false,
202           FindSubstr(res, "foo"),
203           {
204               {FindSubstr(res, "a1"), FindSubstr(res, "Expr")},
205               {FindSubstr(res, "b1"), FindSubstr(res, "TableOrSubquery")},
206               {FindSubstr(res, "c3_d"), FindSubstr(res, "TableOrSubquery2")},
207           },
208           FindSubstr(res, "TableOrSubquery3"),
209           FindSubstr(res, "random sql snippet")}));
210   ASSERT_FALSE(parser.Next());
211 }
212 
TEST_F(PerfettoSqlParserTest,CreateOrReplacePerfettoMacro)213 TEST_F(PerfettoSqlParserTest, CreateOrReplacePerfettoMacro) {
214   auto res = SqlSource::FromExecuteQuery(
215       "create or replace perfetto macro foo() returns Expr as 1");
216   PerfettoSqlParser parser(res, macros_);
217   ASSERT_TRUE(parser.Next());
218   ASSERT_EQ(parser.statement(), Statement(CreateMacro{true,
219                                                       FindSubstr(res, "foo"),
220                                                       {},
221                                                       FindSubstr(res, "Expr"),
222                                                       FindSubstr(res, "1")}));
223   ASSERT_FALSE(parser.Next());
224 }
225 
TEST_F(PerfettoSqlParserTest,CreatePerfettoMacroAndOther)226 TEST_F(PerfettoSqlParserTest, CreatePerfettoMacroAndOther) {
227   auto res = SqlSource::FromExecuteQuery(
228       "create perfetto macro foo() returns sql1 as random sql snippet; "
229       "select 1");
230   PerfettoSqlParser parser(res, macros_);
231   ASSERT_TRUE(parser.Next());
232   ASSERT_EQ(parser.statement(), Statement(CreateMacro{
233                                     false,
234                                     FindSubstr(res, "foo"),
235                                     {},
236                                     FindSubstr(res, "sql1"),
237                                     FindSubstr(res, "random sql snippet"),
238                                 }));
239   ASSERT_TRUE(parser.Next());
240   ASSERT_EQ(parser.statement(), Statement(SqliteSql{}));
241   ASSERT_EQ(parser.statement_sql(), FindSubstr(res, "select 1"));
242   ASSERT_FALSE(parser.Next());
243 }
244 
TEST_F(PerfettoSqlParserTest,CreatePerfettoTable)245 TEST_F(PerfettoSqlParserTest, CreatePerfettoTable) {
246   auto res = SqlSource::FromExecuteQuery(
247       "CREATE PERFETTO TABLE foo AS SELECT 42 AS bar");
248   PerfettoSqlParser parser(res, macros_);
249   ASSERT_TRUE(parser.Next());
250   ASSERT_EQ(parser.statement(),
251             Statement(CreateTable{
252                 false, "foo", FindSubstr(res, "SELECT 42 AS bar"), {}}));
253   ASSERT_FALSE(parser.Next());
254 }
255 
TEST_F(PerfettoSqlParserTest,CreateOrReplacePerfettoTable)256 TEST_F(PerfettoSqlParserTest, CreateOrReplacePerfettoTable) {
257   auto res = SqlSource::FromExecuteQuery(
258       "CREATE OR REPLACE PERFETTO TABLE foo AS SELECT 42 AS bar");
259   PerfettoSqlParser parser(res, macros_);
260   ASSERT_TRUE(parser.Next());
261   ASSERT_EQ(parser.statement(),
262             Statement(CreateTable{
263                 true, "foo", FindSubstr(res, "SELECT 42 AS bar"), {}}));
264   ASSERT_FALSE(parser.Next());
265 }
266 
TEST_F(PerfettoSqlParserTest,CreatePerfettoTableWithSchema)267 TEST_F(PerfettoSqlParserTest, CreatePerfettoTableWithSchema) {
268   auto res = SqlSource::FromExecuteQuery(
269       "CREATE PERFETTO TABLE foo(bar INT) AS SELECT 42 AS bar");
270   PerfettoSqlParser parser(res, macros_);
271   ASSERT_TRUE(parser.Next());
272   ASSERT_EQ(parser.statement(), Statement(CreateTable{
273                                     false,
274                                     "foo",
275                                     FindSubstr(res, "SELECT 42 AS bar"),
276                                     {{"$bar", sql_argument::Type::kInt}},
277                                 }));
278   ASSERT_FALSE(parser.Next());
279 }
280 
TEST_F(PerfettoSqlParserTest,CreatePerfettoTableAndOther)281 TEST_F(PerfettoSqlParserTest, CreatePerfettoTableAndOther) {
282   auto res = SqlSource::FromExecuteQuery(
283       "CREATE PERFETTO TABLE foo AS SELECT 42 AS bar; select 1");
284   PerfettoSqlParser parser(res, macros_);
285   ASSERT_TRUE(parser.Next());
286   ASSERT_EQ(parser.statement(),
287             Statement(CreateTable{
288                 false, "foo", FindSubstr(res, "SELECT 42 AS bar"), {}}));
289   ASSERT_TRUE(parser.Next());
290   ASSERT_EQ(parser.statement(), Statement(SqliteSql{}));
291   ASSERT_EQ(parser.statement_sql(), FindSubstr(res, "select 1"));
292   ASSERT_FALSE(parser.Next());
293 }
294 
TEST_F(PerfettoSqlParserTest,CreatePerfettoView)295 TEST_F(PerfettoSqlParserTest, CreatePerfettoView) {
296   auto res = SqlSource::FromExecuteQuery(
297       "CREATE PERFETTO VIEW foo AS SELECT 42 AS bar");
298   PerfettoSqlParser parser(res, macros_);
299   ASSERT_TRUE(parser.Next());
300   ASSERT_EQ(
301       parser.statement(),
302       Statement(CreateView{
303           false,
304           "foo",
305           SqlSource::FromExecuteQuery("SELECT 42 AS bar"),
306           SqlSource::FromExecuteQuery("CREATE VIEW foo AS SELECT 42 AS bar"),
307           {}}));
308   ASSERT_FALSE(parser.Next());
309 }
310 
TEST_F(PerfettoSqlParserTest,CreateOrReplacePerfettoView)311 TEST_F(PerfettoSqlParserTest, CreateOrReplacePerfettoView) {
312   auto res = SqlSource::FromExecuteQuery(
313       "CREATE OR REPLACE PERFETTO VIEW foo AS SELECT 42 AS bar");
314   PerfettoSqlParser parser(res, macros_);
315   ASSERT_TRUE(parser.Next());
316   ASSERT_EQ(
317       parser.statement(),
318       Statement(CreateView{
319           true,
320           "foo",
321           SqlSource::FromExecuteQuery("SELECT 42 AS bar"),
322           SqlSource::FromExecuteQuery("CREATE VIEW foo AS SELECT 42 AS bar"),
323           {}}));
324   ASSERT_FALSE(parser.Next());
325 }
326 
TEST_F(PerfettoSqlParserTest,CreatePerfettoViewAndOther)327 TEST_F(PerfettoSqlParserTest, CreatePerfettoViewAndOther) {
328   auto res = SqlSource::FromExecuteQuery(
329       "CREATE PERFETTO VIEW foo AS SELECT 42 AS bar; select 1");
330   PerfettoSqlParser parser(res, macros_);
331   ASSERT_TRUE(parser.Next());
332   ASSERT_EQ(
333       parser.statement(),
334       Statement(CreateView{
335           false,
336           "foo",
337           SqlSource::FromExecuteQuery("SELECT 42 AS bar"),
338           SqlSource::FromExecuteQuery("CREATE VIEW foo AS SELECT 42 AS bar"),
339           {}}));
340   ASSERT_TRUE(parser.Next());
341   ASSERT_EQ(parser.statement(), Statement(SqliteSql{}));
342   ASSERT_EQ(parser.statement_sql(), FindSubstr(res, "select 1"));
343   ASSERT_FALSE(parser.Next());
344 }
345 
TEST_F(PerfettoSqlParserTest,CreatePerfettoViewWithSchema)346 TEST_F(PerfettoSqlParserTest, CreatePerfettoViewWithSchema) {
347   auto res = SqlSource::FromExecuteQuery(
348       "CREATE PERFETTO VIEW foo(foo STRING, bar INT) AS SELECT 'a' as foo, 42 "
349       "AS bar");
350   PerfettoSqlParser parser(res, macros_);
351   ASSERT_TRUE(parser.Next());
352   ASSERT_EQ(parser.statement(),
353             Statement(CreateView{
354                 false,
355                 "foo",
356                 SqlSource::FromExecuteQuery("SELECT 'a' as foo, 42 AS bar"),
357                 SqlSource::FromExecuteQuery(
358                     "CREATE VIEW foo AS SELECT 'a' as foo, 42 AS bar"),
359                 {{"$foo", sql_argument::Type::kString},
360                  {"$bar", sql_argument::Type::kInt}},
361             }));
362   ASSERT_FALSE(parser.Next());
363 }
364 
365 }  // namespace
366 }  // namespace trace_processor
367 }  // namespace perfetto
368