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