ThinSQLite++
A thin, safe and convenient modern C++ wrapper for the SQLite API.
Loading...
Searching...
No Matches
vtab_iface.hpp
1/*
2 Copyright 2024 Eugene Gershnik
3
4 Use of this source code is governed by a BSD-style
5 license that can be found in the LICENSE file or at
6 https://github.com/gershnik/thinsqlitepp/blob/master/LICENSE
7*/
8
9#ifndef HEADER_SQLITEPP_VTAB_IFACE_INCLUDED
10#define HEADER_SQLITEPP_VTAB_IFACE_INCLUDED
11
12#include "database_iface.hpp"
13#include "exception_iface.hpp"
14#include "value_iface.hpp"
15#include "context_iface.hpp"
16#include "memory_iface.hpp"
17#include "span.hpp"
18
19#include <type_traits>
20#include <string.h>
21#include <cstdint>
22
23namespace thinsqlitepp {
24
29
48 SQLITEPP_EXPORTED
49 template<class T = void>
50 class index_info : public handle<sqlite3_index_info, index_info<T>>
51 {
53 "template argument must be void or a pointer to a trivially destructible type");
54 public:
61 public:
62 ~index_info() = delete;
63
66 { return { this->c_ptr()->aConstraint, size_t(this->c_ptr()->nConstraint)}; };
67
69 { return { this->c_ptr()->aOrderBy, size_t(this->c_ptr()->nOrderBy)}; };
70
71 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 10, 0)
72
77 uint64_t columns_used() const noexcept
78 { return uint64_t(this->c_ptr()->colUsed); }
79
80 #endif
81
87 const char * collation(int constraint_idx) const noexcept
88 { return sqlite3_vtab_collation(this->c_ptr(), constraint_idx); }
89
95 int distinct() const noexcept
96 { return sqlite3_vtab_distinct(this->c_ptr()); }
97
98 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 38, 0)
99
105 bool is_in(int constraint_idx) const noexcept
106 { return sqlite3_vtab_in(this->c_ptr(), constraint_idx, -1); }
107
113 void handle_in(int constraint_idx, bool handle) const noexcept
114 { sqlite3_vtab_in(this->c_ptr(), constraint_idx, handle); }
115
116 #endif
117
118
125 { return { this->c_ptr()->aConstraintUsage, size_t(this->c_ptr()->nConstraint)}; }
126
132 { return { this->c_ptr()->aConstraintUsage, size_t(this->c_ptr()->nConstraint)}; }
133
135 int index_number() const noexcept
136 { return this->c_ptr()->idxNum; }
137
138 void set_index_number(int val) noexcept
139 { this->c_ptr()->idxNum = val; }
140
147 T index_data() const noexcept
148 { return (T)this->c_ptr()->idxStr; }
149
161 template<class X>
162 SQLITEPP_ENABLE_IF((std::is_convertible_v<X *, T>),
163 void) set_index_data(X * data, bool allocated = false) noexcept
164 {
165 this->c_ptr()->idxStr = (char *)data;
166 this->c_ptr()->needToFreeIdxStr = allocated;
167 }
168
178 template<class X>
181 { set_index_data(data.release(), true); }
182
192 template<class X>
193 SQLITEPP_ENABLE_IF((
198 { set_index_data(data.release(), true); }
199
201 bool order_by_consumed() const noexcept
202 { return this->c_ptr()->orderByConsumed != 0; }
203
204 void set_order_by_consumed(bool val) noexcept
205 { this->c_ptr()->orderByConsumed = val; }
206
208 double estimated_cost() const noexcept
209 { return this->c_ptr()->estimatedCost; }
210
211 void set_estimated_cost(double val) noexcept
212 { this->c_ptr()->estimatedCost = val; }
213
214 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 8, 2)
215
220 int64_t estimated_rows() const noexcept
221 { return int64_t(this->c_ptr()->estimatedRows); }
222
226 void set_estimated_rows(int64_t val) noexcept
227 { this->c_ptr()->estimatedRows = sqlite3_int64(val); }
228
229 #endif
230
231 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 9, 0)
232
237 int index_flags() const noexcept
238 { return this->c_ptr()->idxFlags; }
239
244 void set_index_flags(int val) noexcept
245 { this->c_ptr()->idxFlags = val; }
246
247 #endif
248
249 };
250
252
257
275 SQLITEPP_EXPORTED
276 template<class Derived>
277 class vtab : private sqlite3_vtab
278 {
279 public:
289
299 using index_data_type = void;
300
308 class cursor : private sqlite3_vtab_cursor
309 {
310 friend vtab;
311 public:
312 cursor(cursor &) = delete;
313 cursor & operator=(cursor &) = delete;
314
316 sqlite3_vtab_cursor * c_ptr() const noexcept
317 { return const_cast<cursor *>(this); }
318
343 template<class D=Derived> //defer resolution of nested data types
345 void) filter([[maybe_unused]] int idx,
346 [[maybe_unused]] typename D::index_data_type idx_data,
347 [[maybe_unused]] int argc,
348 [[maybe_unused]] value ** argv)
349 {
350 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
351 }
352
375 template<class D=Derived> //defer resolution of nested data types
377 void) filter([[maybe_unused]] int idx,
378 [[maybe_unused]] int argc,
379 [[maybe_unused]] value ** argv)
380 {
381 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
382 }
383
394 bool eof() const noexcept
395 { return true; }
396
408 void next()
409 { throw exception(SQLITE_INTERNAL, error::message_ptr("cursor::next is not implemented")); }
410
424 void column(context & ctxt, [[maybe_unused]] int idx) const
425 { ctxt.result(nullptr); }
426
437 sqlite_int64 rowid() const
438 { throw exception(SQLITE_INTERNAL, error::message_ptr("cursor::rowid is not implemented")); }
439 protected:
443 cursor(Derived * owner):
445 {}
446 ~cursor()
447 {}
448
456 Derived * owner() const noexcept
457 { return static_cast<Derived *>(this->pVtab); }
458 };
459 public:
461 struct create_t {};
462
464 struct connect_t {};
465 public:
477 static void create_module(database & db, const string_param & name)
478 {
479 db.create_module(name, vtab::get_module());
480 }
481
499 template<class D=Derived>
501 static,
503 void) create_module(database & db,
504 const string_param & name,
505 typename D::constructor_data_type data,
506 void(*destructor)(typename D::constructor_data_type) noexcept = nullptr)
507 {
508 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
509 db.create_module(name, vtab::get_module(), data, destructor);
510 }
511
528 template<class D=Derived>
530 static,
532 void) create_module(database & db,
533 const string_param & name,
535 {
536 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
537 db.create_module(name, vtab::get_module(), data.release(), [](typename D::constructor_data_type ptr) noexcept {
538 delete ptr;
539 });
540 }
541
566 template<class D=Derived>
567 bool best_index(index_info<typename D::index_data_type> & info) const
568 {
569 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
570 info.set_estimated_cost(0);
571 return true;
572 }
573
587 template<class D=Derived>
588 std::unique_ptr<typename D::cursor> open()
589 {
590 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
591 return std::unique_ptr<typename D::cursor>(
592 new typename D::cursor(static_cast<D *>(this))
593 );
594 }
595
603 static sqlite3_module * get_module();
604
605 protected:
608 sqlite3_vtab{nullptr, 0, nullptr}
609 {}
610
611 vtab(const vtab &) = delete;
613 vtab & operator=(const vtab &) = delete;
616 {}
617
618
619 private:
620 void set_error_message(error & err) const
621 {
622 auto me = const_cast<vtab *>(this);
623 if (me->zErrMsg)
624 sqlite3_free(me->zErrMsg);
625 auto message = err.extract_message();
626 me->zErrMsg = (char *)message.release();
627 }
628
629 void set_error_message(exception & ex) const
630 { set_error_message(ex.error()); }
631
632 void set_error_message(std::exception & ex) const
633 {
634 auto me = const_cast<vtab *>(this);
635 if (me->zErrMsg)
636 {
637 sqlite3_free(me->zErrMsg);
638 me->zErrMsg = nullptr;
639 }
640 auto message = ex.what();
641 const auto len = strlen(message) + 1;
642 if (char * const ret = (char *)sqlite_allocate_nothrow(len))
643 {
644 memcpy(ret, message, len);
645 me->zErrMsg = ret;
646 }
647 }
648
649 static constexpr void check_requirements();
650
651 #define SQLITEPP_DECLARE_IMPL(xname, name) \
652 static std::remove_pointer_t<decltype(sqlite3_module::xname)> name##_impl
653 #define SQLITEPP_DECLARE_CONDITIONAL_IMPL(xname, name) \
654 SQLITEPP_DECLARE_IMPL(xname, name); \
655 static constexpr decltype(sqlite3_module::xname) get_##name##_impl()
656
657 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xCreate, create);
658 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xConnect, connect);
659 SQLITEPP_DECLARE_IMPL(xBestIndex, best_index);
660 SQLITEPP_DECLARE_IMPL(xDisconnect, disconnect);
661 SQLITEPP_DECLARE_IMPL(xDestroy, destroy);
662 SQLITEPP_DECLARE_IMPL(xOpen, open);
663 SQLITEPP_DECLARE_IMPL(xClose, close);
664 SQLITEPP_DECLARE_IMPL(xEof, eof);
665 SQLITEPP_DECLARE_IMPL(xFilter, filter);
666 SQLITEPP_DECLARE_IMPL(xNext, next);
667 SQLITEPP_DECLARE_IMPL(xColumn, column);
668 SQLITEPP_DECLARE_IMPL(xRowid, rowid);
669 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xUpdate, update);
670 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xFindFunction, find_function);
671 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xBegin, begin);
672 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xSync, sync);
673 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xCommit, commit);
674 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xRollback, rollback);
675 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xRename, rename);
676 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xSavepoint, savepoint);
677 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xRelease, release);
678 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xRollbackTo, rollback_to);
679
680 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 26, 0)
681
682 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xShadowName, shadow_name);
683
684 #endif
685
686 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 44, 0)
687
688 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xIntegrity, integrity);
689
690 #endif
691
692 #undef SQLITEPP_DECLARE_IMPL
693 #undef SQLITEPP_DECLARE_CONDITIONAL_IMPL
694
695 };
696
698
699}
700
701
702#endif
SQL Function Context Object.
Definition context_iface.hpp:38
void result(std::nullptr_t) noexcept
Return NULL from the implemented SQL function.
Definition context_iface.hpp:108
Database Connection.
Definition database_iface.hpp:109
void create_module(const string_param &name, const sqlite3_module *mod)
Register a virtual table implementation.
Definition database_iface.hpp:962
Carries information about SQLite error.
Definition exception_iface.hpp:39
std::unique_ptr< const char, free_message > message_ptr
An owning pointer to SQLite error message.
Definition exception_iface.hpp:59
message_ptr extract_message() &noexcept
Move the message out of this object.
Definition exception_iface.hpp:150
Exception used to report any SQLite errors.
Definition exception_iface.hpp:180
sqlite3_index_info * c_ptr() const noexcept
Definition handle.hpp:45
Virtual Table Indexing Information.
Definition vtab_iface.hpp:51
void set_index_data(std::unique_ptr< X > data) noexcept
Set the index data.
Definition vtab_iface.hpp:197
int64_t estimated_rows() const noexcept
Returns estimated number of rows returned.
Definition vtab_iface.hpp:220
sqlite3_index_info::sqlite3_index_constraint constraint
Alias for unwieldy C struct name.
Definition vtab_iface.hpp:56
void set_estimated_cost(double val) noexcept
Sets estimated cost of using this index.
Definition vtab_iface.hpp:211
T index_data() const noexcept
Returns data associated with the index.
Definition vtab_iface.hpp:147
bool order_by_consumed() const noexcept
Returns whether the cursor output is already ordered.
Definition vtab_iface.hpp:201
int distinct() const noexcept
Determine if the query is DISTINCT.
Definition vtab_iface.hpp:95
void set_order_by_consumed(bool val) noexcept
Sets whether the cursor output is already ordered.
Definition vtab_iface.hpp:204
const char * collation(int constraint_idx) const noexcept
Determine the collation for a constraint.
Definition vtab_iface.hpp:87
void set_index_number(int val) noexcept
Sets number used to identify the index.
Definition vtab_iface.hpp:138
span< const orderby > orderbys() const noexcept
Returns the table of ORDER BY clause constraints.
Definition vtab_iface.hpp:68
span< const constraint > constraints() const noexcept
Returns the table of WHERE clause constraints.
Definition vtab_iface.hpp:65
span< const constraint_usage > constraints_usage() const noexcept
Returns the desired usage of the constraints.
Definition vtab_iface.hpp:124
sqlite3_index_info::sqlite3_index_orderby orderby
Alias for unwieldy C struct name.
Definition vtab_iface.hpp:60
int index_flags() const noexcept
Returns mask of SQLITE_INDEX_SCAN_ flags.
Definition vtab_iface.hpp:237
uint64_t columns_used() const noexcept
Returns mask of columns used by statement.
Definition vtab_iface.hpp:77
void handle_in(int constraint_idx, bool handle) const noexcept
Set all-at-once processing of an IN operator.
Definition vtab_iface.hpp:113
void set_index_data(X *data, bool allocated=false) noexcept
Set the index data.
Definition vtab_iface.hpp:163
void set_estimated_rows(int64_t val) noexcept
Sets estimated number of rows returned.
Definition vtab_iface.hpp:226
sqlite3_index_info::sqlite3_index_constraint_usage constraint_usage
Alias for unwieldy C struct name.
Definition vtab_iface.hpp:58
double estimated_cost() const noexcept
Returns estimated cost of using this index.
Definition vtab_iface.hpp:208
span< constraint_usage > constraints_usage() noexcept
Returns the desired usage of the constraints.
Definition vtab_iface.hpp:131
bool is_in(int constraint_idx) const noexcept
Determine if a constraint is an IN that can be processed all at once.
Definition vtab_iface.hpp:105
void set_index_data(std::unique_ptr< X, sqlite_deleter< X > > data) noexcept
Set the index data.
Definition vtab_iface.hpp:180
void set_index_flags(int val) noexcept
Sets mask of SQLITE_INDEX_SCAN_ flags.
Definition vtab_iface.hpp:244
int index_number() const noexcept
Returns number used to identify the index.
Definition vtab_iface.hpp:135
Memory deleter that uses sqlite3_free.
Definition memory_iface.hpp:32
Dynamically Typed Value Object.
Definition value_iface.hpp:36
Base class for cursors.
Definition vtab_iface.hpp:309
void next()
Advances the cursor.
Definition vtab_iface.hpp:408
Derived * owner() const noexcept
Returns the owning vtab - derived class.
Definition vtab_iface.hpp:456
sqlite3_vtab_cursor * c_ptr() const noexcept
Access the underlying sqlite3_vtab_cursor struct.
Definition vtab_iface.hpp:316
cursor(Derived *owner)
Constructs an instance with a given owner.
Definition vtab_iface.hpp:443
sqlite_int64 rowid() const
Retrieves the rowid of the row cursor is currently pointing at.
Definition vtab_iface.hpp:437
bool eof() const noexcept
Whether the cursor reached the end.
Definition vtab_iface.hpp:394
void filter(int idx, int argc, value **argv)
Begins a search of a virtual table.
Definition vtab_iface.hpp:377
void filter(int idx, typename D::index_data_type idx_data, int argc, value **argv)
Begins a search of a virtual table.
Definition vtab_iface.hpp:345
void column(context &ctxt, int idx) const
Retrieves the value of the virtual table column in a row cursor is currently pointing at.
Definition vtab_iface.hpp:424
Base class for virtual table object implementations.
Definition vtab_iface.hpp:278
void index_data_type
Type of data stored in index_info and passed between best_index and filter.
Definition vtab_iface.hpp:299
SQLITEPP_ENABLE_IFP(static,(std::is_pointer_v< typename D::constructor_data_type >), void) create_module(database &db
Register a virtual table implementation with a database connection.
vtab(const vtab &)=delete
You cannot copy (or move) this class.
vtab()
This class is default constructible only by derived classes.
Definition vtab_iface.hpp:607
~vtab()
This class is destructible only by derived classes.
Definition vtab_iface.hpp:615
static void create_module(database &db, const string_param &name)
Register a virtual table implementation with a database connection.
Definition vtab_iface.hpp:477
void constructor_data_type
Type of data passed via create_module to the constructor(s).
Definition vtab_iface.hpp:288
vtab & operator=(const vtab &)=delete
You cannot assign this class.
Marker type that tells the constructor of Derived to be used to connect to an existing table.
Definition vtab_iface.hpp:464
Marker type that marks the constructor of Derived to be used to create a new table.
Definition vtab_iface.hpp:461
sqlite3_free
std::span< T > span
Alias or reimplementation of std::span.
Definition span.hpp:36
basic_string_param< char > string_param
Convenience typedef.
Definition string_param.hpp:58
T is_base_of_v
T is_convertible_v
T is_trivially_destructible_v
T is_pointer_v
T is_same_v
T is_void_v
T memcpy(T... args)
ThinSQLite++ namespace.
Definition backup_iface.hpp:17
T release(T... args)
T strlen(T... args)
sqlite3_vtab_collation
sqlite3_vtab_distinct
sqlite3_vtab_in
T what(T... args)