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_preprocessor.h"
18
19 #include <optional>
20 #include <string>
21
22 #include "perfetto/ext/base/flat_hash_map.h"
23 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_test_utils.h"
24 #include "test/gtest_and_gmock.h"
25
26 namespace perfetto {
27 namespace trace_processor {
28 namespace {
29
30 using Macro = PerfettoSqlPreprocessor::Macro;
31
32 class PerfettoSqlPreprocessorUnittest : public ::testing::Test {
33 protected:
34 base::FlatHashMap<std::string, PerfettoSqlPreprocessor::Macro> macros_;
35 };
36
TEST_F(PerfettoSqlPreprocessorUnittest,Empty)37 TEST_F(PerfettoSqlPreprocessorUnittest, Empty) {
38 PerfettoSqlPreprocessor preprocessor(SqlSource::FromExecuteQuery(""),
39 macros_);
40 ASSERT_FALSE(preprocessor.NextStatement());
41 ASSERT_TRUE(preprocessor.status().ok());
42 }
43
TEST_F(PerfettoSqlPreprocessorUnittest,SemiColonTerminatedStatement)44 TEST_F(PerfettoSqlPreprocessorUnittest, SemiColonTerminatedStatement) {
45 auto source = SqlSource::FromExecuteQuery("SELECT * FROM slice;");
46 PerfettoSqlPreprocessor preprocessor(source, macros_);
47 ASSERT_TRUE(preprocessor.NextStatement());
48 ASSERT_EQ(preprocessor.statement(),
49 FindSubstr(source, "SELECT * FROM slice"));
50 ASSERT_FALSE(preprocessor.NextStatement());
51 ASSERT_TRUE(preprocessor.status().ok());
52 }
53
TEST_F(PerfettoSqlPreprocessorUnittest,IgnoreOnlySpace)54 TEST_F(PerfettoSqlPreprocessorUnittest, IgnoreOnlySpace) {
55 auto source = SqlSource::FromExecuteQuery(" ; SELECT * FROM s; ; ;");
56 PerfettoSqlPreprocessor preprocessor(source, macros_);
57 ASSERT_TRUE(preprocessor.NextStatement());
58 ASSERT_EQ(preprocessor.statement(), FindSubstr(source, "SELECT * FROM s"));
59 ASSERT_FALSE(preprocessor.NextStatement());
60 ASSERT_TRUE(preprocessor.status().ok());
61 }
62
TEST_F(PerfettoSqlPreprocessorUnittest,MultipleStmts)63 TEST_F(PerfettoSqlPreprocessorUnittest, MultipleStmts) {
64 auto source =
65 SqlSource::FromExecuteQuery("SELECT * FROM slice; SELECT * FROM s");
66 PerfettoSqlPreprocessor preprocessor(source, macros_);
67 ASSERT_TRUE(preprocessor.NextStatement());
68 ASSERT_EQ(preprocessor.statement(),
69 FindSubstr(source, "SELECT * FROM slice"));
70 ASSERT_TRUE(preprocessor.NextStatement());
71 ASSERT_EQ(preprocessor.statement(), FindSubstr(source, "SELECT * FROM s"));
72 ASSERT_FALSE(preprocessor.NextStatement());
73 ASSERT_TRUE(preprocessor.status().ok());
74 }
75
TEST_F(PerfettoSqlPreprocessorUnittest,CreateMacro)76 TEST_F(PerfettoSqlPreprocessorUnittest, CreateMacro) {
77 auto source = SqlSource::FromExecuteQuery(
78 "CREATE PERFETTO MACRO foo(a, b) AS SELECT $a + $b");
79 PerfettoSqlPreprocessor preprocessor(source, macros_);
80 ASSERT_TRUE(preprocessor.NextStatement());
81 ASSERT_EQ(
82 preprocessor.statement(),
83 FindSubstr(source, "CREATE PERFETTO MACRO foo(a, b) AS SELECT $a + $b"));
84 ASSERT_FALSE(preprocessor.NextStatement());
85 ASSERT_TRUE(preprocessor.status().ok());
86 }
87
TEST_F(PerfettoSqlPreprocessorUnittest,SingleMacro)88 TEST_F(PerfettoSqlPreprocessorUnittest, SingleMacro) {
89 auto foo = SqlSource::FromExecuteQuery(
90 "CREATE PERFETTO MACRO foo(a Expr, b Expr) Returns Expr AS "
91 "SELECT $a + $b");
92 macros_.Insert(
93 "foo",
94 Macro{false, "foo", {"a", "b"}, FindSubstr(foo, "SELECT $a + $b")});
95
96 auto source = SqlSource::FromExecuteQuery(
97 "foo!((select s.ts + r.dur from s, r), 1234); SELECT 1");
98 PerfettoSqlPreprocessor preprocessor(source, macros_);
99 ASSERT_TRUE(preprocessor.NextStatement());
100 ASSERT_EQ(preprocessor.statement().AsTraceback(0),
101 "Fully expanded statement\n"
102 " SELECT (select s.ts + r.dur from s, r) + 1234\n"
103 " ^\n"
104 "Traceback (most recent call last):\n"
105 " File \"stdin\" line 1 col 1\n"
106 " foo!((select s.ts + r.dur from s, r), 1234)\n"
107 " ^\n"
108 " File \"stdin\" line 1 col 59\n"
109 " SELECT $a + $b\n"
110 " ^\n");
111 ASSERT_EQ(preprocessor.statement().AsTraceback(7),
112 "Fully expanded statement\n"
113 " SELECT (select s.ts + r.dur from s, r) + 1234\n"
114 " ^\n"
115 "Traceback (most recent call last):\n"
116 " File \"stdin\" line 1 col 1\n"
117 " foo!((select s.ts + r.dur from s, r), 1234)\n"
118 " ^\n"
119 " File \"stdin\" line 1 col 66\n"
120 " SELECT $a + $b\n"
121 " ^\n"
122 " File \"stdin\" line 1 col 6\n"
123 " (select s.ts + r.dur from s, r)\n"
124 " ^\n");
125 ASSERT_EQ(preprocessor.statement().sql(),
126 "SELECT (select s.ts + r.dur from s, r) + 1234");
127 ASSERT_TRUE(preprocessor.NextStatement());
128 ASSERT_EQ(preprocessor.statement(), FindSubstr(source, "SELECT 1"));
129 ASSERT_FALSE(preprocessor.NextStatement());
130 ASSERT_TRUE(preprocessor.status().ok());
131 }
132
TEST_F(PerfettoSqlPreprocessorUnittest,NestedMacro)133 TEST_F(PerfettoSqlPreprocessorUnittest, NestedMacro) {
134 auto foo = SqlSource::FromExecuteQuery(
135 "CREATE PERFETTO MACRO foo(a Expr, b Expr) Returns Expr AS $a + $b");
136 macros_.Insert("foo", Macro{
137 false,
138 "foo",
139 {"a", "b"},
140 FindSubstr(foo, "$a + $b"),
141 });
142
143 auto bar = SqlSource::FromExecuteQuery(
144 "CREATE PERFETTO MACRO bar(a, b) Returns Expr AS "
145 "tfoo!($a, $b) + foo!($b, $a)");
146 macros_.Insert("bar", Macro{
147 false,
148 "bar",
149 {"a", "b"},
150 FindSubstr(bar, "foo!($a, $b) + foo!($b, $a)"),
151 });
152
153 auto source = SqlSource::FromExecuteQuery(
154 "SELECT bar!((select s.ts + r.dur from s, r), 1234); SELECT 1");
155 PerfettoSqlPreprocessor preprocessor(source, macros_);
156 ASSERT_TRUE(preprocessor.NextStatement());
157 ASSERT_EQ(preprocessor.statement().sql(),
158 "SELECT (select s.ts + r.dur from s, r) + 1234 + 1234 + "
159 "(select s.ts + r.dur from s, r)");
160 ASSERT_TRUE(preprocessor.NextStatement());
161 ASSERT_EQ(preprocessor.statement().sql(), "SELECT 1");
162 }
163
164 } // namespace
165 } // namespace trace_processor
166 } // namespace perfetto
167