lnav/src/vtab_module.hh

942 lines
26 KiB
C++
Raw Normal View History

/**
* Copyright (c) 2017, Timothy Stack
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* * Neither the name of Timothy Stack nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
2022-03-16 22:38:08 +00:00
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef vtab_module_hh
#define vtab_module_hh
#include <string>
#include <utility>
2022-03-16 22:38:08 +00:00
#include <vector>
2022-03-16 22:38:08 +00:00
#include <sqlite3.h>
2022-04-12 23:07:13 +00:00
#include "base/auto_mem.hh"
2022-03-13 22:49:41 +00:00
#include "base/intern_string.hh"
2022-03-16 22:38:08 +00:00
#include "base/lnav_log.hh"
#include "base/string_util.hh"
2020-04-25 14:32:05 +00:00
#include "fmt/format.h"
2022-03-16 22:38:08 +00:00
#include "mapbox/variant.hpp"
#include "optional.hpp"
#include "sqlite-extension-func.hh"
struct from_sqlite_conversion_error : std::exception {
2022-03-16 22:38:08 +00:00
from_sqlite_conversion_error(const char* type, int argi)
: e_type(type), e_argi(argi){
2022-03-16 22:38:08 +00:00
};
2022-03-16 22:38:08 +00:00
const char* e_type;
int e_argi;
};
struct sqlite_func_error : std::exception {
2022-03-16 22:38:08 +00:00
template<typename... Args>
explicit sqlite_func_error(fmt::string_view format_str, const Args&... args)
: e_what(fmt::vformat(format_str, fmt::make_format_args(args...)))
{
2020-04-25 14:32:05 +00:00
}
2022-03-16 22:38:08 +00:00
const char* what() const noexcept override
{
return this->e_what.c_str();
}
2020-04-25 14:32:05 +00:00
const std::string e_what;
};
namespace vtab_types {
template<typename T>
struct nullable {
2022-03-16 22:38:08 +00:00
T* n_value{nullptr};
};
template<typename>
2022-03-16 22:38:08 +00:00
struct is_nullable : std::false_type {
};
template<typename T>
2022-03-16 22:38:08 +00:00
struct is_nullable<nullable<T>> : std::true_type {
};
2022-03-16 22:38:08 +00:00
} // namespace vtab_types
template<typename T>
struct from_sqlite {
2021-02-05 07:10:44 +00:00
using U = typename std::remove_reference<T>::type;
2022-03-16 22:38:08 +00:00
inline U operator()(int argc, sqlite3_value** val, int argi)
{
2021-02-05 07:10:44 +00:00
return U();
};
};
template<>
struct from_sqlite<bool> {
2022-03-16 22:38:08 +00:00
inline bool operator()(int argc, sqlite3_value** val, int argi)
{
if (sqlite3_value_numeric_type(val[argi]) != SQLITE_INTEGER) {
throw from_sqlite_conversion_error("integer", argi);
}
return sqlite3_value_int64(val[argi]);
}
};
template<>
struct from_sqlite<int64_t> {
2022-03-16 22:38:08 +00:00
inline int64_t operator()(int argc, sqlite3_value** val, int argi)
{
if (sqlite3_value_numeric_type(val[argi]) != SQLITE_INTEGER) {
throw from_sqlite_conversion_error("integer", argi);
}
return sqlite3_value_int64(val[argi]);
}
};
template<>
2022-03-16 22:38:08 +00:00
struct from_sqlite<sqlite3_value*> {
inline sqlite3_value* operator()(int argc, sqlite3_value** val, int argi)
{
return val[argi];
}
};
template<>
struct from_sqlite<int> {
2022-03-16 22:38:08 +00:00
inline int operator()(int argc, sqlite3_value** val, int argi)
{
if (sqlite3_value_numeric_type(val[argi]) != SQLITE_INTEGER) {
throw from_sqlite_conversion_error("integer", argi);
}
return sqlite3_value_int(val[argi]);
}
};
template<>
2022-03-16 22:38:08 +00:00
struct from_sqlite<const char*> {
inline const char* operator()(int argc, sqlite3_value** val, int argi)
{
return (const char*) sqlite3_value_text(val[argi]);
}
};
2021-10-03 06:17:33 +00:00
template<>
struct from_sqlite<string_fragment> {
2022-03-16 22:38:08 +00:00
inline string_fragment operator()(int argc, sqlite3_value** val, int argi)
{
return string_fragment{
(const unsigned char*) sqlite3_value_blob(val[argi]),
2021-10-03 06:17:33 +00:00
0,
sqlite3_value_bytes(val[argi]),
};
}
};
template<>
2020-04-25 14:32:05 +00:00
struct from_sqlite<std::string> {
2022-03-16 22:38:08 +00:00
inline std::string operator()(int argc, sqlite3_value** val, int argi)
{
2021-10-26 16:39:05 +00:00
return {
2022-03-16 22:38:08 +00:00
(const char*) sqlite3_value_blob(val[argi]),
2021-10-26 16:39:05 +00:00
(size_t) sqlite3_value_bytes(val[argi]),
};
}
};
template<>
struct from_sqlite<double> {
2022-03-16 22:38:08 +00:00
inline double operator()(int argc, sqlite3_value** val, int argi)
{
return sqlite3_value_double(val[argi]);
}
};
template<typename T>
struct from_sqlite<nonstd::optional<T>> {
2022-03-16 22:38:08 +00:00
inline nonstd::optional<T> operator()(int argc,
sqlite3_value** val,
int argi)
{
if (argi >= argc || sqlite3_value_type(val[argi]) == SQLITE_NULL) {
return nonstd::nullopt;
}
return nonstd::optional<T>(from_sqlite<T>()(argc, val, argi));
}
};
template<typename T>
2022-03-16 22:38:08 +00:00
struct from_sqlite<const std::vector<T>&> {
inline std::vector<T> operator()(int argc, sqlite3_value** val, int argi)
{
std::vector<T> retval;
for (int lpc = argi; lpc < argc; lpc++) {
retval.emplace_back(from_sqlite<T>()(argc, val, lpc));
}
return retval;
}
};
template<typename T>
struct from_sqlite<vtab_types::nullable<T>> {
2022-03-16 22:38:08 +00:00
inline vtab_types::nullable<T> operator()(int argc,
sqlite3_value** val,
int argi)
{
return {from_sqlite<T*>()(argc, val, argi)};
}
};
2022-03-16 22:38:08 +00:00
inline void
to_sqlite(sqlite3_context* ctx, const char* str)
{
if (str == nullptr) {
sqlite3_result_null(ctx);
} else {
sqlite3_result_text(ctx, str, -1, SQLITE_STATIC);
}
}
2022-03-16 22:38:08 +00:00
inline void
to_sqlite(sqlite3_context* ctx, text_auto_buffer& buf)
{
2021-10-26 16:39:05 +00:00
auto pair = buf.inner.release();
2021-03-06 00:17:28 +00:00
sqlite3_result_text(ctx, pair.first, pair.second, free);
}
2022-03-16 22:38:08 +00:00
inline void
to_sqlite(sqlite3_context* ctx, blob_auto_buffer& buf)
2021-10-26 16:39:05 +00:00
{
auto pair = buf.inner.release();
sqlite3_result_blob(ctx, pair.first, pair.second, free);
}
2022-03-16 22:38:08 +00:00
inline void
to_sqlite(sqlite3_context* ctx, const std::string& str)
{
sqlite3_result_text(ctx, str.c_str(), str.length(), SQLITE_TRANSIENT);
}
2022-03-16 22:38:08 +00:00
inline void
to_sqlite(sqlite3_context* ctx, const string_fragment& sf)
{
if (sf.is_valid()) {
2022-03-16 22:38:08 +00:00
sqlite3_result_text(
ctx, &sf.sf_string[sf.sf_begin], sf.length(), SQLITE_TRANSIENT);
} else {
sqlite3_result_null(ctx);
}
}
2022-03-16 22:38:08 +00:00
inline void
to_sqlite(sqlite3_context* ctx, bool val)
{
sqlite3_result_int(ctx, val);
}
template<typename T>
2022-03-16 22:38:08 +00:00
inline void
to_sqlite(sqlite3_context* ctx,
T val,
typename std::enable_if<std::is_integral<T>::value
&& !std::is_same<T, bool>::value>::type* dummy
= 0)
{
sqlite3_result_int64(ctx, val);
}
2022-03-16 22:38:08 +00:00
inline void
to_sqlite(sqlite3_context* ctx, double val)
{
sqlite3_result_double(ctx, val);
}
2022-03-16 22:38:08 +00:00
#define JSON_SUBTYPE 74 /* Ascii for "J" */
template<typename T>
2022-03-16 22:38:08 +00:00
inline void
to_sqlite(sqlite3_context* ctx, nonstd::optional<T>& val)
{
if (val.has_value()) {
to_sqlite(ctx, val.value());
} else {
sqlite3_result_null(ctx);
}
}
template<typename T>
2022-03-16 22:38:08 +00:00
inline void
to_sqlite(sqlite3_context* ctx, const nonstd::optional<T>& val)
{
if (val.has_value()) {
to_sqlite(ctx, val.value());
} else {
sqlite3_result_null(ctx);
}
}
struct ToSqliteVisitor {
2022-03-16 22:38:08 +00:00
ToSqliteVisitor(sqlite3_context* vctx)
: tsv_context(vctx){
2022-03-16 22:38:08 +00:00
};
template<typename T>
2022-03-16 22:38:08 +00:00
void operator()(T&& t) const
{
to_sqlite(this->tsv_context, t);
}
2022-03-16 22:38:08 +00:00
sqlite3_context* tsv_context;
};
2022-03-16 22:38:08 +00:00
template<typename... Types>
void
to_sqlite(sqlite3_context* ctx, mapbox::util::variant<Types...>& val)
{
ToSqliteVisitor visitor(ctx);
mapbox::util::apply_visitor(visitor, val);
}
2022-03-16 22:38:08 +00:00
template<typename... Args>
struct optional_counter {
constexpr static int value = 0;
};
template<typename T>
struct optional_counter<nonstd::optional<T>> {
constexpr static int value = 1;
};
2020-09-12 06:10:11 +00:00
template<typename T, typename U>
2022-03-16 22:38:08 +00:00
struct optional_counter<nonstd::optional<T>, const std::vector<U>&> {
2020-09-12 06:10:11 +00:00
constexpr static int value = 1;
};
2022-03-16 22:38:08 +00:00
template<typename T, typename... Rest>
struct optional_counter<nonstd::optional<T>, Rest...> {
constexpr static int value = 1 + sizeof...(Rest);
};
template<typename Arg>
struct optional_counter<Arg> {
constexpr static int value = 0;
};
2022-03-16 22:38:08 +00:00
template<typename Arg1, typename... Args>
struct optional_counter<Arg1, Args...> : optional_counter<Args...> {
};
2022-03-16 22:38:08 +00:00
template<typename... Args>
struct variadic_counter {
constexpr static int value = 0;
};
template<typename T>
2022-03-16 22:38:08 +00:00
struct variadic_counter<const std::vector<T>&> {
constexpr static int value = 1;
};
template<typename Arg>
struct variadic_counter<Arg> {
constexpr static int value = 0;
};
2022-03-16 22:38:08 +00:00
template<typename Arg1, typename... Args>
struct variadic_counter<Arg1, Args...> : variadic_counter<Args...> {
};
2022-03-16 22:38:08 +00:00
template<typename F, F f>
struct sqlite_func_adapter;
2022-03-16 22:38:08 +00:00
template<typename Return, typename... Args, Return (*f)(Args...)>
struct sqlite_func_adapter<Return (*)(Args...), f> {
2020-09-12 06:10:11 +00:00
constexpr static size_t OPT_COUNT = optional_counter<Args...>::value;
constexpr static size_t VAR_COUNT = variadic_counter<Args...>::value;
constexpr static size_t REQ_COUNT = sizeof...(Args) - OPT_COUNT - VAR_COUNT;
2022-03-16 22:38:08 +00:00
template<size_t... Idx>
static void func2(sqlite3_context* context,
int argc,
sqlite3_value** argv,
std::index_sequence<Idx...>)
{
try {
Return retval = f(from_sqlite<Args>()(argc, argv, Idx)...);
to_sqlite(context, retval);
2022-03-16 22:38:08 +00:00
} catch (from_sqlite_conversion_error& e) {
char buffer[64];
2022-03-16 22:38:08 +00:00
snprintf(buffer,
sizeof(buffer),
"Expecting an %s for argument number %d",
e.e_type,
e.e_argi);
sqlite3_result_error(context, buffer, -1);
2022-03-16 22:38:08 +00:00
} catch (const std::exception& e) {
sqlite3_result_error(context, e.what(), -1);
} catch (...) {
2022-03-16 22:38:08 +00:00
sqlite3_result_error(
context, "Function threw an unexpected exception", -1);
}
};
2022-03-16 22:38:08 +00:00
static void func1(sqlite3_context* context, int argc, sqlite3_value** argv)
{
const static bool IS_NULLABLE[]
= {vtab_types::is_nullable<Args>::value...};
const static bool IS_SQLITE3_VALUE[]
= {std::is_same<Args, sqlite3_value*>::value...};
2021-09-28 05:02:32 +00:00
2020-09-12 06:10:11 +00:00
if ((size_t) argc < REQ_COUNT && VAR_COUNT == 0) {
2022-03-16 22:38:08 +00:00
const struct FuncDef* fd
= (const FuncDef*) sqlite3_user_data(context);
char buffer[128];
if (OPT_COUNT == 0) {
2022-03-16 22:38:08 +00:00
snprintf(buffer,
sizeof(buffer),
2020-09-12 06:10:11 +00:00
"%s() expects exactly %ld argument%s",
fd->fd_help.ht_name,
REQ_COUNT,
REQ_COUNT == 1 ? "s" : "");
} else {
2022-03-16 22:38:08 +00:00
snprintf(buffer,
sizeof(buffer),
2020-09-12 06:10:11 +00:00
"%s() expects between %ld and %ld arguments",
fd->fd_help.ht_name,
REQ_COUNT,
REQ_COUNT + OPT_COUNT);
}
sqlite3_result_error(context, buffer, -1);
return;
}
2020-09-12 06:10:11 +00:00
for (size_t lpc = 0; lpc < REQ_COUNT; lpc++) {
2022-03-16 22:38:08 +00:00
if (!IS_NULLABLE[lpc] && !IS_SQLITE3_VALUE[lpc]
&& sqlite3_value_type(argv[lpc]) == SQLITE_NULL)
{
sqlite3_result_null(context);
return;
}
}
func2(context, argc, argv, std::make_index_sequence<sizeof...(Args)>{});
};
2022-03-16 22:38:08 +00:00
static FuncDef builder(help_text ht)
{
require(ht.ht_parameters.size() == sizeof...(Args));
return {
ht.ht_name,
2020-09-12 06:10:11 +00:00
(OPT_COUNT > 0 || VAR_COUNT > 0) ? -1 : (int) REQ_COUNT,
SQLITE_UTF8 | SQLITE_DETERMINISTIC,
0,
func1,
ht,
};
};
};
extern std::string vtab_module_schemas;
extern std::map<intern_string_t, std::string> vtab_module_ddls;
class vtab_index_constraints {
public:
2022-03-16 22:38:08 +00:00
vtab_index_constraints(const sqlite3_index_info* index_info)
: vic_index_info(*index_info){};
struct const_iterator {
2022-03-16 22:38:08 +00:00
const_iterator(vtab_index_constraints* parent, int index = 0)
: i_parent(parent), i_index(index)
{
while (this->i_index < this->i_parent->vic_index_info.nConstraint
&& !this->i_parent->vic_index_info.aConstraint[this->i_index]
.usable)
{
this->i_index += 1;
}
};
2022-03-16 22:38:08 +00:00
const_iterator& operator++()
{
do {
this->i_index += 1;
} while (
2022-03-16 22:38:08 +00:00
this->i_index < this->i_parent->vic_index_info.nConstraint
&& !this->i_parent->vic_index_info.aConstraint[this->i_index]
.usable);
return *this;
};
2022-03-16 22:38:08 +00:00
const sqlite3_index_info::sqlite3_index_constraint& operator*() const
{
return this->i_parent->vic_index_info.aConstraint[this->i_index];
};
2022-03-16 22:38:08 +00:00
const sqlite3_index_info::sqlite3_index_constraint* operator->() const
{
return &this->i_parent->vic_index_info.aConstraint[this->i_index];
};
2022-03-16 22:38:08 +00:00
bool operator!=(const const_iterator& rhs) const
{
return this->i_parent != rhs.i_parent
|| this->i_index != rhs.i_index;
};
2022-03-16 22:38:08 +00:00
const vtab_index_constraints* i_parent;
int i_index;
};
2022-03-16 22:38:08 +00:00
const_iterator begin()
{
return {this};
};
2022-03-16 22:38:08 +00:00
const_iterator end()
{
return {this, this->vic_index_info.nConstraint};
};
private:
2022-03-16 22:38:08 +00:00
const sqlite3_index_info& vic_index_info;
};
class vtab_index_usage {
public:
2022-03-16 22:38:08 +00:00
vtab_index_usage(sqlite3_index_info* index_info)
: viu_index_info(*index_info), viu_used_column_count(0),
viu_max_column(0){
2022-03-16 22:38:08 +00:00
};
2022-03-16 22:38:08 +00:00
void column_used(const vtab_index_constraints::const_iterator& iter)
{
this->viu_max_column = std::max(iter->iColumn, this->viu_max_column);
this->viu_index_info.idxNum |= (1L << iter.i_index);
this->viu_used_column_count += 1;
};
2022-03-16 22:38:08 +00:00
void allocate_args(int expected)
{
int n_arg = 0;
if (this->viu_used_column_count != expected) {
this->viu_index_info.estimatedCost = 2147483647;
this->viu_index_info.estimatedRows = 2147483647;
return;
}
for (int lpc = 0; lpc <= this->viu_max_column; lpc++) {
for (int cons_index = 0;
cons_index < this->viu_index_info.nConstraint;
2022-03-16 22:38:08 +00:00
cons_index++)
{
if (this->viu_index_info.aConstraint[cons_index].iColumn != lpc)
{
continue;
}
if (!(this->viu_index_info.idxNum & (1L << cons_index))) {
continue;
}
2022-03-16 22:38:08 +00:00
this->viu_index_info.aConstraintUsage[cons_index].argvIndex
= ++n_arg;
}
}
this->viu_index_info.estimatedCost = 1.0;
this->viu_index_info.estimatedRows = 1;
};
private:
2022-03-16 22:38:08 +00:00
sqlite3_index_info& viu_index_info;
int viu_used_column_count;
int viu_max_column;
};
struct vtab_module_base {
2022-03-16 22:38:08 +00:00
virtual int create(sqlite3* db) = 0;
virtual ~vtab_module_base() = default;
};
template<typename T>
struct vtab_module : public vtab_module_base {
struct vtab {
2022-03-16 22:38:08 +00:00
explicit vtab(T& impl) : v_impl(impl){};
2022-03-16 22:38:08 +00:00
explicit operator sqlite3_vtab*()
{
return &this->base;
};
sqlite3_vtab v_base{};
2022-03-16 22:38:08 +00:00
T& v_impl;
};
2022-03-16 22:38:08 +00:00
static int tvt_create(sqlite3* db,
void* pAux,
int argc,
const char* const* argv,
sqlite3_vtab** pp_vt,
char** pzErr)
{
auto* mod = static_cast<vtab_module<T>*>(pAux);
auto vt = new vtab(mod->vm_impl);
2022-03-16 22:38:08 +00:00
*pp_vt = (sqlite3_vtab*) &vt->v_base;
return sqlite3_declare_vtab(db, T::CREATE_STMT);
};
2022-03-16 22:38:08 +00:00
template<typename... Args, size_t... Idx>
static int apply_impl(T& obj,
int (T::*func)(sqlite3_vtab*,
sqlite3_int64&,
Args...),
sqlite3_vtab* tab,
sqlite3_int64& rowid,
sqlite3_value** argv,
std::index_sequence<Idx...>)
{
2022-03-16 22:38:08 +00:00
return (obj.*func)(
tab, rowid, from_sqlite<Args>()(sizeof...(Args), argv, Idx)...);
}
2022-03-16 22:38:08 +00:00
template<typename... Args>
static int apply(T& obj,
int (T::*func)(sqlite3_vtab*, sqlite3_int64&, Args...),
sqlite3_vtab* tab,
sqlite3_int64& rowid,
int argc,
2022-03-16 22:38:08 +00:00
sqlite3_value** argv)
{
require(sizeof...(Args) == 0 || argc == sizeof...(Args));
try {
return apply_impl(obj,
func,
tab,
rowid,
argv,
std::make_index_sequence<sizeof...(Args)>{});
2022-03-25 23:38:11 +00:00
} catch (const from_sqlite_conversion_error& e) {
tab->zErrMsg = sqlite3_mprintf(
2022-03-16 22:38:08 +00:00
"Expecting an %s for column number %d", e.e_type, e.e_argi);
return SQLITE_ERROR;
2022-03-16 22:38:08 +00:00
} catch (const std::exception& e) {
tab->zErrMsg = sqlite3_mprintf("%s", e.what());
return SQLITE_ERROR;
} catch (...) {
2022-03-16 22:38:08 +00:00
tab->zErrMsg
= sqlite3_mprintf("Encountered an unexpected exception");
return SQLITE_ERROR;
}
}
2022-03-16 22:38:08 +00:00
static int tvt_destructor(sqlite3_vtab* p_svt)
{
2022-03-16 22:38:08 +00:00
vtab* vt = (vtab*) p_svt;
delete vt;
return SQLITE_OK;
}
2022-03-16 22:38:08 +00:00
static int tvt_open(sqlite3_vtab* p_svt, sqlite3_vtab_cursor** pp_cursor)
{
p_svt->zErrMsg = nullptr;
2022-03-16 22:38:08 +00:00
auto* p_cur = new (typename T::cursor)(p_svt);
if (p_cur == nullptr) {
return SQLITE_NOMEM;
} else {
2022-03-16 22:38:08 +00:00
*pp_cursor = (sqlite3_vtab_cursor*) p_cur;
}
return SQLITE_OK;
}
2022-03-16 22:38:08 +00:00
static int tvt_next(sqlite3_vtab_cursor* cur)
{
2022-03-16 22:38:08 +00:00
auto* p_cur = (typename T::cursor*) cur;
return p_cur->next();
}
2022-03-16 22:38:08 +00:00
static int tvt_eof(sqlite3_vtab_cursor* cur)
{
2022-03-16 22:38:08 +00:00
auto* p_cur = (typename T::cursor*) cur;
return p_cur->eof();
}
2022-03-16 22:38:08 +00:00
static int tvt_close(sqlite3_vtab_cursor* cur)
{
2022-03-16 22:38:08 +00:00
auto* p_cur = (typename T::cursor*) cur;
delete p_cur;
return SQLITE_OK;
}
2022-03-16 22:38:08 +00:00
static int tvt_rowid(sqlite3_vtab_cursor* cur, sqlite_int64* p_rowid)
{
auto* p_cur = (typename T::cursor*) cur;
return p_cur->get_rowid(*p_rowid);
};
2022-03-16 22:38:08 +00:00
static int tvt_column(sqlite3_vtab_cursor* cur,
sqlite3_context* ctx,
int col)
{
auto* mod_vt = (typename vtab_module<T>::vtab*) cur->pVtab;
auto* p_cur = (typename T::cursor*) cur;
return mod_vt->v_impl.get_column(*p_cur, ctx, col);
};
2022-03-16 22:38:08 +00:00
static int vt_best_index(sqlite3_vtab* tab, sqlite3_index_info* p_info)
{
return SQLITE_OK;
};
2022-03-16 22:38:08 +00:00
static int vt_filter(sqlite3_vtab_cursor* p_vtc,
int idxNum,
const char* idxStr,
int argc,
sqlite3_value** argv)
{
auto* p_cur = (typename T::cursor*) p_vtc;
2019-02-18 22:44:59 +00:00
return p_cur->reset();
}
2022-03-16 22:38:08 +00:00
static int tvt_update(sqlite3_vtab* tab,
int argc,
2022-03-16 22:38:08 +00:00
sqlite3_value** argv,
sqlite_int64* rowid)
{
auto* mod_vt = (typename vtab_module<T>::vtab*) tab;
if (argc <= 1) {
2017-03-14 13:28:42 +00:00
sqlite3_int64 rowid = sqlite3_value_int64(argv[0]);
return mod_vt->v_impl.delete_row(tab, rowid);
}
if (sqlite3_value_type(argv[0]) == SQLITE_NULL) {
2022-03-16 22:38:08 +00:00
sqlite3_int64* rowid2 = rowid;
return vtab_module<T>::apply(mod_vt->v_impl,
&T::insert_row,
tab,
*rowid2,
argc - 2,
argv + 2);
}
2017-03-14 13:28:42 +00:00
sqlite3_int64 index = sqlite3_value_int64(argv[0]);
if (index != sqlite3_value_int64(argv[1])) {
tab->zErrMsg = sqlite3_mprintf(
"The rowids in the lnav_views table cannot be changed");
return SQLITE_ERROR;
}
2022-03-16 22:38:08 +00:00
return vtab_module<T>::apply(
mod_vt->v_impl, &T::update_row, tab, index, argc - 2, argv + 2);
};
template<typename U>
2022-03-16 22:38:08 +00:00
auto addUpdate(U u) -> decltype(&U::delete_row, void())
{
this->vm_module.xUpdate = tvt_update;
};
template<typename U>
2022-03-16 22:38:08 +00:00
void addUpdate(...){};
2022-03-16 22:38:08 +00:00
template<typename... Args>
vtab_module(Args&... args) noexcept : vm_impl(args...)
{
memset(&this->vm_module, 0, sizeof(this->vm_module));
this->vm_module.iVersion = 0;
this->vm_module.xCreate = tvt_create;
this->vm_module.xConnect = tvt_create;
this->vm_module.xOpen = tvt_open;
this->vm_module.xNext = tvt_next;
this->vm_module.xEof = tvt_eof;
this->vm_module.xClose = tvt_close;
this->vm_module.xDestroy = tvt_destructor;
this->vm_module.xRowid = tvt_rowid;
this->vm_module.xDisconnect = tvt_destructor;
this->vm_module.xBestIndex = vt_best_index;
this->vm_module.xFilter = vt_filter;
this->vm_module.xColumn = tvt_column;
this->addUpdate<T>(this->vm_impl);
};
~vtab_module() override = default;
2022-03-16 22:38:08 +00:00
int create(sqlite3* db, const char* name)
{
auto impl_name = std::string(name);
vtab_module_schemas += T::CREATE_STMT;
vtab_module_ddls[intern_string::lookup(name)] = trim(T::CREATE_STMT);
// XXX Eponymous tables don't seem to work in older sqlite versions
impl_name += "_impl";
int rc = sqlite3_create_module(
db, impl_name.c_str(), &this->vm_module, this);
ensure(rc == SQLITE_OK);
2022-03-16 22:38:08 +00:00
auto create_stmt = fmt::format(
2022-03-29 05:00:49 +00:00
FMT_STRING("CREATE VIRTUAL TABLE {} USING {}()"), name, impl_name);
return sqlite3_exec(db, create_stmt.c_str(), nullptr, nullptr, nullptr);
};
2022-03-16 22:38:08 +00:00
int create(sqlite3* db) override
{
return this->create(db, T::NAME);
}
sqlite3_module vm_module;
T vm_impl;
};
template<typename T>
struct tvt_iterator_cursor {
struct cursor {
sqlite3_vtab_cursor base{};
typename T::iterator iter;
2022-03-16 22:38:08 +00:00
explicit cursor(sqlite3_vtab* vt)
{
2022-03-16 22:38:08 +00:00
auto* mod_vt = (typename vtab_module<T>::vtab*) vt;
this->base.pVtab = vt;
this->iter = mod_vt->v_impl.begin();
};
2022-03-16 22:38:08 +00:00
int reset()
{
this->iter = get_handler().begin();
2019-02-18 22:44:59 +00:00
return SQLITE_OK;
};
int next()
{
if (this->iter != get_handler().end()) {
++this->iter;
}
return SQLITE_OK;
};
int eof()
{
return this->iter == get_handler().end();
};
2022-03-16 22:38:08 +00:00
template<bool cond, typename U>
using resolvedType = typename std::enable_if<cond, U>::type;
2022-03-16 22:38:08 +00:00
template<typename U = int>
resolvedType<
std::is_same<std::random_access_iterator_tag,
typename std::iterator_traits<
typename T::iterator>::iterator_category>::value,
U>
get_rowid(sqlite_int64& rowid_out)
{
rowid_out = std::distance(get_handler().begin(), this->iter);
return SQLITE_OK;
}
2022-03-16 22:38:08 +00:00
template<typename U = int>
resolvedType<
!std::is_same<std::random_access_iterator_tag,
typename std::iterator_traits<
typename T::iterator>::iterator_category>::value,
U>
get_rowid(sqlite_int64& rowid_out)
{
rowid_out = get_handler().get_rowid(this->iter);
return SQLITE_OK;
}
private:
2022-03-16 22:38:08 +00:00
T& get_handler()
{
auto* mod_vt = (typename vtab_module<T>::vtab*) this->base.pVtab;
return mod_vt->v_impl;
}
};
};
template<typename T>
struct tvt_no_update : public T {
2022-03-16 22:38:08 +00:00
int delete_row(sqlite3_vtab* vt, sqlite3_int64 rowid)
{
vt->zErrMsg = sqlite3_mprintf("Rows cannot be deleted from this table");
return SQLITE_ERROR;
};
2022-03-16 22:38:08 +00:00
int insert_row(sqlite3_vtab* tab, sqlite3_int64& rowid_out)
{
tab->zErrMsg
= sqlite3_mprintf("Rows cannot be inserted into this table");
return SQLITE_ERROR;
};
2022-03-16 22:38:08 +00:00
int update_row(sqlite3_vtab* tab, sqlite3_int64& rowid_out)
{
tab->zErrMsg = sqlite3_mprintf("Rows cannot be updated in this table");
return SQLITE_ERROR;
};
};
#endif