diff options
author | John Turner <jturner.usa@gmail.com> | 2025-09-14 00:16:10 -0400 |
---|---|---|
committer | John Turner <jturner.usa@gmail.com> | 2025-09-14 00:16:10 -0400 |
commit | 13e0821fd783a1d5083d825af53cf20e8dcbfd76 (patch) | |
tree | 1ea363b0f13b3e87d177100e6ae6b9f30a2de1b8 /subprojects/boost-sqlite/include/boost/sqlite/detail/vtable.hpp | |
parent | aa55cb93036a89c64c08e08f4e1de4fa1fd5a775 (diff) | |
parent | efcea3a80da7c4479d5fe168435ecc9fd06bdc72 (diff) | |
download | sqlite-kv-bench-13e0821fd783a1d5083d825af53cf20e8dcbfd76.tar.gz |
Merge commit 'efcea3a80da7c4479d5fe168435ecc9fd06bdc72' as 'subprojects/boost-sqlite'
Diffstat (limited to 'subprojects/boost-sqlite/include/boost/sqlite/detail/vtable.hpp')
-rw-r--r-- | subprojects/boost-sqlite/include/boost/sqlite/detail/vtable.hpp | 611 |
1 files changed, 611 insertions, 0 deletions
diff --git a/subprojects/boost-sqlite/include/boost/sqlite/detail/vtable.hpp b/subprojects/boost-sqlite/include/boost/sqlite/detail/vtable.hpp new file mode 100644 index 0000000..f85f44c --- /dev/null +++ b/subprojects/boost-sqlite/include/boost/sqlite/detail/vtable.hpp @@ -0,0 +1,611 @@ +// Copyright (c) 2023 Klemens D. Morgenstern +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) +#ifndef BOOST_SQLITE_DETAIL_VTABLE_HPP +#define BOOST_SQLITE_DETAIL_VTABLE_HPP + +#include <boost/sqlite/detail/config.hpp> +#include <boost/sqlite/detail/catch.hpp> +#include <boost/sqlite/vtable.hpp> + +BOOST_SQLITE_BEGIN_NAMESPACE +namespace detail +{ +struct vtab_impl +{ + +template<typename Module> +static int connect(sqlite3 * db, void * pAux, int argc, const char * const * argv, + sqlite3_vtab **ppVTab, char** errMsg) +{ + using table_type = typename Module::table_type; + auto &impl = *static_cast<Module*>(pAux); + BOOST_SQLITE_TRY + { + result<table_type> rtab = impl.connect( + sqlite::connection(db, false), + argc, argv); + + if (rtab.has_error()) + return extract_error(*errMsg, rtab); + + auto tab = make_unique<table_type>(std::move(*rtab)); + tab->db_ = db; + auto code = sqlite3_declare_vtab(db, tab->declaration()); + if (code != SQLITE_OK) + return code; + + sqlite::vtab::module_config cfg{db}; + auto r = tab->config(cfg); + if (r.has_error()) + return extract_error(*errMsg, r); + + *ppVTab = tab.release(); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(*errMsg) +} + + +template<typename Module> +static int create(sqlite3 * db, void * pAux, int argc, const char * const * argv, + sqlite3_vtab **ppVTab, char** errMsg) +{ + using table_type = typename Module::table_type; + auto &impl = *static_cast<Module*>(pAux); + BOOST_SQLITE_TRY + { + result<table_type> rtab = impl.create( + sqlite::connection(db, false), + argc, argv); + + if (rtab.has_error()) + return extract_error(*errMsg, rtab); + + auto tab = make_unique<table_type>(std::move(*rtab)); + tab->db_ = db; + + auto code = sqlite3_declare_vtab(db, tab->declaration()); + if (code != SQLITE_OK) + return code; + + sqlite::vtab::module_config mc{db}; + auto r = tab->config(mc); + if (r.has_error()) + return extract_error(*errMsg, r); + + *ppVTab = tab.release(); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(*errMsg) +} + +template<typename Table> +static int disconnect(sqlite3_vtab * tab) +{ + BOOST_SQLITE_TRY + { + auto tb = static_cast<Table*>(tab); + tb->~Table(); + sqlite3_free(tb); + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(tab->zErrMsg); +} + +template<typename Table> +static int destroy(sqlite3_vtab * tab) +{ + BOOST_SQLITE_TRY + { + auto tb = static_cast<Table*>(tab); + auto res = tb->destroy(); + tb->~Table(); + sqlite3_free(tb); + if (res.has_error()) + return std::move(res).error().code; + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(tab->zErrMsg); +} + +template<typename Module, typename Table> +static void assign_create(sqlite3_module & md, const Module &, + const sqlite::vtab::eponymous_module<Table> & base) +{ + md.xConnect = md.xCreate = &connect<Module>; + md.xDisconnect = md.xDestroy = &disconnect<Table>; + if (base.eponymous_only()) + md.xCreate = nullptr; +} + +template<typename Module, typename Table> +static void assign_create(sqlite3_module & md, const Module &, + const sqlite::vtab::module<Table> &) +{ + md.xConnect = &connect<Module>; + md.xDisconnect = &disconnect<Table>; + md.xCreate = &create<Module>; + md.xDestroy = &destroy<Table>; +} + +template<typename Table> +static int open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor) +{ + auto tab = static_cast<Table *>(pVTab); + + BOOST_SQLITE_TRY + { + auto res = tab->open(); + if (res.has_error()) + return extract_error(pVTab->zErrMsg, res); + *ppCursor = new (memory_tag{}) typename Table::cursor_type(std::move(*res)); + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_AND_RETURN(); +} + +template<typename Cursor> +static int close(sqlite3_vtab_cursor * cursor) +{ + auto p = static_cast<Cursor *>(cursor); + + BOOST_SQLITE_TRY + { + p->~Cursor(); + } + BOOST_SQLITE_CATCH_AND_RETURN(); + + sqlite3_free(p); + return SQLITE_OK; + +} + +template<typename Table> +static int best_index(sqlite3_vtab *pVTab, sqlite3_index_info* info) +{ + BOOST_SQLITE_TRY + { + auto tb = static_cast<Table*>(pVTab); + + sqlite::vtab::index_info ii(tb->db_, info); + auto r = tb->best_index(ii); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); +} + + +template<typename Cursor> +static int filter(sqlite3_vtab_cursor* pCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Cursor*>(pCursor); + + auto r = cr->filter(idxNum, idxStr, + boost::span<value>{reinterpret_cast<value*>(argv), + static_cast<std::size_t>(argc)}); + if (r.has_error()) + return extract_error(pCursor->pVtab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pCursor->pVtab->zErrMsg); +} + + +template<typename Cursor> +static int next(sqlite3_vtab_cursor* pCursor) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Cursor*>(pCursor); + + auto r = cr->next(); + if (r.has_error()) + return extract_error(pCursor->pVtab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pCursor->pVtab->zErrMsg); +} + + +template<typename Cursor> +static int eof(sqlite3_vtab_cursor* pCursor) +{ + return static_cast<Cursor*>(pCursor)->eof() ? 1 : 0; +} + +template<typename Cursor> +static auto column(sqlite3_vtab_cursor* pCursor, + sqlite3_context * ctx, int idx) + -> typename std::enable_if<!std::is_void<typename Cursor::column_type>::value, int>::type +{ +#if SQLITE_VERSION_NUMBER >= 3032000 + bool no_change = sqlite3_vtab_nochange(ctx) != 0; +#else + bool no_change = false; +#endif + auto cr = static_cast<Cursor*>(pCursor); + execute_context_function( + ctx, + [&]{ + return cr->column(idx, no_change); + }); + + return SQLITE_OK; +} + + +template<typename Cursor> +static auto column(sqlite3_vtab_cursor* pCursor, + sqlite3_context * ctx, int idx) + -> typename std::enable_if<std::is_void<typename Cursor::column_type>::value, int>::type +{ +#if SQLITE_VERSION_NUMBER >= 3032000 + bool no_change = sqlite3_vtab_nochange(ctx) != 0; +#else + bool no_change = false; +#endif + auto cr = static_cast<Cursor*>(pCursor); + BOOST_SQLITE_TRY + { + cr->column(context<>{ctx}, idx, no_change); + } + BOOST_SQLITE_CATCH_RESULT(ctx); + return SQLITE_OK; +} + +template<typename Cursor> +static int row_id(sqlite3_vtab_cursor* pCursor, sqlite3_int64 *pRowid) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Cursor*>(pCursor); + + auto r = cr->row_id(); + if (r.has_error()) + return extract_error(pCursor->pVtab->zErrMsg, r); + *pRowid = *r; + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pCursor->pVtab->zErrMsg); +} + +template<typename Table> +static int update(sqlite3_vtab * pVTab, int argc, sqlite3_value ** argv, sqlite3_int64 * pRowid) +{ + using table_type = Table; + BOOST_SQLITE_TRY + { + auto & mod = *static_cast<table_type *>(pVTab); + auto db = mod.db_; + if (argc == 1 && sqlite3_value_type(argv[0]) != SQLITE_NULL) + { + auto r = mod.delete_(sqlite::value(*argv)); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + } + else if (argc > 1 && sqlite3_value_type(argv[0]) == SQLITE_NULL) + { + auto r = mod.insert(value{argv[1]}, + boost::span<value>{reinterpret_cast<value *>(argv + 2), + static_cast<std::size_t>(argc - 2)}, + sqlite3_vtab_on_conflict(db)); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + *pRowid = r.value(); + } + else if (argc > 1 && sqlite3_value_type(argv[0]) != SQLITE_NULL) + { + auto r = mod.update(sqlite::value(*argv), value{argv[1]}, // ID + boost::span<value>{reinterpret_cast<value *>(argv + 2), + static_cast<std::size_t>(argc - 2)}, + sqlite3_vtab_on_conflict(db)); + + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + *pRowid = r.value(); + } + else + { + pVTab->zErrMsg = sqlite3_mprintf("Misuse of update api"); + return SQLITE_MISUSE; + } + + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg) + return SQLITE_OK; +} + +template<typename Module> +static void assign_update(sqlite3_module & md, const Module &, + std::true_type /* modifiable */) +{ + md.xUpdate = &update<typename Module::table_type>; +} + +template<typename Module> +static void assign_update(sqlite3_module & /*md*/, const Module &, + std::false_type /* modifiable */) +{ +} + +template<typename Table> +static int begin(sqlite3_vtab* pVTab) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Table*>(pVTab); + + auto r = cr->begin(); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); +} + +template<typename Table> +static int sync(sqlite3_vtab* pVTab) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Table*>(pVTab); + + auto r = cr->sync(); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); +} + +template<typename Table> +static int commit(sqlite3_vtab* pVTab) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Table*>(pVTab); + + auto r = cr->commit(); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); +} + +template<typename Table> +static int rollback(sqlite3_vtab* pVTab) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Table*>(pVTab); + + auto r = cr->rollback(); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); +} + +template<typename Module> +static void assign_transaction(sqlite3_module & /*md*/, const Module &, + std::false_type /* modifiable */) +{ +} + +template<typename Module> +static void assign_transaction(sqlite3_module & md, const Module &, + std::true_type /* modifiable */) +{ + md.xBegin = &begin <typename Module::table_type>; + md.xSync = &sync <typename Module::table_type>; + md.xCommit = &commit <typename Module::table_type>; + md.xRollback = &rollback<typename Module::table_type>; +} + +template<typename Table> +static int find_function(sqlite3_vtab *pVtab, int nArg, const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Table*>(pVtab); + + auto r = cr->find_function( + nArg, zName, sqlite::vtab::function_setter(pxFunc, ppArg)); + if (r.has_error()) + return extract_error(pVtab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVtab->zErrMsg); +} + +template<typename Module> +static void assign_find_function(sqlite3_module & /*md*/, const Module &, + std::false_type /* overloadable */) +{ +} + +template<typename Module> +static void assign_find_function(sqlite3_module & md, const Module &, + std::true_type /* overloadable */) +{ + md.xFindFunction = &find_function<typename Module::table_type>; +} + +template<typename Table> +static int rename(sqlite3_vtab* pVTab, const char * name) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Table*>(pVTab); + + auto r = cr->rename(name); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); +} + +template<typename Module> +static void assign_rename(sqlite3_module & /*md*/, const Module &, + std::false_type /* renamable */) +{ +} + +template<typename Module> +static void assign_rename(sqlite3_module & md, const Module &, + std::true_type /* renamable */) +{ + md.xRename = &rename<typename Module::table_type>; +} +#if SQLITE_VERSION_NUMBER >= 3007007 + +template<typename Table> +static int savepoint(sqlite3_vtab* pVTab, int i) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Table*>(pVTab); + + auto r = cr->savepoint(i); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); +} + +template<typename Table> +static int release(sqlite3_vtab* pVTab, int i) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Table*>(pVTab); + + auto r = cr->release(i); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); +} + +template<typename Table> +static int rollback_to(sqlite3_vtab* pVTab, int i) +{ + BOOST_SQLITE_TRY + { + auto cr = static_cast<Table*>(pVTab); + + auto r = cr->rollback_to(i); + if (r.has_error()) + return extract_error(pVTab->zErrMsg, r); + + return SQLITE_OK; + } + BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg); +} + +template<typename Module> +static void assign_recursive_transaction(sqlite3_module & /*md*/, const Module &, + std::false_type /* recursive_transaction */) +{ +} + +template<typename Module> +static void assign_recursive_transaction(sqlite3_module & md, const Module &, + std::true_type /* recursive_transaction */) +{ + md.xSavepoint = &savepoint <typename Module::table_type>; + md.xRelease = &release <typename Module::table_type>; + md.xRollbackTo = &rollback_to<typename Module::table_type>; +} + +#endif + +#if SQLITE_VERSION_NUMBER >= 3026000 + +template<typename Table> +static void assign_shadow_name(sqlite3_module & /*md*/, const sqlite::vtab::module<Table> &) {} + +template<typename Table> +static void assign_shadow_name(sqlite3_module & /*md*/, const sqlite::vtab::eponymous_module<Table> &) {} + +template<typename Module, + bool (*Func)(const char *) = &Module::shadow_name> +static void assign_shadow_name(sqlite3_module & md, const Module & mod) +{ + md.xShadowName = +[](const char * name){return Func(name) != 0;}; +} + +#endif + +}; + +template<typename Module> +const sqlite3_module make_module(const Module & mod) +{ + sqlite3_module md; + std::memset(&md, 0, sizeof(sqlite3_module)); + +#if SQLITE_VERSION_NUMBER < 3007007 + md.iVersion = 1; +#elif SQLITE_VERSION_NUMBER < 3026000 + md.iVersion = 2; +#else + md.iVersion = 3; +#endif + using table_type = typename Module::table_type; + using cursor_type = typename table_type::cursor_type; + vtab_impl::assign_create(md, mod, mod); + md.xBestIndex = &vtab_impl::best_index<table_type>; + md.xOpen = &vtab_impl::open <table_type>; + md.xClose = &vtab_impl::close <cursor_type>; + md.xFilter = &vtab_impl::filter <cursor_type>; + md.xNext = &vtab_impl::next <cursor_type>; + md.xEof = &vtab_impl::eof <cursor_type>; + md.xColumn = &vtab_impl::column <cursor_type>; + md.xRowid = &vtab_impl::row_id <cursor_type>; + vtab_impl::assign_update (md, mod, std::is_base_of<sqlite::vtab::modifiable, table_type>{}); + vtab_impl::assign_transaction (md, mod, std::is_base_of<sqlite::vtab::transaction, table_type>{}); + vtab_impl::assign_find_function(md, mod, std::is_base_of<sqlite::vtab::overload_functions, table_type>{}); + vtab_impl::assign_rename (md, mod, std::is_base_of<sqlite::vtab::renamable, table_type>{}); +#if SQLITE_VERSION_NUMBER >= 3007007 + vtab_impl::assign_recursive_transaction(md, mod, std::is_base_of<sqlite::vtab::recursive_transaction, table_type>{}); +#endif +#if SQLITE_VERSION_NUMBER >= 3026000 + vtab_impl::assign_shadow_name(md, mod); +#endif + return md; +} + +} + +BOOST_SQLITE_END_NAMESPACE + +#endif //BOOST_SQLITE_DETAIL_VTABLE_HPP |