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