diff options
Diffstat (limited to 'src/trace_processor/prelude/functions/register_function.h')
-rw-r--r-- | src/trace_processor/prelude/functions/register_function.h | 233 |
1 files changed, 0 insertions, 233 deletions
diff --git a/src/trace_processor/prelude/functions/register_function.h b/src/trace_processor/prelude/functions/register_function.h deleted file mode 100644 index acca3e62a..000000000 --- a/src/trace_processor/prelude/functions/register_function.h +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_REGISTER_FUNCTION_H_ -#define SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_REGISTER_FUNCTION_H_ - -#include <sqlite3.h> -#include <memory> - -#include "src/trace_processor/sqlite/sqlite_utils.h" - -namespace perfetto { -namespace trace_processor { - -// Prototype for a C++ function which can be registered with SQLite. -// -// Usage -// -// Define a subclass of this struct as follows: -// struct YourFunction : public SqlFunction { -// // Optional if you want a custom context object (i.e. an object -// // passed in at registration time which will be passed to Run on -// // every invocation) -// struct YourContext { /* define context fields here */ }; -// -// static base::Status Run(/* see parameters below */) { -// /* function body here */ -// } -// -// static base::Status Cleanup(/* see parameters below */) { -// /* function body here */ -// } -// } -// -// Then, register this function with SQLite using RegisterFunction (see below); -// you'll likely want to do this in TraceProcessorImpl: -// RegisterFunction<YourFunction>(/* see arguments below */) -struct SqlFunction { - // The type of the context object which will be passed to the function. - // Can be redefined in any sub-classes to override the context. - using Context = void; - - // Indicates whether this function is "void" (i.e. doesn't actually want - // to return a value). While the function will still return null in SQL - // (because SQLite does not actually allow null functions), for accounting - // purposes, this null will be ignored when verifying whether this statement - // has any output. - // Can be redefined in any sub-classes to override it. - // If this is set to true, subclasses must not modify |out| or |destructors|. - static constexpr bool kVoidReturn = false; - - // Struct which holds destructors for strings/bytes returned from the - // function. Passed as an argument to |Run| to allow implementations to - // override the destructors. - struct Destructors { - sqlite3_destructor_type string_destructor = sqlite_utils::kSqliteTransient; - sqlite3_destructor_type bytes_destructor = sqlite_utils::kSqliteTransient; - }; - - // The function which will be exectued with the arguments from SQL. - // - // Implementations MUST define this function themselves; this function is - // declared but *not* defined so linker errors will be thrown if not defined. - // - // |ctx|: the context object passed at registration time. - // |argc|: number of arguments. - // |argv|: arguments to the function. - // |out|: the return value of the function. - // |destructors|: destructors for string/bytes return values. - static base::Status Run(Context* ctx, - size_t argc, - sqlite3_value** argv, - SqlValue& out, - Destructors& destructors); - - // Executed after the result from |Run| is reported to SQLite. - // Allows implementations to verify post-conditions without needing to worry - // about overwriting return types. - // - // Implementations do not need to define this function; a default no-op - // implementation will be used in this case. - static base::Status VerifyPostConditions(Context*); - - // Executed after the result from |Run| is reported to SQLite. - // Allows any pending state to be cleaned up post-copy of results by SQLite: - // this function will be called even if |Run| or |PostRun| returned errors. - // - // Implementations do not need to define this function; a default no-op - // implementation will be used in this case. - static void Cleanup(Context*); -}; - -// Registers a C++ function to be runnable from SQL. -// The format of the function is given by the |SqlFunction|; see the -// documentaion above. -// -// |db|: sqlite3 database object -// |name|: name of the function in SQL -// |argc|: number of arguments for this function, -1 if variable -// |ctx|: context object for the function (see SqlFunction::Run above); -// this object *must* outlive the function so should likely be -// either static or scoped to the lifetime of TraceProcessor. -// |determistic|: whether this function has deterministic output given the -// same set of arguments. -template <typename Function> -base::Status RegisterSqlFunction(sqlite3* db, - const char* name, - int argc, - typename Function::Context* ctx, - bool deterministic = true); - -// Same as above except allows a unique_ptr to be passed for the context; this -// allows for SQLite to manage the lifetime of this pointer instead of the -// essentially static requirement of the context pointer above. -template <typename Function> -base::Status RegisterSqlFunction( - sqlite3* db, - const char* name, - int argc, - std::unique_ptr<typename Function::Context> ctx, - bool deterministic = true); - -} // namespace trace_processor -} // namespace perfetto - -// The rest of this file is just implementation details which we need -// in the header file because it is templated code. We separate it out -// like this to keep the API people actually care about easy to read. - -namespace perfetto { -namespace trace_processor { - -namespace sqlite_internal { - -// RAII type to call Function::Cleanup when destroyed. -template <typename Function> -struct ScopedCleanup { - typename Function::Context* ctx; - ~ScopedCleanup() { Function::Cleanup(ctx); } -}; - -template <typename Function> -void WrapSqlFunction(sqlite3_context* ctx, int argc, sqlite3_value** argv) { - using Context = typename Function::Context; - Context* ud = static_cast<Context*>(sqlite3_user_data(ctx)); - - ScopedCleanup<Function> scoped_cleanup{ud}; - SqlValue value{}; - SqlFunction::Destructors destructors{}; - base::Status status = - Function::Run(ud, static_cast<size_t>(argc), argv, value, destructors); - if (!status.ok()) { - sqlite3_result_error(ctx, status.c_message(), -1); - return; - } - - if (Function::kVoidReturn) { - if (!value.is_null()) { - sqlite3_result_error(ctx, "void SQL function returned value", -1); - return; - } - - // If the function doesn't want to return anything, set the "VOID" - // pointer type to a non-null value. Note that because of the weird - // way |sqlite3_value_pointer| works, we need to set some value even - // if we don't actually read it - just set it to a pointer to an empty - // string for this reason. - static char kVoidValue[] = ""; - sqlite3_result_pointer(ctx, kVoidValue, "VOID", nullptr); - } else { - sqlite_utils::ReportSqlValue(ctx, value, destructors.string_destructor, - destructors.bytes_destructor); - } - - status = Function::VerifyPostConditions(ud); - if (!status.ok()) { - sqlite3_result_error(ctx, status.c_message(), -1); - return; - } -} -} // namespace sqlite_internal - -template <typename Function> -base::Status RegisterSqlFunction(sqlite3* db, - const char* name, - int argc, - typename Function::Context* ctx, - bool deterministic) { - int flags = SQLITE_UTF8 | (deterministic ? SQLITE_DETERMINISTIC : 0); - int ret = sqlite3_create_function_v2( - db, name, static_cast<int>(argc), flags, ctx, - sqlite_internal::WrapSqlFunction<Function>, nullptr, nullptr, nullptr); - if (ret != SQLITE_OK) { - return base::ErrStatus("Unable to register function with name %s", name); - } - return base::OkStatus(); -} - -template <typename Function> -base::Status RegisterSqlFunction( - sqlite3* db, - const char* name, - int argc, - std::unique_ptr<typename Function::Context> user_data, - bool deterministic) { - int flags = SQLITE_UTF8 | (deterministic ? SQLITE_DETERMINISTIC : 0); - int ret = sqlite3_create_function_v2( - db, name, static_cast<int>(argc), flags, user_data.release(), - sqlite_internal::WrapSqlFunction<Function>, nullptr, nullptr, - [](void* ptr) { delete static_cast<typename Function::Context*>(ptr); }); - if (ret != SQLITE_OK) { - return base::ErrStatus("Unable to register function with name %s", name); - } - return base::OkStatus(); -} - -} // namespace trace_processor -} // namespace perfetto - -#endif // SRC_TRACE_PROCESSOR_PRELUDE_FUNCTIONS_REGISTER_FUNCTION_H_ |