5#ifndef BOOST_SQLITE_DETAIL_VTABLE_HPP
6#define BOOST_SQLITE_DETAIL_VTABLE_HPP
8#include <boost/sqlite/detail/config.hpp>
9#include <boost/sqlite/detail/catch.hpp>
10#include <boost/sqlite/vtable.hpp>
12BOOST_SQLITE_BEGIN_NAMESPACE
18template<
typename Module>
19static int connect(sqlite3 * db,
void * pAux,
int argc,
const char *
const * argv,
20 sqlite3_vtab **ppVTab,
char** errMsg)
22 using table_type =
typename Module::table_type;
23 auto &impl = *
static_cast<Module*
>(pAux);
26 result<table_type> rtab = impl.connect(
27 sqlite::connection(db,
false),
31 return extract_error(*errMsg, rtab);
33 auto tab = make_unique<table_type>(std::move(*rtab));
35 auto code = sqlite3_declare_vtab(db, tab->declaration());
36 if (code != SQLITE_OK)
39 sqlite::vtab::module_config cfg{db};
40 auto r = tab->config(cfg);
42 return extract_error(*errMsg, r);
44 *ppVTab = tab.release();
48 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(*errMsg)
52template<
typename Module>
53static int create(sqlite3 * db,
void * pAux,
int argc,
const char *
const * argv,
54 sqlite3_vtab **ppVTab,
char** errMsg)
56 using table_type =
typename Module::table_type;
57 auto &impl = *
static_cast<Module*
>(pAux);
60 result<table_type> rtab = impl.create(
61 sqlite::connection(db,
false),
65 return extract_error(*errMsg, rtab);
67 auto tab = make_unique<table_type>(std::move(*rtab));
70 auto code = sqlite3_declare_vtab(db, tab->declaration());
71 if (code != SQLITE_OK)
74 sqlite::vtab::module_config mc{db};
75 auto r = tab->config(mc);
77 return extract_error(*errMsg, r);
79 *ppVTab = tab.release();
83 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(*errMsg)
86template<
typename Table>
87static int disconnect(sqlite3_vtab * tab)
91 auto tb =
static_cast<Table*
>(tab);
96 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(tab->zErrMsg);
99template<
typename Table>
100static int destroy(sqlite3_vtab * tab)
104 auto tb =
static_cast<Table*
>(tab);
105 auto res = tb->destroy();
109 return std::move(res).error().code;
112 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(tab->zErrMsg);
115template<
typename Module,
typename Table>
116static void assign_create(sqlite3_module & md,
const Module & mod,
117 const sqlite::vtab::eponymous_module<Table> & base)
119 md.xConnect = md.xCreate = &connect<Module>;
120 md.xDisconnect = md.xDestroy = &disconnect<Table>;
121 if (base.eponymous_only())
122 md.xCreate =
nullptr;
125template<
typename Module,
typename Table>
126static void assign_create(sqlite3_module & md,
const Module & mod,
127 const sqlite::vtab::module<Table> & base)
129 md.xConnect = &connect<Module>;
130 md.xDisconnect = &disconnect<Table>;
131 md.xCreate = &create<Module>;
132 md.xDestroy = &destroy<Table>;
135template<
typename Table>
136static int open(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor)
138 auto tab =
static_cast<Table *
>(pVTab);
142 auto res = tab->open();
144 return extract_error(pVTab->zErrMsg, res);
145 *ppCursor =
new (memory_tag{})
typename Table::cursor_type(std::move(*res));
148 BOOST_SQLITE_CATCH_AND_RETURN();
151template<
typename Cursor>
152static int close(sqlite3_vtab_cursor * cursor)
154 auto p =
static_cast<Cursor *
>(cursor);
160 BOOST_SQLITE_CATCH_AND_RETURN();
167template<
typename Table>
168static int best_index(sqlite3_vtab *pVTab, sqlite3_index_info* info)
172 auto tb =
static_cast<Table*
>(pVTab);
174 sqlite::vtab::index_info ii(tb->db_, info);
175 auto r = tb->best_index(ii);
177 return extract_error(pVTab->zErrMsg, r);
181 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg);
185template<
typename Cursor>
186static int filter(sqlite3_vtab_cursor* pCursor,
187 int idxNum,
const char *idxStr,
188 int argc, sqlite3_value **argv)
192 auto cr =
static_cast<Cursor*
>(pCursor);
194 auto r = cr->filter(idxNum, idxStr,
195 boost::span<value>{
reinterpret_cast<value*
>(argv),
196 static_cast<std::size_t
>(argc)});
198 return extract_error(pCursor->pVtab->zErrMsg, r);
202 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pCursor->pVtab->zErrMsg);
206template<
typename Cursor>
207static int next(sqlite3_vtab_cursor* pCursor)
211 auto cr =
static_cast<Cursor*
>(pCursor);
215 return extract_error(pCursor->pVtab->zErrMsg, r);
219 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pCursor->pVtab->zErrMsg);
223template<
typename Cursor>
224static int eof(sqlite3_vtab_cursor* pCursor)
226 return static_cast<Cursor*
>(pCursor)->eof() ? 1 : 0;
229template<
typename Cursor>
230static auto column(sqlite3_vtab_cursor* pCursor,
231 sqlite3_context * ctx,
int idx)
232 ->
typename std::enable_if<!std::is_void<typename Cursor::column_type>::value,
int>::type
234#if SQLITE_VERSION_NUMBER >= 3032000
235 bool no_change = sqlite3_vtab_nochange(ctx) != 0;
237 bool no_change =
false;
239 auto cr =
static_cast<Cursor*
>(pCursor);
240 execute_context_function(
243 return cr->column(idx, no_change);
250template<
typename Cursor>
251static auto column(sqlite3_vtab_cursor* pCursor,
252 sqlite3_context * ctx,
int idx)
253 ->
typename std::enable_if<std::is_void<typename Cursor::column_type>::value,
int>::type
255#if SQLITE_VERSION_NUMBER >= 3032000
256 bool no_change = sqlite3_vtab_nochange(ctx) != 0;
258 bool no_change =
false;
260 auto cr =
static_cast<Cursor*
>(pCursor);
263 cr->column(context<>{ctx}, idx, no_change);
265 BOOST_SQLITE_CATCH_RESULT(ctx);
269template<
typename Cursor>
270static int row_id(sqlite3_vtab_cursor* pCursor, sqlite3_int64 *pRowid)
274 auto cr =
static_cast<Cursor*
>(pCursor);
276 auto r = cr->row_id();
278 return extract_error(pCursor->pVtab->zErrMsg, r);
282 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pCursor->pVtab->zErrMsg);
285template<
typename Table>
286static int update(sqlite3_vtab * pVTab,
int argc, sqlite3_value ** argv, sqlite3_int64 * pRowid)
288 using table_type = Table;
291 auto & mod = *
static_cast<table_type *
>(pVTab);
293 if (argc == 1 && sqlite3_value_type(argv[0]) != SQLITE_NULL)
295 auto r = mod.delete_(sqlite::value(*argv));
297 return extract_error(pVTab->zErrMsg, r);
299 else if (argc > 1 && sqlite3_value_type(argv[0]) == SQLITE_NULL)
301 auto r = mod.insert(value{argv[1]},
302 boost::span<value>{
reinterpret_cast<value *
>(argv + 2),
303 static_cast<std::size_t
>(argc - 2)},
304 sqlite3_vtab_on_conflict(db));
306 return extract_error(pVTab->zErrMsg, r);
309 else if (argc > 1 && sqlite3_value_type(argv[0]) != SQLITE_NULL)
311 auto r = mod.update(sqlite::value(*argv), value{argv[1]},
312 boost::span<value>{
reinterpret_cast<value *
>(argv + 2),
313 static_cast<std::size_t
>(argc - 2)},
314 sqlite3_vtab_on_conflict(db));
317 return extract_error(pVTab->zErrMsg, r);
322 pVTab->zErrMsg = sqlite3_mprintf(
"Misuse of update api");
323 return SQLITE_MISUSE;
327 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg)
331template<typename Module>
332static
void assign_update(sqlite3_module & md, const Module & mod,
335 md.xUpdate = &update<typename Module::table_type>;
338template<
typename Module>
339static void assign_update(sqlite3_module & md,
const Module & mod,
344template<
typename Table>
345static int begin(sqlite3_vtab* pVTab)
349 auto cr =
static_cast<Table*
>(pVTab);
351 auto r = cr->begin();
353 return extract_error(pVTab->zErrMsg, r);
357 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg);
360template<
typename Table>
361static int sync(sqlite3_vtab* pVTab)
365 auto cr =
static_cast<Table*
>(pVTab);
369 return extract_error(pVTab->zErrMsg, r);
373 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg);
376template<
typename Table>
377static int commit(sqlite3_vtab* pVTab)
381 auto cr =
static_cast<Table*
>(pVTab);
383 auto r = cr->commit();
385 return extract_error(pVTab->zErrMsg, r);
389 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg);
392template<
typename Table>
393static int rollback(sqlite3_vtab* pVTab)
397 auto cr =
static_cast<Table*
>(pVTab);
399 auto r = cr->rollback();
401 return extract_error(pVTab->zErrMsg, r);
405 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg);
408template<
typename Module>
409static void assign_transaction(sqlite3_module & md,
const Module & mod,
414template<
typename Module>
415static void assign_transaction(sqlite3_module & md,
const Module & mod,
418 md.xBegin = &begin <typename Module::table_type>;
419 md.xSync = &sync <typename Module::table_type>;
420 md.xCommit = &commit <typename Module::table_type>;
421 md.xRollback = &rollback<typename Module::table_type>;
424template<
typename Table>
425static int find_function(sqlite3_vtab *pVtab,
int nArg,
const char *zName,
426 void (**pxFunc)(sqlite3_context*,
int,sqlite3_value**),
431 auto cr =
static_cast<Table*
>(pVtab);
433 auto r = cr->find_function(
434 nArg, zName, sqlite::vtab::function_setter(pxFunc, ppArg));
436 return extract_error(pVtab->zErrMsg, r);
440 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVtab->zErrMsg);
443template<
typename Module>
444static void assign_find_function(sqlite3_module & md,
const Module & mod,
449template<
typename Module>
450static void assign_find_function(sqlite3_module & md,
const Module & mod,
453 md.xFindFunction = &find_function<typename Module::table_type>;
456template<
typename Table>
457static int rename(sqlite3_vtab* pVTab,
const char * name)
461 auto cr =
static_cast<Table*
>(pVTab);
463 auto r = cr->rename(name);
465 return extract_error(pVTab->zErrMsg, r);
469 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg);
472template<
typename Module>
473static void assign_rename(sqlite3_module & md,
const Module & mod,
478template<
typename Module>
479static void assign_rename(sqlite3_module & md,
const Module & mod,
482 md.xRename = &rename<typename Module::table_type>;
484#if SQLITE_VERSION_NUMBER >= 3007007
486template<
typename Table>
487static int savepoint(sqlite3_vtab* pVTab,
int i)
491 auto cr =
static_cast<Table*
>(pVTab);
493 auto r = cr->savepoint(i);
495 return extract_error(pVTab->zErrMsg, r);
499 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg);
502template<
typename Table>
503static int release(sqlite3_vtab* pVTab,
int i)
507 auto cr =
static_cast<Table*
>(pVTab);
509 auto r = cr->release(i);
511 return extract_error(pVTab->zErrMsg, r);
515 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg);
518template<
typename Table>
519static int rollback_to(sqlite3_vtab* pVTab,
int i)
523 auto cr =
static_cast<Table*
>(pVTab);
525 auto r = cr->rollback_to(i);
527 return extract_error(pVTab->zErrMsg, r);
531 BOOST_SQLITE_CATCH_ASSIGN_STR_AND_RETURN(pVTab->zErrMsg);
534template<
typename Module>
535static void assign_recursive_transaction(sqlite3_module & md,
const Module & mod,
540template<
typename Module>
541static void assign_recursive_transaction(sqlite3_module & md,
const Module & mod,
544 md.xSavepoint = &savepoint <typename Module::table_type>;
545 md.xRelease = &release <typename Module::table_type>;
546 md.xRollbackTo = &rollback_to<typename Module::table_type>;
551#if SQLITE_VERSION_NUMBER >= 3026000
553template<
typename Table>
554static void assign_shadow_name(sqlite3_module & md,
const sqlite::vtab::module<Table> &) {}
556template<
typename Table>
557static void assign_shadow_name(sqlite3_module & md,
const sqlite::vtab::eponymous_module<Table> &) {}
559template<
typename Module,
560 bool (*Func)(
const char *) = &Module::shadow_name>
561static void assign_shadow_name(sqlite3_module & md,
const Module & mod)
563 md.xShadowName = +[](
const char * name){
return Func(name) != 0;};
570template<
typename Module>
571const sqlite3_module make_module(
const Module & mod)
574 std::memset(&md, 0,
sizeof(sqlite3_module));
576#if SQLITE_VERSION_NUMBER < 3007007
578#elif SQLITE_VERSION_NUMBER < 3026000
583 using table_type =
typename Module::table_type;
584 using cursor_type =
typename table_type::cursor_type;
585 vtab_impl::assign_create(md, mod, mod);
586 md.xBestIndex = &vtab_impl::best_index<table_type>;
587 md.xOpen = &vtab_impl::open <table_type>;
588 md.xClose = &vtab_impl::close <cursor_type>;
589 md.xFilter = &vtab_impl::filter <cursor_type>;
590 md.xNext = &vtab_impl::next <cursor_type>;
591 md.xEof = &vtab_impl::eof <cursor_type>;
592 md.xColumn = &vtab_impl::column <cursor_type>;
593 md.xRowid = &vtab_impl::row_id <cursor_type>;
594 vtab_impl::assign_update (md, mod, std::is_base_of<sqlite::vtab::modifiable, table_type>{});
595 vtab_impl::assign_transaction (md, mod, std::is_base_of<sqlite::vtab::transaction, table_type>{});
596 vtab_impl::assign_find_function(md, mod, std::is_base_of<sqlite::vtab::overload_functions, table_type>{});
597 vtab_impl::assign_rename (md, mod, std::is_base_of<sqlite::vtab::renamable, table_type>{});
598#if SQLITE_VERSION_NUMBER >= 3007007
599 vtab_impl::assign_recursive_transaction(md, mod, std::is_base_of<sqlite::vtab::recursive_transaction, table_type>{});
601#if SQLITE_VERSION_NUMBER >= 3026000
602 vtab_impl::assign_shadow_name(md, mod);
609BOOST_SQLITE_END_NAMESPACE