diff options
Diffstat (limited to 'doc')
31 files changed, 0 insertions, 2444 deletions
diff --git a/doc/Jamfile b/doc/Jamfile deleted file mode 100644 index 9a9f9d3..0000000 --- a/doc/Jamfile +++ /dev/null @@ -1,18 +0,0 @@ -import asciidoctor ; - -html index.html : index.adoc ; - -install html_ : index.html : <location>html ; - - -pdf sqlite.pdf : index.adoc ; -explicit sqlite.pdf ; - -install pdf_ : sqlite.pdf : <location>pdf ; -explicit pdf_ ; - -alias boostdoc ; -explicit boostdoc ; -alias boostrelease : html_ ; -explicit boostrelease ; - diff --git a/doc/extensions.adoc b/doc/extensions.adoc deleted file mode 100644 index 528fb39..0000000 --- a/doc/extensions.adoc +++ /dev/null @@ -1,41 +0,0 @@ -= Extension Modules - -This library can also be used to https://www.sqlite.org/loadext.html::[run-time loadable extensions] -that can be used by other applications, e.g. the `sqlite3` CLI. - -In order to write this, you'll need to include `boost/sqlite/extension.hpp`, -and write a named module like so: - -[source,cpp] ----- -BOOST_SQLITE_EXTENSION(testlibrary, conn) -{ - // create a function that can be used in the plugin - create_scalar_function( - conn, "assert", - [](boost::sqlite::context<>, boost::span<boost::sqlite::value, 1u> sp) - { - if (sp.front().get_int() == 0) - throw std::logic_error("assertion failed"); - }); -} ----- - -[source,sqlite] ----- -SELECT load_extension('./test_library'); - -select assert((3 * 4) = 12); ----- - -In order to build this, you'll to link against `Boost::sqlite_ext` -instead of `Boost::sqlite`. - -Including the `extension.hpp` header will also define -`BOOST_SQLITE_COMPILE_EXTENSION`, which will include `sqlite3ext.h` -instead of `sqlite3.h` and create an inline namespace `ext` inside -`boost::sqlite`. - -This prevents linker issues, but will not allow you to mix extension -and non-extension code in one translation unit. - diff --git a/doc/functions.adoc b/doc/functions.adoc deleted file mode 100644 index 9b58b62..0000000 --- a/doc/functions.adoc +++ /dev/null @@ -1,88 +0,0 @@ -= Adding functions - -== Scalar Functions - -Scalar functions are data transformers. - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=to_upper] ----- -<1> The context is optional, and can be used to share between invocations, within the same query or to set errors/return values. -<2> Let this function take 1 parameter. If this is `span::extent` it will be any size. Functions can be overloaded by the number of parameters. -<3> Any exception will be turned into an sqlite-error code. -<4> The function is determistic, i.e. it has no side effects (see https://www.sqlite.org/c3ref/c_deterministic.html[Function Flags]) - -The return type `T` of the function gets transformed into an sqlite value by using a `tag_invoke` overload. -This interface is public and meant to be extended. - -[source,cpp] ----- -void tag_invoke(set_result_tag, sqlite3_context * ctx, T); ----- - -The builtin types are: - -- `blob` -- `zero_blob` -- `double` -- `std::int64_t` -- `nullptr` -- `string_view` -- `std::string` -- `sqlite::value` -- `variant2::monostate` -- `error` -- `std::unique_ptr<T>` (see the https://www.sqlite.org/bindptr.html[pointer passing interface]) -- `variant2::variant<Ts...>` if all `Ts` are supported -- `result<T>` -- `boost::json::value` //when including boost/sqlite/json.hpp - -The translation of the exceptions happens as follows: - -[cols="1,1"] -|=== -| Type | Sqlite error code - -| `boost::system::system_error` | `.code()` -| `std::bad_alloc` | SQLITE_NOMEM -| `std::length_error` | SQLITE_TOOBIG -| `std::out_of_range` | SQLITE_RANGE -| `std::logic_error` | SQLITE_MISUSE -| `...` | SQLITE_ERROR - -|=== - -NOTE: You can also return an <<`result`,sqlite::result>> type instead of throwing exceptions. - -== A ggregate functions - -An aggregate function builds a value from multiple values of the same column, e.g: - -[source,sqlite] ----- -select avg(age) from users ; ----- - -`avg` is a built-in function, but -Below is a toy example. We count how many retirees are among the users, based on a retirement age. - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=oldest] ----- - -The `retirees` object will be constructed for every query it's used in, and the parameters passed witht he `make_tuple` -will be passed to the constructor. -The `step` will be called for every value and `final` at the end when the query has ended and a value is required. - -The value types & exceptions are the same as for the scalar function. - -== Window functions - -Window functions look similar to aggregate functions, they only need an `inverse` function, that shares the signature with `step`. - -It is recommended to consult the https://www.sqlite.org/windowfunctions.html[sqlite window function documentation]. - -NOTE: Window functions are only available for sqlite 3.25.0 and higher. - diff --git a/doc/index.adoc b/doc/index.adoc deleted file mode 100644 index 1ec5ec7..0000000 --- a/doc/index.adoc +++ /dev/null @@ -1,28 +0,0 @@ -= Documentation boost.sqlite -Klemens Morgenstern <klemens.morgenstern@gmx.net> -Version 1.0, 23.11.2024 -:source-highlighter: rouge -:toc: left -:toclevels: 4 -:icons: font -:idprefix: -:docinfo: private-footer -:source-highlighter: rouge -:source-language: c++ -:example-caption: Example -:coderay-linenums-mode: inline - -:leveloffset: +1 - -= Introduction - -This small C+\+-14 library, extending the excellent sqlite API for C++. -It sticks as close as possible to the sqlite API, but adopts thing like errors or ranges. - -It is therefore highly recommended to study the https://www.sqlite.org/docs.html[sqlite documentation]. - -include::tutorial.adoc[] -include::functions.adoc[] -include::extensions.adoc[] -include::vtable.adoc[] -include::reference.adoc[] diff --git a/doc/reference.adoc b/doc/reference.adoc deleted file mode 100644 index 17de91c..0000000 --- a/doc/reference.adoc +++ /dev/null @@ -1,28 +0,0 @@ -= Reference - -include::reference/allocator.adoc[] -include::reference/backup.adoc[] -include::reference/blob.adoc[] -include::reference/collation.adoc[] -include::reference/connection.adoc[] -include::reference/cstring_ref.adoc[] -include::reference/error.adoc[] -include::reference/extension.adoc[] -include::reference/field.adoc[] -include::reference/function.adoc[] -include::reference/hooks.adoc[] -include::reference/json.adoc[] -include::reference/memory.adoc[] -include::reference/meta_data.adoc[] -include::reference/mutex.adoc[] -include::reference/result.adoc[] -include::reference/resultset.adoc[] -include::reference/row.adoc[] -include::reference/statement.adoc[] -include::reference/static_resultset.adoc[] -include::reference/string.adoc[] -include::reference/transaction.adoc[] -include::reference/value.adoc[] -include::reference/vtable.adoc[] - - diff --git a/doc/reference/allocator.adoc b/doc/reference/allocator.adoc deleted file mode 100644 index ab9a4e9..0000000 --- a/doc/reference/allocator.adoc +++ /dev/null @@ -1,31 +0,0 @@ -== `sqlite/allocator.hpp` -[#allocator] - -The sqlite allocator wraps sqlite's malloc & free functions in a similar way that std::allocator wraps `new`/`delete`. - -This can be used for sqlite-related code (e.g. vtables or custom functions) that should use memory from the sqlite3 pool. - -[source,cpp,subs=+quotes] ----- -template<typename T> -struct allocator -{ - constexpr allocator() noexcept {} - constexpr allocator( const allocator& other ) noexcept {} - template< class U > - constexpr allocator( const allocator<U>& other ) noexcept {} - - constexpr static std::size_t alignment = __implementation_defined__; - - - static_assert(alignof(T) <= alignment, "T alignment can't be fulfilled by sqlite"); - - [[nodiscard]] T* allocate( std::size_t n ); // <1> - void deallocate( T* p, std::size_t); // <2> -}; ----- -<1> Invokes `sqlite3_malloc64` and throws `std::bad_alloc` if it fails. -<2> Invokes `sqlite3_free` - -NOTE: Sqlite provides extensive https://www.sqlite.org/malloc.html[customizability for its dynamic memory allocation]. - diff --git a/doc/reference/backup.adoc b/doc/reference/backup.adoc deleted file mode 100644 index bc74619..0000000 --- a/doc/reference/backup.adoc +++ /dev/null @@ -1,43 +0,0 @@ -== `sqlite/backup.hpp` -[#backup] - -Backup is a small wrapper function to create a backup of one database into another. -This can be useful to write an in memory database to disk et vice versa. - -[source,cpp] ----- -void -backup(connection & source, - connection & target, - cstring_ref source_name = "main", - cstring_ref target_name = "main"); - -void -backup(connection & source, - connection & target, - cstring_ref source_name, - cstring_ref target_name, - system::error_code & ec, - error_info & ei); ----- - - -source:: The source database to backup - -target:: The target of the backup - -source_name:: The source database to read the backup from. Default is 'main'. -target_name:: The target database to write the backup to. Default is 'main'. - - -.Example -[source,cpp] ----- -sqlite::connection conn{sqlite::in_memory}; -{ - sqlite::connection read{"./read_only_db.db", SQLITE_READONLY}; - // read peristed data into memory. - backup(read, target); -} ----- - diff --git a/doc/reference/blob.adoc b/doc/reference/blob.adoc deleted file mode 100644 index 8f73105..0000000 --- a/doc/reference/blob.adoc +++ /dev/null @@ -1,141 +0,0 @@ -== `sqlite/blob.hpp` - -=== `blob_view` - -A `blob_view` is a view type referring to https://www.sqlite.org/datatype3.html[Binary Large OBject], -i.e. a non-owning type. - -.Definition -[source,cpp] ----- -//A view to a binary large object -struct blob_view -{ - // The data in the blob - const void * data() const; - // The size of the data in the blob, in bytes - std::size_t size() const - // Construct a blob from existing data - blob_view(const void * data, std::size_t size); - - // Construct an empty blob - blob_view() = default; - // Construct a blob from some other blob-like structure (data() is a pointer & size() returns size_t) - template<typename T> - explicit blob_view(const T & value); - - // Create a blob from the - blob_view(const struct blob & b); -}; ----- - -The `blob_view` can be used to access binary data from the database without copying. - -=== `zero_blob` - -The `zero_blob` is a special type that denotes blobs full of zeros without requiring any allocations. -It can be used as a result from a <<function>> or as a parameter for a <<statement>>. - -.Definition -[source,cpp] ----- -enum class zero_blob : sqlite3_uint64 {}; ----- - -.Example -[source,cpp] ----- -extern sqlite::connection conn; -conn.prepare("INSERT INTO example(bdata) VALUES(?)") - .execute(sqlite::zero_blob(1024)); // <1> ----- -<1> Insert a blob of zeros with the size 1024 - -=== `blob` - -The `blob` object owns a binary large object. - -[source,cpp] ----- -// @brief An object that owns a binary large object. @ingroup reference -struct blob -{ - // The data in the blob - void * data() const; - // The size of the data int he blob, in bytes - std::size_t size() const; - - // Create a blob from a blob_view - explicit blob(blob_view bv); - // Create an empty blob with size `n`. - explicit blob(std::size_t n); - - // Construct an empty blob - constexpr blob() = default; - // Release & take ownership of the blob. - void * release() && -}; ----- - - -=== `blob_handle` - -A `blob_handle` is readable & writable handle to a `blob` in the database. -It allows incremental reading/writing of the raw data. - -[source,cpp] ----- -// Open a blob -blob_handle open_blob(connection & conn, - cstring_ref db, - cstring_ref table, - cstring_ref column, - sqlite3_int64 row, - bool read_only, - system::error_code &ec, - error_info &ei); -blob_handle open_blob(connection & conn, - cstring_ref db, - cstring_ref table, - cstring_ref column, - sqlite3_int64 row, - bool read_only = false); - -// An object that holds a binary large object. Can be obtained by using @ref blob_handle. @ingroup reference -struct blob_handle -{ - // Default constructor - blob_handle() = default; - - // Construct from a handle. This takesowner ship of the `sqlite3_blob` handle. - explicit blob_handle(sqlite3_blob * blob); - - // Reopen the blob on another row (i.e. the same column of the same table) - void reopen(sqlite3_int64 row_id); - void reopen(sqlite3_int64 row_id, system::error_code & ec); - - // Read data from the blob - void read_at(void *data, int len, int offset); - void read_at(void *data, int len, int offset, system::error_code &ec); - - // Write data to the blob - void write_at(const void *data, int len, int offset); - void write_at(const void *data, int len, int offset, system::error_code &ec); - - // The size of the blob - std::size_t size() const; - - // The handle of the blob - using handle_type = sqlite3_blob*; - // Returns the handle of the blob - handle_type handle(); - // Release the owned handle. - handle_type release() &&; -}; ----- - - - - - - diff --git a/doc/reference/collation.adoc b/doc/reference/collation.adoc deleted file mode 100644 index 6578f59..0000000 --- a/doc/reference/collation.adoc +++ /dev/null @@ -1,45 +0,0 @@ -== `sqlite/collation.hpp` -[#collation] - -A https://www.sqlite.org/datatype3.html#collation[collation] is a comparison operator between two string-like values, -that allows ordering with a custom algorithm. - -.Definition -[source,cpp] ----- - -// Create a collation -template<typename Func> -void create_collation(connection & conn, cstring_ref name, Func && func); -template<typename Func> -void create_collation(connection & conn, cstring_ref name, Func && func, system::error_code &ec); - -// Delete an existing collation. -void delete_collation(connection & conn, cstring_ref name, system::error_code & ec); -void delete_collation(connection & conn, cstring_ref name); ----- - - conn:: A connection to the database in which to install the collation. - name:: The name of the collation. - func:: The function - -The function must be callable with two `string_view` and return an int, indicating the comparison results. - -.Example -[source,cpp] ----- -// a case insensitive string omparison, e.g. from boost.urls -int ci_compare(string_view s0, string_view s1) noexcept; - -extern sqlite::connection conn; - -// Register the collation -sqlite::create_collation(conn, "iequal", &ci_compare); - -// use the collation to get by name, case insensitively -conn.query("select first_name, last_name from people where first_name = 'Klemens' collate iequal;"); - -// order by names case insensitively -conn.query("select * from people order by last_name collate iequal asc;"); ----- - diff --git a/doc/reference/connection.adoc b/doc/reference/connection.adoc deleted file mode 100644 index 6d62c10..0000000 --- a/doc/reference/connection.adoc +++ /dev/null @@ -1,100 +0,0 @@ -== `sqlite/connection.hpp` -[#connection] - -The `connection` object is the main object to access a database. - -.Definition -[source,cpp] ----- -// Utility constant for in-memory databases -constexpr static cstring_ref in_memory = ":memory:"; - -struct connection -{ - // The handle of the connection - using handle_type = sqlite3*; - // Returns the handle - handle_type handle() const; - // Release the owned handle. - handle_type release() &&; - - //Default constructor - connection() = default; - // Construct the connection from a handle. - explicit connection(handle_type handle, bool take_ownership = true); // <1> - // Move constructor. - connection(connection && ) = default; - // Move assign operator. - connection& operator=(connection && ) = default; - - // Construct a connection and connect it to `filename`. `flags` is set by `SQLITE_OPEN_*` flags. - connection(cstring_ref filename, - int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); // <2> - template<typename Path> - explicit connection(const Path & pth); - - - // Connect the database to `filename`. `flags` is set by `SQLITE_OPEN_*` flags. - void connect(cstring_ref filename, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); // <2> - void connect(cstring_ref filename, int flags, system::error_code & ec); - - template<typename Path> - void connect(const Path & pth, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE); - template<typename Path> - void connect(const Path & pth, int flags, system::error_code & ec); - - // Close the database connection. - void close(); - void close(system::error_code & ec, error_info & ei); - - // Check if the database holds a valid handle. - bool valid() const; - - // Perform a query without parameters. Can only execute a single statement. - resultset query( - core::string_view q, - system::error_code & ec, - error_info & ei); - resultset query(core::string_view q); - - template<typename T, bool Strict = false> - static_resultset<T, Strict> query(core::string_view q, system::error_code & ec, error_info & ei); - template<typename T, bool Strict = false> - static_resultset<T, Strict> query(core::string_view q); - - // Perform a query without parametert, It execute a multiple statement. - void execute(cstring_ref q, system::error_code & ec, error_info & ei); - void execute(cstring_ref q); - - - // Preparse a a statement. - statement prepare( - core::string_view q, - system::error_code & ec, - error_info & ei); - statement prepare(core::string_view q); - - - // Check if the database has the table - bool has_table( - cstring_ref table, - cstring_ref db_name = "main") const; - - // Check if the database has the table - bool has_column( - cstring_ref table, - cstring_ref column, - cstring_ref db_name = "main") const; -}; - ----- -<1> The `take_ownership` is usually only false when used from <<extension_modules, extension modules>>. -<2> See https://www.sqlite.org/c3ref/c_open_autoproxy.html[the sqlite documentation for the available flags]. - -.Example -[source,cpp] ----- -sqlite::connection conn; -conn.connect("./my-database.db"); -conn.prepare("insert into log (text) values ($1)").execute(std::make_tuple("booting up")); -----
\ No newline at end of file diff --git a/doc/reference/cstring_ref.adoc b/doc/reference/cstring_ref.adoc deleted file mode 100644 index 402663d..0000000 --- a/doc/reference/cstring_ref.adoc +++ /dev/null @@ -1,16 +0,0 @@ -== `sqlite/cstring_ref.hpp` - -[#string_view] - -The `sqlite::string_view` class is a https://en.cppreference.com/w/cpp/string/basic_string_view[std::string_view] -compatible class. - -[#cstring_ref] - -The `cstring_ref` class is a view type similar to a `string_view`, but with a guarantee that it is null-terminated. - -It can be constructed from a raw `const char *` or any class that has a `c_str()` function returning a `const char *`. - -Otherwise it is similar to a `string_view`, except that `substr(std::size_t())` will return a `cstring_ref`, -whereas a `substr(std::size_t(), std::size_t())` returns a `string_view`. - diff --git a/doc/reference/error.adoc b/doc/reference/error.adoc deleted file mode 100644 index 424c7dd..0000000 --- a/doc/reference/error.adoc +++ /dev/null @@ -1,91 +0,0 @@ -== `sqlite/error.hpp` - -=== `sqlite_category` - -The sqlite_category is a `boost::system::error_category` to be used with sqlite errors. - -=== `error_info` - -The `error_info` class hold additional information about error conditions stored in an sqlite-allocate string. - -Contains an error message describing what happened. Not all error conditions are able to generate this extended information - those that -can't will have an empty error message. - -The `error_info` allocates memory from the sqlite pool and holds it. - -[source,cpp] ----- -struct error_info -{ - // Default constructor. - error_info() = default; - - // Initialization constructor. Copies the message into a newly create buffer. - error_info(core::string_view msg) noexcept; - // set the message by copy - void set_message(core::string_view msg); - - // Reset the buffer. If `c` is not null, its ownership is transferred into the error_info object. - void reset(char * c = nullptr); - - // Format a message into a newly allocated buffer. - cstring_ref format(cstring_ref fmt, ...); - // Format a message into the existing buffer. - cstring_ref snformat(cstring_ref fmt, ...); - /// reserve data in the buffer i.e. allocate - void reserve(std::size_t sz); - - // Get the allocated memory - std::size_t capacity() const; - - // Gets the error message. - cstring_ref message() const noexcept; - - // Release the underlying memory. It must be freed using `sqlite_free` later. - char * release(); - // Restores the message to its initial state. Does not release memory. - void clear() noexcept; - -}; ----- - -=== `error` - -The `error` class holds `error_info` and a `code` and can be used with https://www.boost.org/doc/libs/master/libs/system/doc/html/system.html#ref_boostsystemresult_hpp[`boost::system::result`]. - -[source,cpp] ----- -/** - * \brief An error containing both a code & optional message. - * \ingroup reference - * \details Contains an error . - */ -struct error -{ - // The code of the error. - int code; - // The additional information of the error - error_info info; - - // Create an error with code & message - error(int code, error_info info) ; - error(int code, core::string_view info); - error(system::error_code code, error_info info) // <1> - // Create an error with only a code. - explicit error(int code); - - error(system::error_code code); - // Create an empty error; - error() = default; - error(error && ) noexcept = default; -}; - -// For compatability with system::result; -void throw_exception_from_error( error const & e, boost::source_location const & loc ); - -template<typename T = void> -using result = system::result<T, error>; ----- -<1> If code.category() is not `sqlite_category`, the code will be set to `SQLITE_FAIL`. - - diff --git a/doc/reference/extension.adoc b/doc/reference/extension.adoc deleted file mode 100644 index 7ee2500..0000000 --- a/doc/reference/extension.adoc +++ /dev/null @@ -1,36 +0,0 @@ -== `sqlite/extension.hpp` - -=== `BOOST_SQLITE_EXTENSION` - - This macro can be used to create an sqlite extension. - -.Definition -[source,cpp] ----- -#define BOOST_SQLITE_EXTENSION(Name, Conn) ----- - -Name:: The name of the module. -Conn:: The parameter name of the connection. - - -NOTE: When defining BOOST_SQLITE_COMPILE_EXTENSION (was is done in extension.hpp) -sqlite will use an inline namespace to avoid symbol clashes. - -You must link against `Boost::sqlite_ext` and not `Boost::sqlite` and should not mix both in the same binary. - -.Example -[source,cpp] ----- -BOOST_SQLITE_EXTENSION(extension, conn) -{ - create_scalar_function( - conn, "assert", - [](boost::sqlite::context<>, boost::span<boost::sqlite::value, 1u> sp) - { - if (sp.front().get_int() == 0) - throw std::logic_error("assertion failed"); - }); -} ----- - diff --git a/doc/reference/field.adoc b/doc/reference/field.adoc deleted file mode 100644 index 572719d..0000000 --- a/doc/reference/field.adoc +++ /dev/null @@ -1,42 +0,0 @@ -== `sqlite/field.hpp` - -A `field` is a type representing a <<value>> in a database. or as a result from a query. - -.Definition -[source,cpp] ----- - -struct field -{ - typedef sqlite_int64 int64; - - // The type of the value - value_type type() const; - // Is the held value null - bool is_null() const; - // Is the held value is not null - explicit operator bool () const; - // Returns the value as an `int64`. - int64 get_int() const; - // Returns the value as an `double`. - double get_double() const; - // Returns the value as text, i.e. a string_view. Note that this value may be invalidated - cstring_ref get_text() const; - // Returns the value as blob, i.e. raw memory. Note that this value may be invalidated - blob_view get_blob() const; - // Returns the field as a value. - value get_value() const; - // Returns the name of the column. - cstring_ref column_name() const; - // Returns the name of the table. - cstring_ref table_name() const; - // Returns the name of the original data source. - cstring_ref column_origin_name() const; -} ----- - -NOTE: The view types can be invalidated when the database changes or the next row is read by the query. - -WARNING: The `field` type does not own the statement/query it was produced by. It is a merely a view into the `resultset`. -Reading the next row will change the values returned. - diff --git a/doc/reference/function.adoc b/doc/reference/function.adoc deleted file mode 100644 index 311aebc..0000000 --- a/doc/reference/function.adoc +++ /dev/null @@ -1,263 +0,0 @@ -== `sqlite/function.hpp` - -=== `function_flags` - -[source, cpp] ----- -enum function_flags -{ - deterministic = SQLITE_DETERMINISTIC, - directonly = SQLITE_DIRECTONLY, - subtype = SQLITE_SUBTYPE, - innocuous = SQLITE_INNOCUOUS, - result_subtype = SQLITE_RESULT_SUBTYPE, - selforder1 = SQLITE_SELFORDER1, - selforder1 = SQLITE_SELFORDER1 -}; ----- - -These function flags can be used in accordance to the -https://www.sqlite.org/c3ref/c_deterministic.html[sqlite documentation]. - -=== `context` - -A context is an object share values between invocations of a scalar function. - -.Definition -[source,cpp] ----- - -template<typename ... Args> -struct context -{ - template<std::size_t N> - using element = mp11::mp_take_c<mp11::mp_list<Args...>, N>; - - // Set the value in the context at position `Idx` - template<std::size_t Idx> - void set(element<Idx> value); - - // Returns the value in the context at position `Idx`. Throws if the value isn't set. - template<std::size_t Idx> - auto get() -> element<Idx> &; - - // Returns the value in the context at position `Idx`. Returns nullptr .value isn't set. - template<std::size_t Idx> - auto get_if() -> element<Idx> *; - - explicit context(sqlite3_context * ctx) noexcept; - - // Set the result through the context, instead of returning it. - template<typename T> - auto set_result(T && val); - - // Set the an error through the context, instead of throwing it. - void set_error(cstring_ref message, int code = SQLITE_ERROR); - - // Returns the connection of the context. - connection get_connection() const; -}; ----- - - -.Example -[source,cpp] ----- -extern sqlite::connection conn; - -sqlite::create_scalar_function( -conn, "my_sum", -[](sqlite::context<std::size_t> ctx, - boost::span<sqlite::value, 1u> args) -> std::size_t -{ - auto value = args[0].get_int(); - auto p = ctx.get_if<0>(); - if (p != nullptr) // increment the counter - return (*p) += value; - else // set the initial value - ctx.set<0>(value); - return value; -}); ----- - - -=== `create_scalar_function` - - -Creates a https://www.sqlite.org/appfunc.html[scalar function]. - -.Definition -[source,cpp] ----- - -template<typename Func> -auto create_scalar_function( - connection & conn, - cstring_ref name, - Func && func, - function_flags flags = {}); - -template<typename Func> -auto create_scalar_function( - connection & conn, - cstring_ref name, - Func && func, - function_flags flags, - system::error_code & ec, - error_info & ei); ----- - -conn:: The connection to add the function to. -name:: The name of the function -func:: The function to be added - -`func` must take `context<Args...>` as the first and a `span<value, N>` as the second value. -If `N` is not `dynamic_extent` it will be used to deduce the number of arguments for the function. - - -.Example -[source,cpp] ----- -extern sqlite::connection conn; - -sqlite::create_function( - conn, "to_upper", - [](sqlite::context<> ctx, - boost::span<sqlite::value, 1u> args) -> std::string - { - std::string res; - auto txt = val[0].get_text(); - res.resize(txt.size()); - std::transform(txt.begin(), txt.end(), res.begin(), - [](char c){return std::toupper(c);}); - return value; - }); ----- - - -=== `create_aggregate_function` - -An aggregrate function will create a new `Func` for a new `aggregate` from the args tuple and call `step` for every step. -When the aggregation is done `final` is called and the result is returned to sqlite. - -[source,cpp] ----- -template<typename Func, typename Args = std::tuple<>> -void create_aggregate_function( -connection & conn, -cstring_ref name, -Args && args= {}, -function_flags flags = {}); - -template<typename Func, typename Args = std::tuple<>> -void create_aggregate_function( -connection & conn, -cstring_ref name, -Args && args, -function_flags flags, -system::error_code & ec, -error_info & ei); ----- - - -conn:: The connection to add the function to. -name:: The name of the function - -args:: The argument tuple to construct `Func` from. -Func:: The function to be added. It needs to be an object with two functions: -[source,cpp] ----- -void step(boost::span<sqlite::value, N> args); -T final(); ----- - -.Example -[source,cpp] ----- - extern sqlite::connection conn; - -struct aggregate_func -{ - aggregate_func(std::size_t init) : counter(init) {} - std::int64_t counter; - void step(, boost::span<sqlite::value, 1u> val) - { - counter += val[0].get_text().size(); - } - - std::int64_t final() - { - return counter; - } -}; - -sqlite::create_function<aggregate_func>(conn, "char_counter", std::make_tuple(42)); ----- - - -=== `create_window_function` - -NOTE: This is only available starting with sqlite 3.25.0. - -An window function will create a new `Func` for a new `aggregate` and call `step` for every step. -When an element is removed from the window `inverse` is called. -When the aggregation is done `final` is called and the result is returned to sqlite. - -[source,cpp] ----- -template<typename Func, typename Args = std::tuple<>> -void create_window_function( - connection & conn, - cstring_ref name, - Args && args = {}, - function_flags flags = {}); - -template<typename Func, typename Args = std::tuple<>> -void create_window_function( - connection & conn, - cstring_ref name, - Args && args, - function_flags flags, - system::error_code & ec); ----- - - -conn:: The connection to add the function to. -name:: The name of the function -args:: The arguments to construct Func from. -Func:: The function to be added. It needs to be an object with three functions: -[source,cpp] ----- -void step(boost::span<sqlite::value, N> args); -void inverse(boost::span<sqlite::value, N> args); -T final(); ----- - - -.Example -[source,cpp] ----- -extern sqlite::connection conn; - -struct window_func -{ - std::int64_t counter; - void step(boost::span<sqlite::value, 1u> val) - { - counter += val[0].get_text().size(); - } - void inverse(boost::span<sqlite::value, 1u> val) - { - counter -= val[0].get_text().size(); - } - - std::int64_t final() - { - return counter; - } -}; - -sqlite::create_function(conn, "win_char_counter", aggregate_func{}); ----- - - diff --git a/doc/reference/hooks.adoc b/doc/reference/hooks.adoc deleted file mode 100644 index c74d712..0000000 --- a/doc/reference/hooks.adoc +++ /dev/null @@ -1,105 +0,0 @@ -== `sqlite/hooks.hpp` - -WARNING: This API might be subject change, if a better solution for ownership is found. - -=== `commit_hook` & `rollback_commit` - -The https://www.sqlite.org/c3ref/commit_hook.html[commit hook] -gets called before a commit gets performed. -Likewise the rollback hook gets invoked before a rollback. -If `func` returns true, the commit goes, otherwise it gets rolled back. - -NOTE: If the function is not a free function pointer, this function will *NOT* take ownership. - -NOTE: If `func` is a `nullptr` the hook gets reset. - - -[source,cpp] ----- -template<typename Func> -bool commit_hook(connection & conn, Func && func); - -template<typename Func> -bool rollback_hook(connection & conn, Func && func); ----- - -return:: `true` if a hook has been replaced. -conn:: The database connection to install the hook in -func:: The hook function. It must be callable without any parameter, return a `bool` and be `noexcept`. - - -=== `update_hook` - -The https://www.sqlite.org/c3ref/update_hook.html[update hook] -The update hook gets called when an update was performed. - - -NOTE: If the function is not a free function pointer, this function will *NOT* take ownership. - -NOTE: If `func` is a `nullptr` the hook gets reset. - - -[source,cpp] ----- -template<typename Func> -bool update_hook(connection & conn, Func && func); ----- - -return:: `true` if a hook has been replaced. -conn:: The database connection to install the hook in -func:: The signature of the function is `void(int op, core::string_view db, core::string_view table, sqlite3_int64 id)`. -`op` is either `SQLITE_INSERT`, `SQLITE_DELETE` and `SQLITE_UPDATE`. The function must be noexcept. - -=== `preupdate_hook` - -NOTE: The https://www.sqlite.org/c3ref/preupdate_blobwrite.html[preupdate hook] requires -sqlite to be required with `SQLITE_ENABLE_PREUPDATE_HOOK` true. - -This hook gets called before an update. - -[source,cpp] ----- -struct preupdate_context -{ - // Returns the old value, i.e. the value before the update. - system::result<value> old(int column) const; - // The count of colums to be updated - int count() const; - // The nesting depth of the update. - int depth() const; - // The new value to be written to column - system::result<value> new_(int column) const; - - // Query the status of blob access, e.g. when using blob_handle <1> - int blob_write() const; - - explicit preupdate_context(sqlite3 * db) noexcept; -}; - - -template<typename Func> -bool preupdate_hook(connection & conn, Func && func); ----- -<1> See https://www.sqlite.org/c3ref/preupdate_blobwrite.html[sqlite/preupdate_blobwrite] - - - -return:: `true` if a hook has been replaced. -conn:: The database connection to install the hook in -func:: The signature of the function is below: -[source,cpp] ----- - void preupdate_hook(sqlite::preupdate_context ctx, - int op, - const char * db_name, - const char * table_name, - sqlite3_int64 current_key, - sqlite3_int64 new_key); ----- - - - - - - - diff --git a/doc/reference/json.adoc b/doc/reference/json.adoc deleted file mode 100644 index 1c15f52..0000000 --- a/doc/reference/json.adoc +++ /dev/null @@ -1,28 +0,0 @@ -== `sqlite/json.hpp` - -The json header provides integration with boost/json. - -[source,cpp] ----- - -// The subtype value used by the sqlite json extension. See the [sqlite reference](https://www.sqlite.org/json1.html) -constexpr int json_subtype = static_cast<int>('J'); - -// Allow json to be used as a result from functions or vtables -void tag_invoke(const struct set_result_tag &, sqlite3_context * ctx, const json::value & value); - -// Check if the value or field is a json. -bool is_json(const value & v); -bool is_json(const field & f); - -//Convert the value or field to a json. -json::value as_json(const value & v, json::storage_ptr ptr = {}); -json::value as_json(const field & f, json::storage_ptr ptr = {}); - -// Allow conversions to boost::json::value -void tag_invoke( const json::value_from_tag &, json::value& val, const value & f); -void tag_invoke( const json::value_from_tag &, json::value& val, const field & f); -void tag_invoke( const json::value_from_tag &, json::value& val, resultset && rs); ----- - - diff --git a/doc/reference/memory.adoc b/doc/reference/memory.adoc deleted file mode 100644 index 7bf62ef..0000000 --- a/doc/reference/memory.adoc +++ /dev/null @@ -1,29 +0,0 @@ -== `sqlite/memory.hpp` - -The memory header provides C++-y access to the memory facilities of sqlite. - -[source,cpp,subs=+quotes] ----- -// A tag to allow `operator new` -struct memory_tag {}; - -// new operators <1> -void *operator new ( std::size_t size, boost::sqlite::memory_tag) noexcept; -void *operator new[]( std::size_t size, boost::sqlite::memory_tag) noexcept; -void operator delete ( void* ptr, boost::sqlite::memory_tag) noexcept; - -// A unique ptr that uses sqlite3_malloc / sqlite3_free -template<typename T> -using unique_ptr = std::unique_ptr<T, __implementation_detail__>; -template<typename T, typename ... Args> -unique_ptr<T> make_unique(Args && ... args); - -// Get the size of the allocated memory. -template<typename T> -std::size_t msize(const unique_ptr<T> & ptr); - - ---- -<1> `new (sqlite::memory_tag{}) T()` uses sqlite3_malloc - - diff --git a/doc/reference/meta_data.adoc b/doc/reference/meta_data.adoc deleted file mode 100644 index 6375108..0000000 --- a/doc/reference/meta_data.adoc +++ /dev/null @@ -1,36 +0,0 @@ -== `sqlite/meta_data.hpp` - -The meta_data header provides some meta_data for columns. - -[source,cpp,subs=+quotes] ----- -// The metadata of a column -struct column_meta_data -{ - // Data type fo the column - cstring_ref data_type; - // Name of default collation sequence - cstring_ref collation; - // true if column has a NOT NULL constraint - bool not_null; - // true if column is part of the PRIMARY KEY - bool primary_key; - // true if column is AUTOINCREMENT - bool auto_increment; -}; - -// get the meta-data of one colum - -column_meta_data table_column_meta_data(connection & conn, - cstring_ref db_name, cstring_ref table_name, cstring_ref column_name, - system::error_code & ec, error_info &ei); -column_meta_data table_column_meta_data(connection & conn, - cstring_ref table_name, cstring_ref column_name, - system::error_code & ec, error_info &ei); - -column_meta_data table_column_meta_data(connection & conn, - cstring_ref db_name, cstring_ref table_name, cstring_ref column_name); -column_meta_data table_column_meta_data(connection & conn, - cstring_ref table_name, cstring_ref column_name); ---- - diff --git a/doc/reference/mutex.adoc b/doc/reference/mutex.adoc deleted file mode 100644 index d0493d6..0000000 --- a/doc/reference/mutex.adoc +++ /dev/null @@ -1,16 +0,0 @@ -== `sqlite/mutex.hpp` - -The mutex header provides to std::mutex compatible classes using the sqlite mutex implementation. - -This will allow C++ code to use mutex code matching the configuration of sqlite. -This may include the mutex being a noop. - -[source,cpp,subs=+quotes] ----- -// similar to std::mutex -struct mutex; -// similar to std::recursive_mutexx -struct recursive_mutex; ----- - - diff --git a/doc/reference/result.adoc b/doc/reference/result.adoc deleted file mode 100644 index 0471b95..0000000 --- a/doc/reference/result.adoc +++ /dev/null @@ -1,40 +0,0 @@ -== `sqlite/result.hpp` - -The result header is used by functions and vtables to turn resulting values into -sqlite values. The `tag_invoke` interface is public and meant to extended. - -That is, implementing `tag_invoke(sqlite::set_result_tag, sqlite3_context, T);` -will enable `T` to be used as a result by sqlite. - -[source,cpp] ----- -// The tag -struct set_result_tag {}; - -// built-in result type -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, blob b); -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, zero_blob zb); -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, double dbl) { sqlite3_result_double(ctx, dbl); } -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, sqlite3_int64 value);inline void tag_invoke(set_result_tag, sqlite3_context * ctx, std::int64_t value); -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, std::nullptr_t); -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, string_view str); -template<typename String> -inline auto tag_invoke(set_result_tag, sqlite3_context * ctx, String && str); -inline void tag_invoke(set_result_tag, sqlite3_context * , variant2::monostate); -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, const value & val); -template<typename ... Args> -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, const variant2::variant<Args...> & var); - -template<typename T> -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, std::unique_ptr<T> ptr); -template<typename T> -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, std::unique_ptr<T, void(*)(T*)> ptr); -template<typename T, typename Deleter> -inline auto tag_invoke(set_result_tag, sqlite3_context * ctx, std::unique_ptr<T> ptr); -inline void tag_invoke(set_result_tag, sqlite3_context * ctx, error err); -template<typename T> -inline void tag_invoke(set_result_tag tag, sqlite3_context * ctx, result<T> res); -inline void tag_invoke(set_result_tag tag, sqlite3_context * ctx, result<void> res): ----- - - diff --git a/doc/reference/resultset.adoc b/doc/reference/resultset.adoc deleted file mode 100644 index fb793a5..0000000 --- a/doc/reference/resultset.adoc +++ /dev/null @@ -1,72 +0,0 @@ -== `sqlite/resultset.hpp` - -A resultset represents the results of a query. - -[source,cpp] ----- -// Representation of a result from a query. - -struct resultset -{ - // Returns the current row. The row is a pure view type. - row current() const &; - // Checks if the last row has been reached. - bool done() const; - - // Read the next row. Returns false if there's nothing more to read. - // Calling this will change the data of any `row` previously obtained from `current. - bool read_next(system::error_code & ec, error_info & ei); - bool read_next(); - - // The number of colums in the resultset - std::size_t column_count() const; - // Returns the name of the column idx. - string_view column_name(std::size_t idx) const; - // Returns the name of the source table for column idx. - string_view table_name(std::size_t idx) const; - // Returns the origin name of the column for column idx. - string_view column_origin_name(std::size_t idx) const; - - // The input iterator can be used to read every row in a for-loop - struct iterator - { - using value_type = value; - using difference_type = int; - using reference = value&; - using iterator_category = std::forward_iterator_tag; - - iterator() {} - - bool operator!=(iterator rhs) const; - row &operator*(); - row *operator->(); - - iterator operator++(); - iterator operator++(int); - }; - - // Return an input iterator to the currently unread row - iterator begin(); - // Sentinel iterator. - iterator end(); -}; ----- - - - - -.Example -[source,cpp] ----- -extern sqlite::connection conn; - -sqlite::resultset rs = conn.query("select * from users;"); - -do -{ - handle_row(r.current()); -} -while (rs.read_next()); // read it line by line ----- - - diff --git a/doc/reference/row.adoc b/doc/reference/row.adoc deleted file mode 100644 index d3af982..0000000 --- a/doc/reference/row.adoc +++ /dev/null @@ -1,56 +0,0 @@ -== `sqlite/row.hpp` - -This type represents one row of data from a query. Is a random-access range. - -WARNING: This type is a pure view type, and will be invalidated when the next row is read. - - - -[source,cpp] ----- - -struct row -{ - // The size of the row, i.e. number of colums - std::size_t size() const; - - // Returns the field at `idx`, @throws std::out_of_range - field at(std::size_t idx) const; - // Returns the field at `idx`. - field operator[](std::size_t idx) const; - - // Random access iterator used to iterate over the columns. - struct const_iterator - { - using difference_type = int; - using reference = field&; - using iterator_category = std::random_access_iterator_tag; - - const_iterator & operator++(); - const_iterator operator++(int); - const_iterator & operator--(); - const_iterator operator--(int); - - field operator[](int i) const; - - const_iterator operator+(int i) const; - const_iterator operator-(int i) const; - const_iterator & operator+=(int i); - const_iterator & operator-=(int i); - const field & operator*() const; - const field * operator->() const; - - bool operator==(const const_iterator& other) const; - bool operator!=(const const_iterator& other) const; - bool operator<(const const_iterator& other) const; - bool operator>(const const_iterator& other) const; - - const_iterator() = default; - }; - // Returns the begin of the column-range. - const_iterator begin() const; - - // Returns the end of the column-range. - const_iterator end() const -}; ----- diff --git a/doc/reference/statement.adoc b/doc/reference/statement.adoc deleted file mode 100644 index 6ce89e4..0000000 --- a/doc/reference/statement.adoc +++ /dev/null @@ -1,165 +0,0 @@ -== `sqlite/statement.hpp` - -=== `param_ref` - -A reference to a value to temporary bind for an execute statement. Most values are captures by reference. - -[source,cpp] ----- -struct param_ref -{ - // Default construct a parameter, gives `null`. - param_ref() = default; - // Bind null - param_ref(variant2::monostate); - // Bind null - param_ref(std::nullptr_t); - // Bind an integer. - template<typename I> - param_ref(I value); - // Bind a blob. - param_ref(blob_view blob); - // Bind a string. - param_ref(string_view text); - - template<typename StringLike> - param_ref(StringLike && text); - template<typename BlobLike> - param_ref(BlobLike && text); - - // Bind a floating point value. - param_ref(double value) : impl_(value) { } - // Bind a zero_blob value, i.e. a blob that initialized by zero. - param_ref(zero_blob zb) : impl_(zb) { } - - // Bind pointer value to the parameter. @see https://www.sqlite.org/bindptr.html - // Requires sqlite 3.20 - // Deleter must a function pointer or trivially constructible. - template<typename T, typename Deleter> - param_ref(std::unique_ptr<T, Deleter> ptr); - - - - // Apply the param_ref to a statement. - int apply(sqlite3_stmt * stmt, int c) const; - - // Construct param_ref from a variant - template<typename T> - param_ref(T && t); - ----- - - -=== `statement` - -A statement used for a prepared-statement. - - - -[source,cpp] ----- -struct statement -{ - // execute the prepared statement once. This transfers ownership to the resultset - template <typename ArgRange = std::initializer_list<param_ref>> - resultset execute(ArgRange && params, system::error_code& ec, error_info& info) &&; // <1> - template <typename ArgRange = std::initializer_list<param_ref> - resultset execute(ArgRange && params) &&; // <1> - resultset execute( - std::initializer_list<std::pair<string_view, param_ref>> params, - system::error_code& ec, - error_info& info) &&; // <2> - - resultset execute(std::initializer_list<std::pair<string_view, param_ref>> params) &&; - template<typename T, bool Strict = false, typename ArgRange = std::initializer_list<param_ref>> - static_resultset<T, Strict> execute( - ArgRange && params, - system::error_code & ec, - error_info & ei) &&; // <1> - - template<typename T, bool Strict = false, typename ArgRange = std::initializer_list<param_ref>> - static_resultset<T, Strict> execute(ArgRange && params) &&; // <1> - - template<typename T, bool Strict = false> - static_resultset<T, Strict> execute( - std::initializer_list<std::pair<string_view, param_ref>> params, - system::error_code & ec, - error_info & ei) &&; // <2> - template<typename T, bool Strict = false> - static_resultset<T, Strict> execute(std::initializer_list<std::pair<string_view, param_ref>> params) &&; // <2> - - - template <typename ArgRange = std::initializer_list<param_ref>> - resultset execute( - ArgRange && params, - system::error_code& ec, - error_info& info) &; // <1> - - - template <typename ArgRange = std::initializer_list<param_ref>> - resultset execute(ArgRange && params) &; // <1> - - - resultset execute( - std::initializer_list<std::pair<string_view, param_ref>> params, - system::error_code& ec, - error_info& info) &; // <2> - - resultset execute(std::initializer_list<std::pair<string_view, param_ref>> params) &; // <2> - - template<typename T, bool Strict = false, typename ArgRange = std::initializer_list<param_ref>> - static_resultset<T, Strict> execute( - ArgRange && params, - system::error_code & ec, - error_info & ei) &; // <1> - - template<typename T, bool Strict = false, typename ArgRange = std::initializer_list<param_ref>> - static_resultset<T, Strict> execute(ArgRange && params) &; // <1> - - template<typename T, bool Strict = false> - static_resultset<T, Strict> execute( - std::initializer_list<std::pair<string_view, param_ref>> params, - system::error_code & ec, - error_info & ei) &; // <2> - template<typename T, bool Strict = false> - static_resultset<T, Strict> execute(std::initializer_list<std::pair<string_view, param_ref>> params) &; // <2> - - - - // Returns the sql used to construct the prepared statement. - stringe_view sql(); - - // Returns the expanded sql used to construct the prepared statement. Requires sqlite 3.14 - stringe_view expanded_sql(); - - // Returns the expanded sql used to construct the prepared statement. requiers sqlite to be compiles with SQLITE_ENABLE_NORMALIZE. - stringe_view normalized_sql(); - - // Returns the declared type of the column - string_view declared_type(int id) const; -}; ----- -<1> Executes a query with positional arguments -<2> Executes a query with named arguments (from a map-like object) - - - - - -WARNING: The `&&` overloads transfer ownership to the resultset, while the `&` keep them in the statement. -That is, this is UB: -[source,cpp] ----- -resultset get_users(sqlite::connection & conn) -{ - auto s = conn.prepare("SELECT * from users where name = ?"); - return s.execute({"allen"}); // UB, because result set points into s -} - -resultset get_users(sqlite::connection & conn) -{ - // correct, because resultset takes ownershipo - return conn.prepare("SELECT * from users where name = ?").execute({"allen"}); -} ----- - diff --git a/doc/reference/static_resultset.adoc b/doc/reference/static_resultset.adoc deleted file mode 100644 index 0e15e25..0000000 --- a/doc/reference/static_resultset.adoc +++ /dev/null @@ -1,98 +0,0 @@ -== `sqlite/static_resultset.hpp` - -A `static_resultset` represents the results of a query matched to a C++ type - -[source,cpp] ----- -// Representation of a result from a query. - -struct resultset -{ - -template<typename T, bool Strict > -struct static_resultset -{ - // Returns the current row. - T current() const &; - - // Returns the current row. - T current(system::error_code & ec, error_info & ei) const &; - // Checks if the last row has been reached. - bool done() const {return result_.done();} - - // Read the next row. Returns false if there's nothing more to read. - bool read_next(system::error_code & ec, error_info & ei); - bool read_next(); - - - // The number of columes in the resultset - std::size_t column_count() const; - // Returns the name of the column idx. - string_view column_name(std::size_t idx) const; - - // Returns the name of the source table for column idx. - string_view table_name(std::size_t idx) const; - // Returns the origin name of the column for column idx. - string_view column_origin_name(std::size_t idx) const; - - static_resultset() = default; - static_resultset(resultset && result) - - static_resultset(static_resultset<T, false> && rhs); - - /// The input iterator can be used to read every row in a for-loop - struct iterator - { - using value_type = T; - using difference_type = int; - using reference = T&; - using iterator_category = std::forward_iterator_tag; - - iterator(); - explicit iterator(resultset::iterator itr); - bool operator!=(iterator rhs) const; - - value_type &operator*(); - value_type *operator->(); - - iterator& operator++(); - iterator operator++(int); - }; - - /// Return an input iterator to the currently unread row - iterator begin(); - /// Sentinel iterator. - iterator end(); - - // Convert the static_result to a strict version - static_resultset<T, true> strict() && - { - return {std::move(result_)}; - } -}; ----- - - -T:: The static type of the query. This must be a tuple or pfr compatible (for C++20) or described. -Strict:: Disables implicit conversions. - - -.Example -[source,cpp] ----- -extern sqlite::connection conn; -struct user { std::string first_name; std::string last_name; }; -BOOST_DESCRIBE_STRUCT(user, (), (first_name, last_name)); - -sqlite::resultset rs = conn.query("select first_name, last_name from users;"); - -do -{ -user usr = r.current(); -handle_row(u); -} -while (rs.read_next()) // read it line by line - ----- - - diff --git a/doc/reference/string.adoc b/doc/reference/string.adoc deleted file mode 100644 index 21660f9..0000000 --- a/doc/reference/string.adoc +++ /dev/null @@ -1,18 +0,0 @@ -== `sqlite/string.hpp` - -This string header exposes some sqlite utility functions in a C++y way. - - -[source,cpp] ----- -bool like(cstring_ref lhs, cstring_ref rhs, char escape = '\0'); // <1> -bool glob(cstring_ref lhs, cstring_ref rhs); // <2> -int icmp(cstring_ref lhs, cstring_ref rhs); // <3> -int icmp(string_view lhs, string_view rhs, std::size_t n); // <4> ----- -<1> uses https://www.sqlite.org/c3ref/strlike.html[strlike] -<2> uses https://www.sqlite.org/c3ref/strglob.html[strglob] -<3> used https://www.sqlite.org/c3ref/stricmp.html[stricmp] -<4> used https://www.sqlite.org/c3ref/stricmp.html[strnicmp] - - diff --git a/doc/reference/transaction.adoc b/doc/reference/transaction.adoc deleted file mode 100644 index b6bc449..0000000 --- a/doc/reference/transaction.adoc +++ /dev/null @@ -1,104 +0,0 @@ -== `sqlite/transaction.hpp` - -=== `transaction` - -A simple transaction guard implementing RAAI for transactions - -.Definition -[source,cpp] ----- -struct transaction -{ - // The mode of the transaction - enum behaviour {deferred, immediate, exclusive}; - // A tag to use, to adopt an already initiated transaction. - constexpr static struct adopt_transaction_t {} adopt_transaction{}; - - // Create transaction guard on an existing transaction - transaction(connection & conn, adopt_transaction_t); - - - // Create transaction guard and initiate a transaction - transaction(connection & conn); - - // Create transaction guard and initiate a transaction with the defined behaviour - transaction(connection & conn, behaviour b) ; - - // see https://www.sqlite.org/lang_transaction.html re noexcept - // rollback the transaction if not committed. - ~transaction() noexcept(SQLITE_VERSION_NUMBER >= 3007011); - - - // Commit the transaction. - void commit(); - void commit(system::error_code & ec, error_info & ei); - // Rollback the transaction explicitly. - void rollback(); - void rollback(system::error_code & ec, error_info & ei); - -}; ----- - - - -.Example -[source,cpp] ----- -sqlite::connection conn; -conn.connect("./my-database.db"); - -sqlite::transaction t{conn}; -conn.prepare("insert into log (text) values ($1)").execute(std::make_tuple("booting up")); -t.commit(); ----- - -=== `savepoint` - -A simple transaction guard implementing RAAI for savepoints. Savepoints can be used recursively. - -.Definition -[source,cpp] ----- - -struct savepoint -{ - // A tag to use, to adopt an already initiated transaction. - constexpr static transaction::adopt_transaction_t adopt_transaction{}; - - // Create savepoint guard on an existing savepoint - savepoint(connection & conn, std::string name, transaction::adopt_transaction_t); - - // Create transaction guard and initiate it - savepoint(connection & conn, std::string name); - - // rollback to the savepoint if not committed. - ~savepoint() noexcept(SQLITE_VERSION_NUMBER >= 3007011); - - // Commit/Release the transaction. - void commit(); - void commit(system::error_code & ec, error_info & ei); - - void release(); - void release(system::error_code & ec, error_info & ei); - - // Rollback the transaction explicitly. - void rollback(); - void rollback(system::error_code & ec, error_info & ei); - // The name of the savepoint. - - const std::string & name() const; -}; ----- - - -.Example -[source,cpp] ----- -sqlite::connection conn; -conn.connect("./my-database.db"); - -sqlite::savepoint t{conn, "my-savepoint}; -conn.prepare("insert into log (text) values ($1)").execute(std::make_tuple("booting up")); -t.commit(); ----- - diff --git a/doc/reference/value.adoc b/doc/reference/value.adoc deleted file mode 100644 index f5cb3de..0000000 --- a/doc/reference/value.adoc +++ /dev/null @@ -1,85 +0,0 @@ -== `sqlite/value.hpp` - -=== `value_type` - -The https://www.sqlite.org/datatype3.html)[type of a value]. - -[source,cpp] ----- -enum class value_type -{ - // An integral value - integer = SQLITE_INTEGER, - // A floating piont value - floating = SQLITE_FLOAT, - // A textual value - text = SQLITE_TEXT, - // A binary value - blob = SQLITE_BLOB, - // No value - null = SQLITE_NULL, -}; - -// Get the name as a string -const char * value_type_name(value_type vt); ----- - -=== `value` - -A holder for a sqlite values used for internal APIs. - -[source,cpp] ----- - -struct value -{ - // The value for integers in the database - typedef sqlite3_int64 int64 ; - - // The type of the value - value_type type() const; - // The subtype of the value. - int subtype() const; - - // Is the held value null - bool is_null() const; - // Is the held value is not null - explicit operator bool () const; - // Returns the value as an `integer`. - int64 get_int() const; - // Returns the value as an `double`. - double get_double() const; - // Returns the value as text, i.e. a string_view. Note that this value may be invalidated`. - cstring_ref get_text() const; - // Returns the value as blob, i.e. raw memory. Note that this value may be invalidated`. - blob_view get_blob() const; - - // Best numeric datatype of the value - value_type numeric_type() const; - - // True if the column is unchanged in an UPDATE against a virtual table. - // requires sqlite 3.32 - bool nochange() const; - // True if value originated from a bound parameter - // requires sqlite 3.31 - bool from_bind() const; - - - // Construct value from a handle. - explicit value(sqlite3_value * value_) noexcept : value_(value_) {} - - // The handle of the value. - using handle_type = sqlite3_value *; - // Returns the handle. - handle_type handle() const; - handle_type & handle(); - - // Get a value that was passed through the pointer interface. - // A value can be set as a pointer by binding/returning a unique_ptr. - // Rquires sqlite 3.20 - template<typename T> - T * get_pointer(); - -}; ----- - diff --git a/doc/reference/vtable.adoc b/doc/reference/vtable.adoc deleted file mode 100644 index 5063ffc..0000000 --- a/doc/reference/vtable.adoc +++ /dev/null @@ -1,275 +0,0 @@ -== `sqlite/vtable.hpp` - -Please read the <<vtables, virtual tables section>> for a more detailed explanation. - -[source,cpp] ----- -namespace vtab -{ - - -// Helper type to set a function through the xFindFunction callback -struct function_setter -{ - /** Set the function - * - * The function can either take a single argument, a `span<sqlite::value, N>` - * for scalar functions, - * or a `context<Args...>` as first, and the span as second for aggegrate functions. - * - */ - template<typename Func> - void set(Func & func); - template<typename ... Args, std::size_t Extent> - void set(void(* ptr)(context<Args...>, span<value, Extent>)) noexcept; - template<typename T, typename ... Args, std::size_t Extent> - void set(T(* ptr)(context<Args...>, span<value, Extent>)); - - template<std::size_t Extent> - void set(void(* ptr)(span<value, Extent>)); - template<typename T, std::size_t Extent> - void set(T(* ptr)(span<value, Extent>)); -}; - - -// requires Sqlite 3.38 -// Utility function that can be used in `xFilter` for the `in` operator. <1> - -struct in -{ - struct iterator - { - iterator() = default; - - iterator & operator++(); - iterator operator++(int); - - const value & operator*() const; - - const value * operator->() const; - - bool operator==(const iterator& other) const; - bool operator!=(const iterator& other) const; - }; - - // Returns a forward iterator to the `in` sequence for an `in` constraint pointing to the begin. - iterator begin(); - // Returns a forward iterator to the `in` sequence for an `in` constraint pointing to the end. - iterator end(); -explicit in(sqlite::value out); -}; - - - -// index info used by the find_index function <2> -struct index_info -{ - // Returns constraints of the index. - span<const sqlite3_index_info::sqlite3_index_constraint> constraints() const; - - // Returns ordering of the index. - span<const sqlite3_index_info::sqlite3_index_orderby> order_by() const; - - span<sqlite3_index_info::sqlite3_index_constraint_usage> usage(); - - - sqlite3_index_info::sqlite3_index_constraint_usage & usage_of( - const sqlite3_index_info::sqlite3_index_constraint & info); - - // Receive the collation for the contrainst of the position. requires 3.22 - const char * collation(std::size_t idx) const; - - int on_conflict() const; - - // Returns true if the constraint is distinct. requires sqlite 3.38 - bool distinct() const; - - // Requires sqlite 3.38 - value * rhs_value(std::size_t idx) const; - - void set_already_ordered(); - void set_estimated_cost(double cost); - // requires sqlite 3.8.2 - void set_estimated_rows(sqlite3_int64 rows); - // requires sqlite 3.9 - void set_index_scan_flags(int flags); - // requires sqlite 3.10 - std::bitset<64u> columns_used(); - - void set_index(int value); - void set_index_string(char * str, bool take_ownership = true); - - sqlite3_index_info * info() const; - sqlite3 * db() const; -}; - - -struct module_config -{ - // Can be used to set SQLITE_VTAB_INNOCUOUS. Requires sqlite 3.31 - void set_innocuous(); - // Can be used to set SQLITE_VTAB_DIRECTONLY. Requires sqlite 3.31 - void set_directonly() {sqlite3_vtab_config(db_, SQLITE_VTAB_DIRECTONLY);} - - - // Can be used to set SQLITE_VTAB_CONSTRAINT_SUPPORT - void set_constraint_support(bool enabled = false); -}; - -template<typename Table> -struct module -{ - using table_type = Table; - - // Creates the instance - // The instance_type gets used & managed by value, OR a pointer to a class that inherits sqlite3_vtab. - // instance_type must have a member `declaration` that returns a `const char *` for the declaration. - virtual result<table_type> create(sqlite::connection db, int argc, const char * const argv[]) = 0; - - // Create a table - // The table_type gets used & managed by value, OR a pointer to a class that inherits sqlite3_vtab. - // table_type must have a member `declaration` that returns a `const char *` for the declaration. - virtual result<table_type> connect(sqlite::connection db, int argc, const char * const argv[]) = 0; -}; - -template<typename Table> -struct eponymous_module -{ - using table_type = Table; - - // Creates the instance - // The instance_type gets used & managed by value, OR a pointer to a class that inherits sqlite3_vtab. - // instance_type must have a member `declaration` that returns a `const char *` for the declaration. - virtual result<table_type> connect(sqlite::connection db, int argc, const char * const argv[]) = 0; - - eponymous_module(bool eponymous_only = false); - - bool eponymous_only() const;' - protected: - bool eponymous_only_{false}; - -}; - - -// The basis for vtable -template<typename Cursor> -struct table : protected sqlite3_vtab -{ - using cursor_type = Cursor; - - virtual result<void> config(module_config &); - - // The Table declaration to be used with sqlite3_declare_vtab - virtual const char *declaration() = 0; - - // Destroy the storage = this function needs to be present for non eponymous tables - virtual result<void> destroy(); - - // Tell sqlite how to communicate with the table. - // Optional, this library will fill in a default function that leaves comparisons to sqlite. - virtual result<void> best_index(index_info & /*info*/); - - // Start a search on the table. - // The cursor_type gets used & managed by value, OR a pointer to a class that inherits sqlite3_vtab_cursor. - virtual result<cursor_type> open() = 0; - - // Get the connection of the vtable - sqlite::connection connection() const; - - table(const sqlite::connection & conn); -}; - - -// Cursor needs the following member. -template<typename ColumnType = void> -struct cursor : protected sqlite3_vtab_cursor -{ - using column_type = ColumnType; - - // Apply a filter to the cursor. Required when best_index is implemented. - virtual result<void> filter( - int /*index*/, const char * /*index_data*/, - boost::span<sqlite::value> /*values*/) - { - return {system::in_place_error, SQLITE_OK}; - } - - // Returns the next row. - virtual result<void> next() = 0; - - // Check if the cursor is and the end - virtual bool eof() = 0; - - // Returns the result of a value. It will use the set_result functionality to create a an sqlite function. <3> - virtual result<column_type> column(int idx, bool no_change) = 0; - // Returns the id of the current row - virtual result<sqlite3_int64> row_id() = 0; - - // Get the table the cursor is pointing to. - vtab::table<cursor> & table(); - const vtab::table<cursor> & table() const; -}; - - -// Group of functions for modifications. The table must inherit this to be modifiable. -struct modifiable -{ - virtual result<void> delete_(sqlite::value key) = 0; - // Insert a new row - virtual result<sqlite_int64> insert(sqlite::value key, span<sqlite::value> values, int on_conflict) = 0; - // Update the row - virtual result<sqlite_int64> update(sqlite::value old_key, sqlite::value new_key, span<sqlite::value> values, int on_conflict) = 0; -}; - -// Group of functions to support transactions. The table must inherit this to support transactions. -struct transaction -{ - // Begin a tranasction - virtual result<void> begin() = 0; - // synchronize the state - virtual result<void> sync() = 0; - // commit the transaction - virtual result<void> commit() = 0; - // rollback the transaction - virtual result<void> rollback() = 0; -}; - -// Base class to enable function overriding See `xFindFunction`. -struct overload_functions -{ - virtual result<void> find_function( - function_setter fs, - int arg, const char * name) = 0; // <4> -}; - -// Support for recursive transactions. Requires sqlite 3.7.7 -struct recursive_transaction -{ - // Save the current state with to `i` - virtual result<void> savepoint(int i) = 0; - // Release all saves states down to `i` - virtual result<void> release(int i) = 0; - // Roll the transaction back to `i`. - virtual result<void> rollback_to(int i) = 0; -}; - -/** Register a vtable <5> - Returns a reference to the module as stored in the database. It's lifetime is managed by the database. -*/ -template<typename T> -auto create_module(connection & conn, - cstring_ref name, - T && module, - system::error_code & ec, - error_info & ei) -> typename std::decay<T>::type &; -template<typename T> -auto create_module(connection & conn, - const char * name, - T && module) -> typename std::decay<T>::type &; ----- -<1> See https://www.sqlite.org/capi3ref.html#sqlite3_vtab_in_first[vtab_in_first] -<2> See https://www.sqlite.org/vtab.html#xbestindex[best_index] -<3> See https://www.sqlite.org/c3ref/vtab_nochange.html[vtab_no_change] -<4> See https://www.sqlite.org/vtab.html#xfindfunction[find_function] -<5> See https://www.sqlite.org/vtab.html[vtab] - diff --git a/doc/tutorial.adoc b/doc/tutorial.adoc deleted file mode 100644 index 4ff91ff..0000000 --- a/doc/tutorial.adoc +++ /dev/null @@ -1,139 +0,0 @@ -= Accessing a database - -== Connecting to a database - -The `sqlite::connection` holds a https://www.sqlite.org/c3ref/sqlite3.html[connection handle], -which is automatically closes on destruction. - -[source,cpp] -.examples/tutorial.cpp ----- -include::../example/tutorial.cpp[tag=conn_path] ----- - -Sqlite supports https://www.sqlite.org/inmemorydb.html[in memory databases], -which are created with the special path `":memory:"`. This is provided as a constant, -called `in_memory`. - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=conn_mem] ----- - -== Executing SQL - -Once the `conn` is created, the common first step is to create a database schema. -This can be done with the `execute` command, which allows the execution of multiple statements with one function invocation. - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=execute] ----- - -Like most functions in sqlite, the `execute` function comes overloaded to allow two modes of error handling: -- errors as exception -- errors assigned to a `boost::system::error_code` and <<error_info>> - -The second version takes both types by reference after the main arguments, i.e.: - -.examples/tutorial_ec.cpp -[source,cpp] ----- -include::../example/tutorial_ec.cpp[tag=execute] ----- - -The `boost::system::error_code` holds the https://www.sqlite.org/rescode.html[actual integer representing the error], -while `boost::sqlite::error_info` is a string-like type holding the https://www.sqlite.org/c3ref/errcode.html[error message]. - -For brevity, the tutorial section will use the exception overloads. See the <<reference>> for details on the overloads. - -== Querying data - -Once the database provides data it can be queried like this: - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=query1] ----- - -The <<resultset>> is a forward range of the data queried from the database. -The first row of the result is already read. - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=query2] ----- - -NOTE: The `resultset` has `begin()`/`end()` member functions, so that it can be used in a ranged for loop. - -The <<row>> type is a range of <<field>>s, -which has all the information for the field requested. - -In many use-cases this is however superfluous because the structure of the table is known. - -To make this easy, you can call query with a type parameter (`query<T>`) which will yield a -`static_resultset<T>`. `T` can either be a tuple of a struct. - -A tuple will assign the query results by order. - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=query3] ----- - -Using a struct will assign the query results by name, i.e. it will reorder results accordingly. -If you're using a standard lower than C++20, the `struct` needs to be https://www.boost.org/doc/libs/develop/libs/describe/doc/html/describe.html#ref_boost_describe_struct::[described]. - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=query_t] -include::../example/tutorial.cpp[tag=query4] ----- - -The types allowed in the `static_resultset` are: - -- `std::int64_t` -- `double` -- <<blob, 'blob'>>, <<blob_view, `blob_view`>> -- <<string>>, <<string_view>> -- `std::optional<T>`/`boost::optional<T>` with any of the types above. - -WARNING: `blob_view` and `string_view` have a limited lifetime. They might be invalidated when the next row is read! - -By default, the `static_result` does not check types, following https://www.sqlite.org/datatype3.html[sqlite's general dynamic type system]. -You can eat type checks, by using strict mode: - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=query_strict] ----- - -== Statements - -To avoid https://xkcd.com/327/[sql injection], querys and execution should not be build dynamically, but be done with parameters. - -This is done by creating a statement and then executing it with parameters. - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=statement_insert] ----- - -The syntax in the sqlite provides multiple versions. -`?` is a positional parameter, that can have an explicit index at the end (e.g. `?3`) as in the above example. -`:`, `@`, `$` are named parameters, e.g. `$age`. Named parameters can make queries more readable and provide more checks. - -NOTE: See the https://www.sqlite.org/c3ref/bind_blob.html[sqlite syntax] for more details. - -A prepared statement can be used multiple times. - -[source,cpp] ----- -include::../example/tutorial.cpp[tag=statement_multi_insert] ----- - -WARNING: Calling `.execute` on an lvalue of `statement` will transfer ownership to the `resultset`, -while calling `.execute` on an rvalue will produce a `resultset` that points to the statement. - -NOTE: The result of an `.execute` can also be turned into a static_resultset<T> by using `.execute<T>`. - diff --git a/doc/vtable.adoc b/doc/vtable.adoc deleted file mode 100644 index d759de1..0000000 --- a/doc/vtable.adoc +++ /dev/null @@ -1,167 +0,0 @@ -= Virtual tables -[#vtables] - -https://www.sqlite.org/vtab.html[A Virtual Table] is an object that is registered with a <<connection>>. -It looks like a regular table, but is actually invoking virtual methods internally. -This allows users to expose functionality from C++ to sqlite through a table interface. - -NOTE: The implementation uses abstract base classes to make interfaces easy to implement. -You can disable the use of virtual by defining `BOOST_SQLITE_VIRTUAL` which will yield linker errors instead. - -== Eponymous - -And eponymous table is a virtual table the exists without needing to be created from sqlite. - -Such a table can either expose global values or can be used to build https://www.sqlite.org/vtab.html#tabfunc2[table-valued functions]. - -=== Eponymous value table - -The easiest example of a data structure to expose to sql, is a simple ordered map: - -[source,cpp] ----- -container::flat_map<std::string, std::string> data; ----- - -To create a virtual table it needs to have a cursor first. The cursor is what runs over the table, akin to an iterator. - -[source,cpp] ----- -include::../example/ordered_map.cpp[tag=cursor] ----- -<1> Declare the value the cursor produces -<2> The data the cursor operates on -<3> Advance the cursor by one -<4> The module is declared without ROW id, see below -<5> Get the actual column value -<6> Tell sqlite when the cursor reached its end - -The cursor above just runs over the ordered map, returning values. -However, the map is always ordered, so the cursor can optimize the built-in filter for sqlite. -That is, sqlite will filter values on its own, but it's more efficient to do that before returning them. - -This can be done in the `filter` function, which can be written as follows: - -[source,cpp] ----- -include::../example/ordered_map.cpp[tag=filter] ----- -<1> If the first idx is not null, it means the order is reversed (see best_index below) -<2> The equal constraint can be fulfilled by setting the range to enclose the value. -<3> A greater than/equal constraint can be fulfilled by moving the beginning of the range. -<4> A lesser than/equal constraint can be fulfilled by moving the end of the range. - -NOTE: Constraints of the same can appear multiple times, so the filter must only narrow the range. - -After the cursor, the actual table needs to be implemented: - -[source,cpp] ----- -include::../example/ordered_map.cpp[tag=table] ----- -<1> Declare the table to not be read-only, which adds functions 4-6. -<2> The declaration is a literal that tells sqlite the shape of the table. It includes `WITHOUT ROWID` as `cursor.row_id()` mustn't be used. -<3> This function gets called when the table gets scanned, i.e. a cursor gets created. -<4> Delete value from the table, inherited from `modifiable`. -<5> Insert a value into the table, inherited from `modifiable`. -<6> Update a value in the table, inherited from `modifiable`. - -Next, there also should be a `best_index` function. This function informs sqlite about the available -filter features so that sqlite can omit the operations. - -[source,cpp] ----- -include::../example/ordered_map.cpp[tag=best_index] ----- -<1> The data being passed on as idxStr to `cursor.filter`. -<2> These are the constraints handled by filter, so only those get encoded. -<3> filter assumes idx != 0 means descending, i.e. inverted -<4> Tell sqlite the data is ordered already. -<5> Set the index information to be passed to filter. - -With that all defined, the only thing left is to declare the module & create it. - -[source,cpp] ----- -include::../example/ordered_map.cpp[tag=module] ----- - -=== Function table - -An eponymous function can be used as a function. For this example, a `query` vtable will be used to -parse the query part of a url and return it as a table: - -[source,sqlite] ----- -include::../example/url.sql[tag=query] ----- - -[cols="1,1,1"] -|=== -|0|name|boost -|1|thingy|foo -|2|name|sqlite -|3|foo| -|=== - -To achieve this a cursor is needed: - -[source,cpp] ----- -include::../example/url.cpp[tag=query_cursor] ----- -<1> Return the parts of the query view as columns -<2> Pick the input value here. - -This is the module & table declaration; - -[source,cpp] ----- -include::../example/url.cpp[tag=query_boiler_plate] ----- -<1> The hidden colum to use for the input value. -<2> Assert only equal is used for input data. - -NOTE: See the https://www.sqlite.org/vtab.html#tabfunc2[sqlite documentation here]. - -== Non-eponymous Tables - -A non-eponymous table is a table backed by an actual resource. - -The module needs to provide a `create` function in the module, -in addition to the `connect` one. -The table is required to have a `destroy` function that removes the resource. - - -[source,cpp] ----- -struct csv_module final : sqlite::vtab::module<csv_table> -{ - // create the csv file - sqlite::result<table_type> create(sqlite::connection /*db*/, - int argc, const char * const argv[]); - - // connect to an existing csv file. - sqlite::result<table_type> connect(sqlite::connection /*db*/, - int argc, const char * const argv[]); - -}; ----- - -The virtual table can be created with the special syntax: - -[source,cpp] ----- -CREATE VIRTUAL TABLE csv_example USING csv_file(./csv-example.csv, username, first_name, last_name); ----- - -When the above query is executed `csv_module.create()` will be executed with `"./csv-example.csv", "username", "first_name", "last_name". - -If the database gets opened with a previously created virtual table, -`csv_module.connect()` will be called with the same parameters. - -Executing `DROP TABLE csv_example` will call `destroy()` on the `csv_table`. - -NOTE: The `destroy` function will be invoked when the virtual table gets dropped, -not when the connection gets closed. - |