1 /*
2 * Copyright (C) 2019 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/runtime_table_function.h"
18
19 #include <sqlite3.h>
20 #include <cstddef>
21 #include <cstdint>
22 #include <memory>
23 #include <optional>
24 #include <string>
25 #include <utility>
26 #include <vector>
27
28 #include "perfetto/base/logging.h"
29 #include "perfetto/base/status.h"
30 #include "perfetto/ext/base/string_utils.h"
31 #include "perfetto/public/compiler.h"
32 #include "src/trace_processor/perfetto_sql/engine/perfetto_sql_engine.h"
33 #include "src/trace_processor/perfetto_sql/parser/function_util.h"
34 #include "src/trace_processor/sqlite/bindings/sqlite_result.h"
35 #include "src/trace_processor/sqlite/module_lifecycle_manager.h"
36 #include "src/trace_processor/sqlite/sqlite_utils.h"
37 #include "src/trace_processor/tp_metatrace.h"
38 #include "src/trace_processor/util/sql_argument.h"
39
40 namespace perfetto::trace_processor {
41
42 namespace {
43
ResetStatement(sqlite3_stmt * stmt)44 void ResetStatement(sqlite3_stmt* stmt) {
45 sqlite3_reset(stmt);
46 sqlite3_clear_bindings(stmt);
47 }
48
CreateTableStrFromState(RuntimeTableFunctionModule::State * state)49 auto CreateTableStrFromState(RuntimeTableFunctionModule::State* state) {
50 std::vector<std::string> columns;
51 columns.reserve(state->return_values.size());
52 for (const auto& ret : state->return_values) {
53 columns.emplace_back(ret.name().ToStdString() + " " +
54 sqlite::utils::SqlValueTypeToSqliteTypeName(
55 sql_argument::TypeToSqlValueType(ret.type())));
56 }
57 for (const auto& arg : state->prototype.arguments) {
58 // Add the "in_" prefix to every argument param to avoid clashes between the
59 // output and input parameters.
60 columns.emplace_back("in_" + arg.name().ToStdString() + " " +
61 sqlite::utils::SqlValueTypeToSqliteTypeName(
62 sql_argument::TypeToSqlValueType(arg.type())) +
63 " HIDDEN");
64 }
65 columns.emplace_back("_primary_key BIGINT HIDDEN");
66
67 std::string cols = base::Join(columns, ",");
68 return base::StackString<1024>(
69 R"(CREATE TABLE x(%s, PRIMARY KEY(_primary_key)) WITHOUT ROWID)",
70 cols.c_str());
71 }
72
73 } // namespace
74
Create(sqlite3 * db,void * ctx,int,const char * const * argv,sqlite3_vtab ** vtab,char **)75 int RuntimeTableFunctionModule::Create(sqlite3* db,
76 void* ctx,
77 int,
78 const char* const* argv,
79 sqlite3_vtab** vtab,
80 char**) {
81 auto* context = GetContext(ctx);
82 auto state = std::move(context->temporary_create_state);
83
84 auto create_table_str = CreateTableStrFromState(state.get());
85 if (int ret = sqlite3_declare_vtab(db, create_table_str.c_str());
86 ret != SQLITE_OK) {
87 return ret;
88 }
89 std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
90 res->reusable_stmt = std::move(state->temporary_create_stmt);
91 state->temporary_create_stmt = std::nullopt;
92 res->state = context->manager.OnCreate(argv, std::move(state));
93 *vtab = res.release();
94 return SQLITE_OK;
95 }
96
Destroy(sqlite3_vtab * vtab)97 int RuntimeTableFunctionModule::Destroy(sqlite3_vtab* vtab) {
98 std::unique_ptr<Vtab> tab(GetVtab(vtab));
99 sqlite::ModuleStateManager<RuntimeTableFunctionModule>::OnDestroy(tab->state);
100 return SQLITE_OK;
101 }
102
Connect(sqlite3 * db,void * ctx,int,const char * const *,sqlite3_vtab ** vtab,char ** argv)103 int RuntimeTableFunctionModule::Connect(sqlite3* db,
104 void* ctx,
105 int,
106 const char* const*,
107 sqlite3_vtab** vtab,
108 char** argv) {
109 auto* context = GetContext(ctx);
110
111 std::unique_ptr<Vtab> res = std::make_unique<Vtab>();
112 res->state = context->manager.OnConnect(argv);
113
114 auto create_table_str = CreateTableStrFromState(
115 sqlite::ModuleStateManager<RuntimeTableFunctionModule>::GetState(
116 res->state));
117 if (int ret = sqlite3_declare_vtab(db, create_table_str.c_str());
118 ret != SQLITE_OK) {
119 // If the registration happens to fail, make sure to disconnect the state
120 // again.
121 sqlite::ModuleStateManager<RuntimeTableFunctionModule>::OnDisconnect(
122 res->state);
123 return ret;
124 }
125 *vtab = res.release();
126 return SQLITE_OK;
127 }
128
Disconnect(sqlite3_vtab * vtab)129 int RuntimeTableFunctionModule::Disconnect(sqlite3_vtab* vtab) {
130 std::unique_ptr<Vtab> tab(GetVtab(vtab));
131 sqlite::ModuleStateManager<RuntimeTableFunctionModule>::OnDisconnect(
132 tab->state);
133 return SQLITE_OK;
134 }
135
BestIndex(sqlite3_vtab * tab,sqlite3_index_info * info)136 int RuntimeTableFunctionModule::BestIndex(sqlite3_vtab* tab,
137 sqlite3_index_info* info) {
138 auto* t = GetVtab(tab);
139 auto* s = sqlite::ModuleStateManager<RuntimeTableFunctionModule>::GetState(
140 t->state);
141
142 // Don't deal with any constraints on the output parameters for simplicty.
143 // TODO(lalitm): reconsider this decision to allow more efficient queries:
144 // we would need to wrap the query in a SELECT * FROM (...) WHERE constraint
145 // like we do for SPAN JOIN.
146 base::Status status = sqlite::utils::ValidateFunctionArguments(
147 info, s->prototype.arguments.size(),
148 [s](size_t c) { return s->IsArgumentColumn(c); });
149 if (!status.ok()) {
150 return SQLITE_CONSTRAINT;
151 }
152 return SQLITE_OK;
153 }
154
Open(sqlite3_vtab * tab,sqlite3_vtab_cursor ** cursor)155 int RuntimeTableFunctionModule::Open(sqlite3_vtab* tab,
156 sqlite3_vtab_cursor** cursor) {
157 auto* t = GetVtab(tab);
158 std::unique_ptr<Cursor> c = std::make_unique<Cursor>();
159 if (t->reusable_stmt) {
160 c->stmt = std::move(t->reusable_stmt);
161 t->reusable_stmt = std::nullopt;
162 }
163 *cursor = c.release();
164 return SQLITE_OK;
165 }
166
Close(sqlite3_vtab_cursor * cursor)167 int RuntimeTableFunctionModule::Close(sqlite3_vtab_cursor* cursor) {
168 std::unique_ptr<Cursor> c(GetCursor(cursor));
169 auto* t = GetVtab(c->pVtab);
170 if (!t->reusable_stmt && c->stmt) {
171 ResetStatement(c->stmt->sqlite_stmt());
172 t->reusable_stmt = std::move(c->stmt);
173 }
174 return SQLITE_OK;
175 }
176
Filter(sqlite3_vtab_cursor * cur,int,const char *,int argc,sqlite3_value ** argv)177 int RuntimeTableFunctionModule::Filter(sqlite3_vtab_cursor* cur,
178 int,
179 const char*,
180 int argc,
181 sqlite3_value** argv) {
182 auto* c = GetCursor(cur);
183 auto* t = GetVtab(cur->pVtab);
184 auto* s = sqlite::ModuleStateManager<RuntimeTableFunctionModule>::GetState(
185 t->state);
186
187 PERFETTO_CHECK(static_cast<size_t>(argc) == s->prototype.arguments.size());
188 PERFETTO_TP_TRACE(metatrace::Category::FUNCTION_CALL, "TABLE_FUNCTION_CALL",
189 [s](metatrace::Record* r) {
190 r->AddArg("Function", s->prototype.function_name.c_str());
191 });
192
193 // Prepare the SQL definition as a statement using SQLite.
194 // TODO(lalitm): measure and implement whether it would be a good idea to
195 // forward constraints here when we build the nested query.
196 if (c->stmt) {
197 // Filter can be called multiple times for the same cursor, so if we
198 // already have a statement, reset and reuse it. Otherwise, create a
199 // new one.
200 ResetStatement(c->stmt->sqlite_stmt());
201 } else {
202 auto stmt = s->engine->sqlite_engine()->PrepareStatement(s->sql_defn_str);
203 c->stmt = std::move(stmt);
204 if (const auto& status = c->stmt->status(); !status.ok()) {
205 return sqlite::utils::SetError(t, status.c_message());
206 }
207 }
208
209 // Bind all the arguments to the appropriate places in the function.
210 for (uint32_t i = 0; i < static_cast<uint32_t>(argc); ++i) {
211 const auto& arg = s->prototype.arguments[i];
212 base::Status status = MaybeBindArgument(
213 c->stmt->sqlite_stmt(), s->prototype.function_name, arg, argv[i]);
214 if (!status.ok()) {
215 return sqlite::utils::SetError(t, status.c_message());
216 }
217 }
218
219 // Reset the next call count - this is necessary because the same cursor
220 // can be used for multiple filter operations.
221 c->next_call_count = 0;
222 return Next(cur);
223 }
224
Next(sqlite3_vtab_cursor * cur)225 int RuntimeTableFunctionModule::Next(sqlite3_vtab_cursor* cur) {
226 auto* c = GetCursor(cur);
227 c->is_eof = !c->stmt->Step();
228 c->next_call_count++;
229 if (const auto& status = c->stmt->status(); !status.ok()) {
230 return sqlite::utils::SetError(cur->pVtab, status.c_message());
231 }
232 return SQLITE_OK;
233 }
234
Eof(sqlite3_vtab_cursor * cur)235 int RuntimeTableFunctionModule::Eof(sqlite3_vtab_cursor* cur) {
236 return GetCursor(cur)->is_eof;
237 }
238
Column(sqlite3_vtab_cursor * cur,sqlite3_context * ctx,int N)239 int RuntimeTableFunctionModule::Column(sqlite3_vtab_cursor* cur,
240 sqlite3_context* ctx,
241 int N) {
242 auto* c = GetCursor(cur);
243 auto* t = GetVtab(cur->pVtab);
244 auto* s = sqlite::ModuleStateManager<RuntimeTableFunctionModule>::GetState(
245 t->state);
246
247 auto idx = static_cast<size_t>(N);
248 if (PERFETTO_LIKELY(s->IsReturnValueColumn(idx))) {
249 sqlite::result::Value(ctx, sqlite3_column_value(c->stmt->sqlite_stmt(), N));
250 return SQLITE_OK;
251 }
252
253 if (PERFETTO_LIKELY(s->IsArgumentColumn(idx))) {
254 // TODO(lalitm): it may be more appropriate to keep a note of the arguments
255 // which we passed in and return them here. Not doing this to because it
256 // doesn't seem necessary for any useful thing but something which may need
257 // to be changed in the future.
258 sqlite::result::Null(ctx);
259 return SQLITE_OK;
260 }
261
262 PERFETTO_DCHECK(s->IsPrimaryKeyColumn(idx));
263 sqlite::result::Long(ctx, c->next_call_count);
264 return SQLITE_OK;
265 }
266
Rowid(sqlite3_vtab_cursor *,sqlite_int64 *)267 int RuntimeTableFunctionModule::Rowid(sqlite3_vtab_cursor*, sqlite_int64*) {
268 return SQLITE_ERROR;
269 }
270
271 } // namespace perfetto::trace_processor
272