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