boost_sqlite 1
A sqlite C++ library
Loading...
Searching...
No Matches
vtable.hpp
1//
2// Copyright (c) 2022 Klemens Morgenstern (klemens.morgenstern@gmx.net)
3//
4// Distributed under the Boost Software License, Version 1.0. (See accompanying
5// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6//
7
8#ifndef BOOST_SQLITE_VTABLE_HPP
9#define BOOST_SQLITE_VTABLE_HPP
10
11#include <boost/sqlite/detail/config.hpp>
12#include <boost/sqlite/detail/catch.hpp>
13#include <boost/sqlite/function.hpp>
14
15#include <boost/core/span.hpp>
16#include <boost/core/demangle.hpp>
17
18#include <bitset>
19
20BOOST_SQLITE_BEGIN_NAMESPACE
21namespace detail
22{
23struct vtab_impl;
24}
25
26
27namespace vtab
28{
29
32{
43 template<typename Func>
44 void set(Func & func)
45 {
46 set_impl(func, static_cast<callable_traits::args_t<Func>*>(nullptr));
47 }
48
49 template<typename ... Args, std::size_t Extent>
50 void set(void(* ptr)(context<Args...>, span<value, Extent>)) noexcept
51 {
52 *ppArg_ = reinterpret_cast<void*>(ptr);
53 *pxFunc_ =
54 +[](sqlite3_context* ctx, int len, sqlite3_value** args)
55 {
56 auto cc = context<Args...>(ctx);
57 auto aa = reinterpret_cast<value*>(args);
58 auto &f = *reinterpret_cast<void(*)(context<Args...>, span<value, Extent>)>(sqlite3_user_data(ctx));
59 detail::execute_context_function(ctx, f, cc, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)});
60 };
61 }
62
63 template<typename T, typename ... Args, std::size_t Extent>
64 void set(T(* ptr)(context<Args...>, span<value, Extent>))
65 {
66 *ppArg_ = reinterpret_cast<void*>(ptr);
67 *pxFunc_ =
68 +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept
69 {
70 auto cc = context<Args...>(ctx);
71 auto aa = reinterpret_cast<value*>(args);
72 auto &f = *reinterpret_cast<T(*)(context<Args...>, span<value, Extent>)>(sqlite3_user_data(ctx));
73 detail::execute_context_function(ctx, f, cc, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)});
74 };
75 }
76
77 template<std::size_t Extent>
78 void set(void(* ptr)(span<value, Extent>))
79 {
80 *ppArg_ = reinterpret_cast<void*>(ptr);
81 *pxFunc_ =
82 +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept
83 {
84 auto aa = reinterpret_cast<value*>(args);
85 auto &f = *reinterpret_cast<void(*)(span<value, Extent>)>(sqlite3_user_data(ctx));
86 detail::execute_context_function(ctx, f, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)});
87 };
88 }
89
90 template<typename T, std::size_t Extent>
91 void set(T(* ptr)(span<value, Extent>))
92 {
93 *ppArg_ = reinterpret_cast<void*>(ptr);
94 *pxFunc_ =
95 +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept
96 {
97 auto aa = reinterpret_cast<value*>(args);
98 auto &f = *reinterpret_cast<T(*)(span<value, Extent>)>(sqlite3_user_data(ctx));
99 detail::execute_context_function(ctx, f, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)});
100 };
101 }
102
103 explicit function_setter(void (**pxFunc)(sqlite3_context*,int,sqlite3_value**),
104 void **ppArg) : pxFunc_(pxFunc), ppArg_(ppArg) {}
105 private:
106
107 template<typename Func, typename ... Args, std::size_t Extent>
108 void set_impl(Func & func, std::tuple<context<Args...>, span<value, Extent>>)
109 {
110 *ppArg_ = &func;
111 *pxFunc_ =
112 +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept
113 {
114 auto cc = context<Args...>(ctx);
115 auto aa = reinterpret_cast<value*>(args);
116 auto &f = *reinterpret_cast<Func*>(sqlite3_user_data(ctx));
117 detail::execute_context_function(ctx, f, cc, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)});
118 };
119 }
120 template<typename Func, std::size_t Extent>
121 void set_impl(Func & func, std::tuple<span<value, Extent>> * )
122 {
123 *ppArg_ = &func;
124 *pxFunc_ =
125 +[](sqlite3_context* ctx, int len, sqlite3_value** args) noexcept
126 {
127 auto aa = reinterpret_cast<value*>(args);
128 auto &f = *reinterpret_cast<Func *>(sqlite3_user_data(ctx));
129 detail::execute_context_function(ctx, f, boost::span<value, Extent>{aa, static_cast<std::size_t>(len)});
130 };
131 }
132
133 void (**pxFunc_)(sqlite3_context*,int,sqlite3_value**);
134 void **ppArg_;
135};
136
137#if SQLITE_VERSION_NUMBER >= 3038000
143struct in
144{
145 struct iterator
146 {
147 iterator() = default;
148 explicit iterator(sqlite3_value * value ) : value_(value)
149 {
150 if (value == nullptr)
151 return ;
152 auto res = sqlite3_vtab_in_first(value, &out_.handle());
153 if (res != SQLITE_OK)
154 {
155 system::error_code ec;
156 BOOST_SQLITE_ASSIGN_EC(ec, res);
157 detail::throw_error_code(ec, ec.location());
158 }
159 }
160
161 iterator & operator++()
162 {
163 auto res = sqlite3_vtab_in_next(value_, &out_.handle());
164 if (res != SQLITE_OK)
165 {
166 system::error_code ec;
167 BOOST_SQLITE_ASSIGN_EC(ec, res);
168 detail::throw_error_code(ec, ec.location());
169 }
170 return *this;
171 }
172
173 iterator operator++(int)
174 {
175 auto last = *this;
176 ++(*this);
177 return last;
178 }
179
180
181 const value & operator*() const
182 {
183 return out_;
184 }
185
186 const value * operator->() const
187 {
188 return &out_;
189 }
190
191 bool operator==(const iterator& other) const
192 {
193 return value_ == other.value_
194 && out_.handle() == other.out_.handle();
195 }
196
197 bool operator!=(const iterator& other) const
198 {
199 return value_ != other.value_
200 || out_.handle() != other.out_.handle();
201 }
202
203
204 private:
205 sqlite3_value * value_{nullptr};
206 value out_{nullptr};
207 };
208
210 iterator begin() {return iterator(out_);}
212 iterator end() {return iterator();}
213
214 explicit in(sqlite3_value * out) : out_(out) {}
215 explicit in(sqlite::value out) : out_(out.handle()) {}
216 private:
217 sqlite3_value * out_{nullptr};
218};
219
220#endif
221
226{
228 BOOST_ATTRIBUTE_NODISCARD
229 span<const sqlite3_index_info::sqlite3_index_constraint> constraints() const
230 {
231 return {info_->aConstraint, static_cast<std::size_t>(info_->nConstraint)};
232 }
233
235 BOOST_ATTRIBUTE_NODISCARD
236 span<const sqlite3_index_info::sqlite3_index_orderby> order_by() const
237 {
238 return {info_->aOrderBy, static_cast<std::size_t>(info_->nOrderBy)};
239 }
240
241 BOOST_ATTRIBUTE_NODISCARD
242 span<sqlite3_index_info::sqlite3_index_constraint_usage> usage()
243 {
244 return {info_->aConstraintUsage, static_cast<std::size_t>(info_->nConstraint)};
245 }
246
247 BOOST_ATTRIBUTE_NODISCARD
248 sqlite3_index_info::sqlite3_index_constraint_usage & usage_of(
249 const sqlite3_index_info::sqlite3_index_constraint & info)
250 {
251 auto dist = std::distance(constraints().begin(), &info);
252 auto itr = usage().begin() + dist;
253 BOOST_ASSERT(itr < usage().end());
254 return *itr;
255 }
256
257#if SQLITE_VERSION_NUMBER >= 3022000
258
260 const char * collation(std::size_t idx) const
261 {
262 return sqlite3_vtab_collation(info_, static_cast<int>(idx));
263 }
264#endif
265
266 int on_conflict() const {return sqlite3_vtab_on_conflict(db_);}
267
268#if SQLITE_VERSION_NUMBER >= 3038000
270 bool distinct() const {return sqlite3_vtab_distinct(info_);}
271
272 value * rhs_value(std::size_t idx) const
273 {
274 value * v = nullptr;
275 if (sqlite3_vtab_rhs_value(
276 info_, static_cast<int>(idx),
277 reinterpret_cast<sqlite3_value**>(v)) == SQLITE_OK)
278 return v;
279 else
280 return nullptr;
281 }
282#endif
283
284 void set_already_ordered() { info_->orderByConsumed = 1; }
285 void set_estimated_cost(double cost) { info_->estimatedCost = cost; }
286#if SQLITE_VERSION_NUMBER >= 3008200
287 void set_estimated_rows(sqlite3_int64 rows) { info_->estimatedRows = rows; }
288#endif
289#if SQLITE_VERSION_NUMBER >= 3009000
290 void set_index_scan_flags(int flags) { info_->idxFlags = flags; }
291#endif
292#if SQLITE_VERSION_NUMBER >= 3010000
293 std::bitset<64u> columns_used()
294 {
295 return std::bitset<64u>(info_->colUsed);
296 }
297#endif
298
299 void set_index(int value) { info_->idxNum = value; }
300 void set_index_string(char * str,
301 bool take_ownership = true)
302 {
303 info_->idxStr = str;
304 info_->needToFreeIdxStr = take_ownership ? 1 : 0;
305 }
306
307 sqlite3_index_info * info() const { return info_; }
308 sqlite3 * db() const { return db_; }
309
310 private:
311 explicit index_info(sqlite3 * db, sqlite3_index_info * info) : db_(db), info_(info) {}
312 sqlite3 * db_;
313 sqlite3_index_info * info_{nullptr};
314 friend struct detail::vtab_impl;
315};
316
317
318struct module_config
319{
320#if SQLITE_VERSION_NUMBER >= 3031000
322 void set_innocuous()
323 {
324 sqlite3_vtab_config(db_, SQLITE_VTAB_INNOCUOUS);
325 }
327 void set_directonly() {sqlite3_vtab_config(db_, SQLITE_VTAB_DIRECTONLY);}
328
329#endif
330
332 void set_constraint_support(bool enabled = false)
333 {
334 sqlite3_vtab_config(db_, SQLITE_VTAB_CONSTRAINT_SUPPORT, enabled ? 1 : 0);
335 }
336
337 private:
338 explicit module_config(sqlite3 *db) : db_(db) {}
339 friend struct detail::vtab_impl;
340 sqlite3 *db_;
341};
342
343template<typename Table>
344struct module
345{
346 using table_type = Table;
347
351 BOOST_SQLITE_VIRTUAL result<table_type> create(sqlite::connection db, int argc, const char * const argv[]) BOOST_SQLITE_PURE;
352
356 BOOST_SQLITE_VIRTUAL result<table_type> connect(sqlite::connection db, int argc, const char * const argv[]) BOOST_SQLITE_PURE;
357};
358
359template<typename Table>
360struct eponymous_module
361{
362 using table_type = Table;
363
367 BOOST_SQLITE_VIRTUAL result<table_type> connect(sqlite::connection db, int argc, const char * const argv[]) BOOST_SQLITE_PURE;
368
369 eponymous_module(bool eponymous_only = false) : eponymous_only_(eponymous_only) {}
370
371 bool eponymous_only() const {return eponymous_only_;}
372 protected:
373 bool eponymous_only_{false};
374
375};
376
377template<typename ColumnType>
378struct cursor;
379
381template<typename Cursor>
382struct table : protected sqlite3_vtab
383{
384 using cursor_type = Cursor;
385
386 BOOST_SQLITE_VIRTUAL result<void> config(module_config &) {return {};}
387
389 BOOST_SQLITE_VIRTUAL const char *declaration() BOOST_SQLITE_PURE;
390
392 BOOST_SQLITE_VIRTUAL result<void> destroy() { return {}; }
393
396 BOOST_SQLITE_VIRTUAL result<void> best_index(index_info & info) {return {system::in_place_error, SQLITE_OK};}
397
400 BOOST_SQLITE_VIRTUAL result<cursor_type> open() BOOST_SQLITE_PURE;
401
403 sqlite::connection connection() const {return sqlite::connection{db_, false};}
404
405 table(const sqlite::connection & conn) : db_(conn.handle()) {}
406 table(sqlite3 * db = nullptr) : db_(db) {}
407 private:
408 template<typename ColumnType>
409 friend struct cursor;
410 friend struct detail::vtab_impl;
411
412 sqlite3 * db_{nullptr};
413};
414
416template<typename ColumnType = void>
417struct cursor : protected sqlite3_vtab_cursor
418{
419 using column_type = ColumnType;
420
422 BOOST_SQLITE_VIRTUAL result<void> filter(
423 int index, const char * index_data,
424 boost::span<sqlite::value> values)
425 {
426 return {system::in_place_error, SQLITE_OK};
427 }
428
430 BOOST_SQLITE_VIRTUAL result<void> next() BOOST_SQLITE_PURE;
431
433 BOOST_SQLITE_VIRTUAL bool eof() BOOST_SQLITE_PURE;
434
437 BOOST_SQLITE_VIRTUAL result<column_type> column(int idx, bool no_change) BOOST_SQLITE_PURE;
439 BOOST_SQLITE_VIRTUAL result<sqlite3_int64> row_id() BOOST_SQLITE_PURE;
440
442 vtab::table<cursor> & table() { return *static_cast< vtab::table<cursor>*>(this->pVtab);}
443 const vtab::table<cursor> & table() const { return *static_cast<const vtab::table<cursor>*>(this->pVtab);}
444
445 friend struct detail::vtab_impl;
446};
447
449template<>
450struct cursor<void> : protected sqlite3_vtab_cursor
451{
452 using column_type = void;
453
455 BOOST_SQLITE_VIRTUAL result<void> filter(
456 int index, const char * index_data,
457 boost::span<sqlite::value> values)
458 {
459 return {system::in_place_error, SQLITE_OK};
460 }
461
463 BOOST_SQLITE_VIRTUAL result<void> next() BOOST_SQLITE_PURE;
464
466 BOOST_SQLITE_VIRTUAL bool eof() BOOST_SQLITE_PURE;
467
470 BOOST_SQLITE_VIRTUAL void column(context<> ctx, int idx, bool no_change) BOOST_SQLITE_PURE;
472 BOOST_SQLITE_VIRTUAL result<sqlite3_int64> row_id() BOOST_SQLITE_PURE;
473
475 vtab::table<cursor> & table() { return *static_cast< vtab::table<cursor>*>(this->pVtab);}
476 const vtab::table<cursor> & table() const { return *static_cast<const vtab::table<cursor>*>(this->pVtab);}
477
478 friend struct detail::vtab_impl;
479};
480
481
484{
485 BOOST_SQLITE_VIRTUAL result<void> delete_(sqlite::value key) BOOST_SQLITE_PURE;
487 BOOST_SQLITE_VIRTUAL result<sqlite_int64> insert(sqlite::value key, span<sqlite::value> values, int on_conflict) BOOST_SQLITE_PURE;
489 BOOST_SQLITE_VIRTUAL result<sqlite_int64> update(sqlite::value old_key, sqlite::value new_key, span<sqlite::value> values, int on_conflict) BOOST_SQLITE_PURE;
490};
491
494{
496 BOOST_SQLITE_VIRTUAL result<void> begin() BOOST_SQLITE_PURE;
498 BOOST_SQLITE_VIRTUAL result<void> sync() BOOST_SQLITE_PURE;
500 BOOST_SQLITE_VIRTUAL result<void> commit() BOOST_SQLITE_PURE;
502 BOOST_SQLITE_VIRTUAL result<void> rollback() BOOST_SQLITE_PURE;
503};
504
507{
509 BOOST_SQLITE_VIRTUAL result<void> find_function(
511 int arg, const char * name) BOOST_SQLITE_PURE;
512};
513
516{
518 BOOST_SQLITE_VIRTUAL result<void> rename(const char * new_name) BOOST_SQLITE_PURE;
519
520};
521
522#if SQLITE_VERSION_NUMBER >= 3007007
525{
527 BOOST_SQLITE_VIRTUAL result<void> savepoint(int i) BOOST_SQLITE_PURE;
529 BOOST_SQLITE_VIRTUAL result<void> release(int i) BOOST_SQLITE_PURE;
531 BOOST_SQLITE_VIRTUAL result<void> rollback_to(int i) BOOST_SQLITE_PURE;
532};
533#endif
534
535}
536
537
538namespace detail
539{
540
541template<typename Module>
542const sqlite3_module make_module(const Module & mod);
543
544}
545
547
565template<typename T>
567 cstring_ref name,
568 T && module,
569 system::error_code & ec,
570 error_info & ei) -> typename std::decay<T>::type &
571{
572 using module_type = typename std::decay<T>::type;
573 static const sqlite3_module mod = detail::make_module(module);
574
575 std::unique_ptr<module_type> p{new (memory_tag{}) module_type(std::forward<T>(module))};
576 auto pp = p.get();
577
578 int res = sqlite3_create_module_v2(
579 conn.handle(), name.c_str(),
580 &mod, p.release(),
581 +[](void * ptr)
582 {
583 static_cast<module_type*>(ptr)->~module_type();
584 sqlite3_free(ptr);
585 });
586
587 if (res != SQLITE_OK)
588 {
589 BOOST_SQLITE_ASSIGN_EC(ec, res);
590 ei.set_message(sqlite3_errmsg(conn.handle()));
591 }
592 return *pp;
593}
594
595template<typename T>
596auto create_module(connection & conn,
597 const char * name,
598 T && module) -> typename std::decay<T>::type &
599{
600 system::error_code ec;
601 error_info ei;
602 T & ref = create_module(conn, name, std::forward<T>(module), ec, ei);
603 if (ec)
604 detail::throw_error_code(ec, ei);
605 return ref;
606}
608
609
610BOOST_SQLITE_END_NAMESPACE
611
612#include <boost/sqlite/detail/vtable.hpp>
613
614#endif //BOOST_SQLITE_VTABLE_HPP
615
auto create_module(connection &conn, cstring_ref name, T &&module, system::error_code &ec, error_info &ei) -> typename std::decay< T >::type &
Register a vtable.
Definition vtable.hpp:566
main object for a connection to a database.
A context that can be passed into scalar functions.
Definition function.hpp:54
Small wrapper for a null-terminated string that can be directly passed to C APIS.
Additional information about error conditions stored in an sqlite-allocate string.
Definition error.hpp:33
A holder for a sqlite values used for internal APIs.
Definition value.hpp:39
handle_type handle() const
Returns the handle.
Definition value.hpp:100
virtual result< void > next()=0
Returns the next row.
virtual result< void > filter(int index, const char *index_data, boost::span< sqlite::value > values)
Apply a filter to the cursor. Required when best_index is implemented.
Definition vtable.hpp:455
Cursor needs the following member.
Definition vtable.hpp:418
virtual result< void > next()=0
Returns the next row.
virtual result< void > filter(int index, const char *index_data, boost::span< sqlite::value > values)
Apply a filter to the cursor. Required when best_index is implemented.
Definition vtable.hpp:422
Helper type to set a function through the xFindFunction callback.
Definition vtable.hpp:32
Utility function that can be used in xFilter for the in operator.
Definition vtable.hpp:144
iterator end()
Returns a forward iterator to the in sequence for an in constraint pointing to the end.
Definition vtable.hpp:212
iterator begin()
Returns a forward iterator to the in sequence for an in constraint pointing to the begin.
Definition vtable.hpp:210
bool distinct() const
Returns true if the constraint is.
Definition vtable.hpp:270
BOOST_ATTRIBUTE_NODISCARD span< const sqlite3_index_info::sqlite3_index_constraint > constraints() const
Returns constraints of the index.
Definition vtable.hpp:229
const char * collation(std::size_t idx) const
Receive the collation for the contrainst of the position.
Definition vtable.hpp:260
BOOST_ATTRIBUTE_NODISCARD span< const sqlite3_index_info::sqlite3_index_orderby > order_by() const
Returns ordering of the index.
Definition vtable.hpp:236
Group of functions for modifications.
Definition vtable.hpp:484
virtual result< sqlite_int64 > update(sqlite::value old_key, sqlite::value new_key, span< sqlite::value > values, int on_conflict)=0
Update the row.
virtual result< sqlite_int64 > insert(sqlite::value key, span< sqlite::value > values, int on_conflict)=0
Insert a new row.
Fucntion to enable function overriding See xFindFunction.
Definition vtable.hpp:507
virtual result< void > find_function(function_setter fs, int arg, const char *name)=0
Support for recursive transactions.
Definition vtable.hpp:525
virtual result< void > savepoint(int i)=0
Save the current state with to i
virtual result< void > release(int i)=0
Release all saves states down to i
virtual result< void > rollback_to(int i)=0
Roll the transaction back to i.
Make the vtable renamable.
Definition vtable.hpp:516
virtual result< void > rename(const char *new_name)=0
Function to rename the table. Optional.
The basis for vtable.
Definition vtable.hpp:383
virtual result< cursor_type > open()=0
Start a search on the table. The cursor_type gets used & managed by value, OR a pointer to a class th...
virtual result< void > best_index(index_info &info)
Definition vtable.hpp:396
virtual const char * declaration()=0
The Table declaration to be used with sqlite3_declare_vtab.
Group of functions to support transactions.
Definition vtable.hpp:494
virtual result< void > begin()=0
Begin a tranasction.