ThinSQLite++
A thin, safe and convenient modern C++ wrapper for 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/main/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
48 template<class T = void>
49 class index_info : public handle<sqlite3_index_info, index_info<T>>
50 {
52 "template argument must be void or a pointer to a trivially destructible type");
53 public:
60 public:
61 ~index_info() = delete;
62
65 { return { this->c_ptr()->aConstraint, size_t(this->c_ptr()->nConstraint)}; };
68 { return { this->c_ptr()->aOrderBy, size_t(this->c_ptr()->nOrderBy)}; };
69
70 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 10, 0)
71
76 uint64_t columns_used() const noexcept
77 { return uint64_t(this->c_ptr()->colUsed); }
78
79 #endif
80
86 const char * collation(int constraint_idx) const noexcept
87 { return sqlite3_vtab_collation(this->c_ptr(), constraint_idx); }
88
94 int distinct() const noexcept
95 { return sqlite3_vtab_distinct(this->c_ptr()); }
96
97 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 38, 0)
98
104 bool is_in(int constraint_idx) const noexcept
105 { return sqlite3_vtab_in(this->c_ptr(), constraint_idx, -1); }
106
112 void handle_in(int constraint_idx, bool handle) const noexcept
113 { sqlite3_vtab_in(this->c_ptr(), constraint_idx, handle); }
114
115 #endif
116
117
124 { return { this->c_ptr()->aConstraintUsage, size_t(this->c_ptr()->nConstraint)}; }
131 { return { this->c_ptr()->aConstraintUsage, size_t(this->c_ptr()->nConstraint)}; }
132
134 int index_number() const noexcept
135 { return this->c_ptr()->idxNum; }
137 void set_index_number(int val) noexcept
138 { this->c_ptr()->idxNum = val; }
139
146 T index_data() const noexcept
147 { return (T)this->c_ptr()->idxStr; }
148
160 template<class X>
161 SQLITEPP_ENABLE_IF((std::is_convertible_v<X *, T>),
162 void) set_index_data(X * data, bool allocated = false) noexcept
163 {
164 this->c_ptr()->idxStr = (char *)data;
165 this->c_ptr()->needToFreeIdxStr = allocated;
166 }
167
177 template<class X>
180 { set_index_data(data.release(), true); }
181
191 template<class X>
192 SQLITEPP_ENABLE_IF((
197 { set_index_data(data.release(), true); }
198
200 bool order_by_consumed() const noexcept
201 { return this->c_ptr()->orderByConsumed != 0; }
203 void set_order_by_consumed(bool val) noexcept
204 { this->c_ptr()->orderByConsumed = val; }
205
207 double estimated_cost() const noexcept
208 { return this->c_ptr()->estimatedCost; }
210 void set_estimated_cost(double val) noexcept
211 { this->c_ptr()->estimatedCost = val; }
212
213 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 8, 2)
214
219 int64_t estimated_rows() const noexcept
220 { return int64_t(this->c_ptr()->estimatedRows); }
225 void set_estimated_rows(int64_t val) noexcept
226 { this->c_ptr()->estimatedRows = sqlite3_int64(val); }
227
228 #endif
229
230 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 9, 0)
231
236 int index_flags() const noexcept
237 { return this->c_ptr()->idxFlags; }
238
243 void set_index_flags(int val) noexcept
244 { this->c_ptr()->idxFlags = val; }
245
246 #endif
247
248 };
249
274 template<class Derived>
275 class vtab : private sqlite3_vtab
276 {
277 public:
287
297 using index_data_type = void;
298
307 {
308 friend vtab;
309 public:
310 cursor(cursor &) = delete;
311 cursor & operator=(cursor &) = delete;
312
314 sqlite3_vtab_cursor * c_ptr() const noexcept
315 { return const_cast<cursor *>(this); }
316
341 template<class D=Derived> //defer resolution of nested data types
343 void) filter([[maybe_unused]] int idx,
344 [[maybe_unused]] typename D::index_data_type idx_data,
345 [[maybe_unused]] int argc,
346 [[maybe_unused]] value ** argv)
347 {
348 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
349 }
350
373 template<class D=Derived> //defer resolution of nested data types
375 void) filter([[maybe_unused]] int idx,
376 [[maybe_unused]] int argc,
377 [[maybe_unused]] value ** argv)
378 {
379 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
380 }
381
392 bool eof() const noexcept
393 { return true; }
394
406 void next()
407 { throw exception(SQLITE_INTERNAL, error::message_ptr("cursor::next is not implemented")); }
408
422 void column(context & ctxt, [[maybe_unused]] int idx) const
423 { ctxt.result(nullptr); }
424
435 sqlite_int64 rowid() const
436 { throw exception(SQLITE_INTERNAL, error::message_ptr("cursor::rowid is not implemented")); }
437 protected:
441 cursor(Derived * owner):
443 {}
444 ~cursor()
445 {}
446
454 Derived * owner() const noexcept
455 { return static_cast<Derived *>(this->pVtab); }
456 };
457 public:
459 struct create_t {};
460
462 struct connect_t {};
463 public:
475 static void create_module(database & db, const string_param & name)
476 {
478 }
479
497 template<class D=Derived>
498 static
501 const string_param & name,
502 typename D::constructor_data_type data,
503 void(*destructor)(typename D::constructor_data_type) = nullptr)
504 {
505 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
506 db.create_module(name, vtab::get_module(), data, destructor);
507 }
508
525 template<class D=Derived>
526 static
529 const string_param & name,
531 {
532 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
533 db.create_module(name, vtab::get_module(), data.release(), [](typename D::constructor_data_type ptr) {
534 delete ptr;
535 });
536 }
537
562 template<class D=Derived>
564 {
565 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
566 info.set_estimated_cost(0);
567 return true;
568 }
569
583 template<class D=Derived>
585 {
586 static_assert(std::is_same_v<D, Derived>, "please invoke this function only with default template parameter");
588 new typename D::cursor(static_cast<D *>(this))
589 );
590 }
591
600
601 protected:
604 sqlite3_vtab{nullptr, 0, nullptr}
605 {}
607 vtab(const vtab &) = delete;
609 vtab & operator=(const vtab &) = delete;
612 {}
613
614
615 private:
616 void set_error_message(error & err) const
617 {
618 auto me = const_cast<vtab *>(this);
619 if (me->zErrMsg)
620 sqlite3_free(me->zErrMsg);
621 auto message = err.extract_message();
622 me->zErrMsg = (char *)message.release();
623 }
624
625 void set_error_message(exception & ex) const
626 { set_error_message(ex.error()); }
627
628 void set_error_message(std::exception & ex) const
629 {
630 auto me = const_cast<vtab *>(this);
631 if (me->zErrMsg)
632 {
633 sqlite3_free(me->zErrMsg);
634 me->zErrMsg = nullptr;
635 }
636 auto message = ex.what();
637 const auto len = strlen(message) + 1;
638 if (char * const ret = (char *)sqlite_allocate_nothrow(len))
639 {
640 memcpy(ret, message, len);
641 me->zErrMsg = ret;
642 }
643 }
644
645 static constexpr void check_requirements();
646
647 #define SQLITEPP_DECLARE_IMPL(xname, name) \
648 static std::remove_pointer_t<decltype(sqlite3_module::xname)> name##_impl
649 #define SQLITEPP_DECLARE_CONDITIONAL_IMPL(xname, name) \
650 SQLITEPP_DECLARE_IMPL(xname, name); \
651 static constexpr decltype(sqlite3_module::xname) get_##name##_impl()
652
653 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xCreate, create);
654 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xConnect, connect);
655 SQLITEPP_DECLARE_IMPL(xBestIndex, best_index);
656 SQLITEPP_DECLARE_IMPL(xDisconnect, disconnect);
657 SQLITEPP_DECLARE_IMPL(xDestroy, destroy);
658 SQLITEPP_DECLARE_IMPL(xOpen, open);
659 SQLITEPP_DECLARE_IMPL(xClose, close);
660 SQLITEPP_DECLARE_IMPL(xEof, eof);
661 SQLITEPP_DECLARE_IMPL(xFilter, filter);
662 SQLITEPP_DECLARE_IMPL(xNext, next);
663 SQLITEPP_DECLARE_IMPL(xColumn, column);
664 SQLITEPP_DECLARE_IMPL(xRowid, rowid);
665 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xUpdate, update);
666 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xFindFunction, find_function);
667 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xBegin, begin);
668 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xSync, sync);
669 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xCommit, commit);
670 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xRollback, rollback);
671 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xRename, rename);
672 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xSavepoint, savepoint);
673 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xRelease, release);
674 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xRollbackTo, rollback_to);
675
676 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 26, 0)
677
678 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xShadowName, shadow_name);
679
680 #endif
681
682 #if SQLITE_VERSION_NUMBER >= SQLITEPP_SQLITE_VERSION(3, 44, 0)
683
684 SQLITEPP_DECLARE_CONDITIONAL_IMPL(xIntegrity, integrity);
685
686 #endif
687
688 #undef SQLITEPP_DECLARE_IMPL
689 #undef SQLITEPP_DECLARE_CONDITIONAL_IMPL
690
691 };
692
695}
696
697
698#endif
A reference to a null terminated string.
Definition string_param.hpp:37
SQL Function Context Object.
Definition context_iface.hpp:37
void result(std::nullptr_t) noexcept
Return NULL from the implemented SQL function.
Definition context_iface.hpp:104
Database Connection.
Definition database_iface.hpp:108
void create_module(const string_param &name, const sqlite3_module *mod)
Register a virtual table implementation.
Definition database_iface.hpp:891
Carries information about SQLite error.
Definition exception_iface.hpp:38
message_ptr extract_message() &noexcept
Move the message out of this object.
Definition exception_iface.hpp:140
Exception used to report any SQLite errors.
Definition exception_iface.hpp:166
Base functionality for all fake wrapper classes
Definition handle.hpp:27
sqlite3_index_info * c_ptr() const noexcept
Definition handle.hpp:45
Virtual Table Indexing Information.
Definition vtab_iface.hpp:50
void set_index_data(std::unique_ptr< X > data) noexcept
Set the index data.
Definition vtab_iface.hpp:196
int64_t estimated_rows() const noexcept
Returns estimated number of rows returned.
Definition vtab_iface.hpp:219
void set_estimated_cost(double val) noexcept
Sets estimated cost of using this index.
Definition vtab_iface.hpp:210
T index_data() const noexcept
Returns data associated with the index.
Definition vtab_iface.hpp:146
bool order_by_consumed() const noexcept
Returns whether the cursor output is already ordered.
Definition vtab_iface.hpp:200
int distinct() const noexcept
Determine if the query is DISTINCT.
Definition vtab_iface.hpp:94
void set_order_by_consumed(bool val) noexcept
Sets whether the cursor output is already ordered.
Definition vtab_iface.hpp:203
const char * collation(int constraint_idx) const noexcept
Determine the collation for a constraint.
Definition vtab_iface.hpp:86
void set_index_number(int val) noexcept
Sets number used to identify the index.
Definition vtab_iface.hpp:137
span< const orderby > orderbys() const noexcept
Returns the table of ORDER BY clause constraints.
Definition vtab_iface.hpp:67
span< const constraint > constraints() const noexcept
Returns the table of WHERE clause constraints.
Definition vtab_iface.hpp:64
span< const constraint_usage > constraints_usage() const noexcept
Returns the desired usage of the constraints.
Definition vtab_iface.hpp:123
int index_flags() const noexcept
Returns mask of SQLITE_INDEX_SCAN_ flags.
Definition vtab_iface.hpp:236
uint64_t columns_used() const noexcept
Returns mask of columns used by statement.
Definition vtab_iface.hpp:76
void handle_in(int constraint_idx, bool handle) const noexcept
Set all-at-once processing of an IN operator.
Definition vtab_iface.hpp:112
void set_index_data(X *data, bool allocated=false) noexcept
Set the index data.
Definition vtab_iface.hpp:162
void set_estimated_rows(int64_t val) noexcept
Sets estimated number of rows returned.
Definition vtab_iface.hpp:225
double estimated_cost() const noexcept
Returns estimated cost of using this index.
Definition vtab_iface.hpp:207
span< constraint_usage > constraints_usage() noexcept
Returns the desired usage of the constraints.
Definition vtab_iface.hpp:130
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:104
void set_index_data(std::unique_ptr< X, sqlite_deleter< X > > data) noexcept
Set the index data.
Definition vtab_iface.hpp:179
void set_index_flags(int val) noexcept
Sets mask of SQLITE_INDEX_SCAN_ flags.
Definition vtab_iface.hpp:243
int index_number() const noexcept
Returns number used to identify the index.
Definition vtab_iface.hpp:134
Memory deleter that uses sqlite3_free.
Definition memory_iface.hpp:31
Dynamically Typed Value Object.
Definition value_iface.hpp:35
Base class for cursors.
Definition vtab_iface.hpp:307
void next()
Advances the cursor.
Definition vtab_iface.hpp:406
Derived * owner() const noexcept
Returns the owning vtab - derived class.
Definition vtab_iface.hpp:454
sqlite3_vtab_cursor * c_ptr() const noexcept
Access the underlying sqlite3_vtab_cursor struct.
Definition vtab_iface.hpp:314
cursor(Derived *owner)
Constructs an instance with a given owner.
Definition vtab_iface.hpp:441
sqlite_int64 rowid() const
Retrieves the rowid of the row cursor is currently pointing at.
Definition vtab_iface.hpp:435
bool eof() const noexcept
Whether the cursor reached the end.
Definition vtab_iface.hpp:392
void filter(int idx, int argc, value **argv)
Begins a search of a virtual table.
Definition vtab_iface.hpp:375
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:343
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:422
Base class for virtual table object implementations.
Definition vtab_iface.hpp:276
static void create_module(database &db, const string_param &name, std::unique_ptr< std::remove_pointer_t< typename D::constructor_data_type > > data)
Register a virtual table implementation with a database connection.
Definition vtab_iface.hpp:528
void index_data_type
Type of data stored in index_info and passed between best_index and cursor::filter.
Definition vtab_iface.hpp:297
static sqlite3_module * get_module()
Obtains the singleton sqlite3_module for this virtual table.
bool best_index(index_info< typename D::index_data_type > &info) const
Determines the best way to access the virtual table.
Definition vtab_iface.hpp:563
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:603
~vtab()
This class is destructible only by derived classes.
Definition vtab_iface.hpp:611
static void create_module(database &db, const string_param &name)
Register a virtual table implementation with a database connection.
Definition vtab_iface.hpp:475
static void create_module(database &db, const string_param &name, typename D::constructor_data_type data, void(*destructor)(typename D::constructor_data_type)=nullptr)
Register a virtual table implementation with a database connection.
Definition vtab_iface.hpp:500
std::unique_ptr< typename D::cursor > open()
Creates a new cursor used for accessing the virtual table.
Definition vtab_iface.hpp:584
void constructor_data_type
Type of data passed via create_module to the constructor(s)
Definition vtab_iface.hpp:286
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:462
Marker type that marks the constructor of Derived to be used to create a new table.
Definition vtab_iface.hpp:459
sqlite3_free
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)