xref: /aosp_15_r20/external/perfetto/src/trace_processor/perfetto_sql/parser/perfetto_sql_parser.h (revision 6dbdd20afdafa5e3ca9b8809fa73465d530080dc)
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 #ifndef SRC_TRACE_PROCESSOR_PERFETTO_SQL_PARSER_PERFETTO_SQL_PARSER_H_
18 #define SRC_TRACE_PROCESSOR_PERFETTO_SQL_PARSER_PERFETTO_SQL_PARSER_H_
19 
20 #include <optional>
21 #include <string>
22 #include <utility>
23 #include <variant>
24 #include <vector>
25 
26 #include "perfetto/ext/base/flat_hash_map.h"
27 #include "src/trace_processor/perfetto_sql/parser/function_util.h"
28 #include "src/trace_processor/perfetto_sql/preprocessor/perfetto_sql_preprocessor.h"
29 #include "src/trace_processor/perfetto_sql/tokenizer/sqlite_tokenizer.h"
30 #include "src/trace_processor/sqlite/sql_source.h"
31 #include "src/trace_processor/util/sql_argument.h"
32 
33 namespace perfetto {
34 namespace trace_processor {
35 
36 // Parser for PerfettoSQL statements. This class provides an iterator-style
37 // interface for reading all PerfettoSQL statements from a block of SQL.
38 //
39 // Usage:
40 // PerfettoSqlParser parser(my_sql_string.c_str());
41 // while (parser.Next()) {
42 //   auto& stmt = parser.statement();
43 //   // Handle |stmt| here
44 // }
45 // RETURN_IF_ERROR(r.status());
46 class PerfettoSqlParser {
47  public:
48   // Indicates that the specified SQLite SQL was extracted directly from a
49   // PerfettoSQL statement and should be directly executed with SQLite.
50   struct SqliteSql {};
51   // Indicates that the specified SQL was a CREATE PERFETTO FUNCTION statement
52   // with the following parameters.
53   struct CreateFunction {
54     bool replace;
55     FunctionPrototype prototype;
56     std::string returns;
57     SqlSource sql;
58     bool is_table;
59   };
60   // Indicates that the specified SQL was a CREATE PERFETTO TABLE statement
61   // with the following parameters.
62   struct CreateTable {
63     bool replace;
64     std::string name;
65     // SQL source for the select statement.
66     SqlSource sql;
67     std::vector<sql_argument::ArgumentDefinition> schema;
68   };
69   // Indicates that the specified SQL was a CREATE PERFETTO VIEW statement
70   // with the following parameters.
71   struct CreateView {
72     bool replace;
73     std::string name;
74     // SQL source for the select statement.
75     SqlSource select_sql;
76     // SQL source corresponding to the rewritten statement creating the
77     // underlying view.
78     SqlSource create_view_sql;
79     std::vector<sql_argument::ArgumentDefinition> schema;
80   };
81   // Indicates that the specified SQL was a CREATE PERFETTO INDEX statement
82   // with the following parameters.
83   struct CreateIndex {
84     bool replace = false;
85     std::string name;
86     std::string table_name;
87     std::vector<std::string> col_names;
88   };
89   // Indicates that the specified SQL was a DROP PERFETTO INDEX statement
90   // with the following parameters.
91   struct DropIndex {
92     std::string name;
93     std::string table_name;
94   };
95   // Indicates that the specified SQL was a INCLUDE PERFETTO MODULE statement
96   // with the following parameter.
97   struct Include {
98     std::string key;
99   };
100   // Indicates that the specified SQL was a CREATE PERFETTO MACRO statement
101   // with the following parameter.
102   struct CreateMacro {
103     bool replace;
104     SqlSource name;
105     std::vector<std::pair<SqlSource, SqlSource>> args;
106     SqlSource returns;
107     SqlSource sql;
108   };
109   using Statement = std::variant<CreateFunction,
110                                  CreateIndex,
111                                  CreateMacro,
112                                  CreateTable,
113                                  CreateView,
114                                  DropIndex,
115                                  Include,
116                                  SqliteSql>;
117 
118   // Creates a new SQL parser with the a block of PerfettoSQL statements.
119   // Concretely, the passed string can contain >1 statement.
120   explicit PerfettoSqlParser(
121       SqlSource,
122       const base::FlatHashMap<std::string, PerfettoSqlPreprocessor::Macro>&);
123 
124   // Attempts to parse to the next statement in the SQL. Returns true if
125   // a statement was successfully parsed and false if EOF was reached or the
126   // statement was not parsed correctly.
127   //
128   // Note: if this function returns false, callers *must* call |status()|: it
129   // is undefined behaviour to not do so.
130   bool Next();
131 
132   // Returns the current statement which was parsed. This function *must not* be
133   // called unless |Next()| returned true.
statement()134   Statement& statement() {
135     PERFETTO_DCHECK(statement_.has_value());
136     return statement_.value();
137   }
138 
139   // Returns the full statement which was parsed. This should return
140   // |statement()| and Perfetto SQL code that's in front. This function *must
141   // not* be called unless |Next()| returned true.
statement_sql()142   const SqlSource& statement_sql() const {
143     PERFETTO_CHECK(statement_sql_);
144     return *statement_sql_;
145   }
146 
147   // Returns the error status for the parser. This will be |base::OkStatus()|
148   // until an unrecoverable error is encountered.
status()149   const base::Status& status() const { return status_; }
150 
151  private:
152   // This cannot be moved because we keep pointers into |sql_| in
153   // |preprocessor_|.
154   PerfettoSqlParser(PerfettoSqlParser&&) = delete;
155   PerfettoSqlParser& operator=(PerfettoSqlParser&&) = delete;
156 
157   // Most of the code needs sql_argument::ArgumentDefinition, but we explcitly
158   // track raw arguments separately, as macro implementations need access to
159   // the underlying tokens.
160   struct RawArgument {
161     SqliteTokenizer::Token name;
162     SqliteTokenizer::Token type;
163     std::optional<std::pair<SqliteTokenizer::Token, SqliteTokenizer::Token>>
164         complex_arg_table_and_column;
165   };
166 
167   bool ParseCreatePerfettoFunction(
168       bool replace,
169       SqliteTokenizer::Token first_non_space_token);
170 
171   enum class TableOrView {
172     kTable,
173     kView,
174   };
175   bool ParseCreatePerfettoTableOrView(
176       bool replace,
177       SqliteTokenizer::Token first_non_space_token,
178       TableOrView table_or_view);
179 
180   bool ParseIncludePerfettoModule(SqliteTokenizer::Token first_non_space_token);
181 
182   bool ParseCreatePerfettoMacro(bool replace);
183 
184   bool ParseCreatePerfettoIndex(bool replace,
185                                 SqliteTokenizer::Token first_non_space_token);
186 
187   bool ParseDropPerfettoIndex(SqliteTokenizer::Token first_non_space_token);
188 
189   // Convert a "raw" argument (i.e. one that points to specific tokens) to the
190   // argument definition consumed by the rest of the SQL code.
191   // Guarantees to call ErrorAtToken if std::nullopt is returned.
192   std::optional<sql_argument::ArgumentDefinition> ResolveRawArgument(
193       RawArgument arg);
194   // Parse the arguments in their raw token form.
195   bool ParseRawArguments(std::vector<RawArgument>&);
196 
197   // Same as above, but also convert the raw tokens into argument definitions.
198   bool ParseArguments(std::vector<sql_argument::ArgumentDefinition>&);
199 
200   // Parse brackets of argument type. Supports arguments of type:
201   // `{type name}({table name}.{column name})`.
202   bool ParseComplexArgumentType(
203       std::pair<SqliteTokenizer::Token, SqliteTokenizer::Token>& table_and_col);
204 
205   bool ErrorAtToken(const SqliteTokenizer::Token&, const char* error, ...);
206 
207   PerfettoSqlPreprocessor preprocessor_;
208   SqliteTokenizer tokenizer_;
209 
210   base::Status status_;
211   std::optional<SqlSource> statement_sql_;
212   std::optional<Statement> statement_;
213 };
214 
215 }  // namespace trace_processor
216 }  // namespace perfetto
217 
218 #endif  // SRC_TRACE_PROCESSOR_PERFETTO_SQL_PARSER_PERFETTO_SQL_PARSER_H_
219